# HW 03




1.  The lowest and highest bins are filled.  We expect clipping in the data. 

2.  Increase sampling frequency till spectra does not change anymore.

3.  Here, we want the resolution $\Delta V$ to be 0.1% of the range (full scale: $FS = V_{max} - V_{min}$).

\begin{align}
\frac{\Delta V}{FS} & = \frac{1}{V_{max} - V_{min}}  \cdot  \frac{V_{max} - V_{min}}{2^{N}} \\
 & = \frac{1}{2^{N}} \lt 0.001
\end{align}

This implies $N = 10$ bit,  ($2^{10} = 1,024$).

4. The signal is:

\begin{align}
y(t) = 1.1 + 3.9 \sin(20,000 \pi t)
\end{align}
Its amplitude will be between 2.8 and 5 V, and the frequency is $f = 10,000$ Hz.  We need to make sure the DAQ system has a high enough sampling rate to prevent aliasing and large enough input rate to prevent clipping.  Then we will select the DAQ system with the best resolution (or the smallest quantization error).

(a): sampling rate is too low to satisfy Nyquiest criterion

(b): input range is too small, we would like to have a safety margin of 20-40 %.

(c) \& (d): sampling rate and input range are ok.  


```python
Q_c = 20/2**(8+1)

Q_d = 20/2**(16+1)

print('Q (c) = ', Q_c, ' V,  Q (d) = ', Q_d, ' V')
```

    Q (c) =  0.0390625  V,  Q (d) =  0.000152587890625  V


Case (d) is the best design.

5.  
\begin{align}
y(t) = 0.03 + 0.05 \cos (1,000 \pi t)
\end{align}

First, we select the gain:  Voltage range: $A_{PT} = 0.02 - 0.08$ V.  The smallest range of $\pm 0.01$ V is the best and has adequate safety margin to guaranty that there will be not clipping.

Then, we select the sampling rate: The signal is periodic and we will optimize the frequency resolution to make sure we do not have aliazing.  The signal frequency is $f = 500$ Hz, to satisfy Nyquiest criterion, we would a sample rate $f_s > 2\cdot f > 1,000$ Hz.  An appropriate sampling frequency would be in the range $f_s = [1,024 - 4,000]$ Hz.

6.  (a) The ideal input range on the DAQ would be: $\pm 60-80$ mV.  We will use an amplifier with an output voltage: $A_{amp}\pm 80$ mV for the analysis here.

The gain should be: $G = A_{amp} / A_{PT} = 80/8 = 10$

(b) Inverting amplifiers are less susceptible to electromagnetic noise, so we should build an amplifier stage based on inverting amplifiers.  However, inverting amplifiers are susceptible to impedance loading, so it would be safe to use a buffer on the input of the amplifier stage.

7.  (a) The desired bandwidth is $f = 100,000$ Hz.  The amplifier gain bandwidth product is $GBP = 1 MHz$.  Remembering the definition of $GBP$:

\begin{align*}
GBP & = G_{theoretical} \times f_c
\end{align*}
So for us the $f_c = f = 100,000$ kHz.  This forces a theoretical gain per amplifier stage that should not exceed $G_{theoretical} = GBP / f_c = 10^6/10^5 = 10$.  

So for a total desired gain of $G=100$, we should use at least two stages of $G_{stage} = G_{theoretical} = 10$ in series.

(b)  You have two options to build your circuit:

1- Use two non-inverting amplifiers of gain $G=10$ in series.  Non-inverting amplifiers have infinite input impedance and not susceptible to impedance loading.

2- Use two inverting amplifiers of gain $G=-10$ in series.  Now you have have to worry about impedance loading, so you should put a buffer first, then the two inverting amplifiers.


8.  For a Butterworth high-pass filter of order $n$ the gain is:

\begin{align*}
G = \frac{1}{\sqrt{1+\left( \frac{f_{cutoff}}{f} \right)^{2n} }}
\end{align*}

Here, $f$ is the noise: $f = 60$ Hz, the cutoff frequency is $f_{cutoff} = 300$ Hz.


```python
import numpy

f = 60 # Hz
f_c = 300 # Hz

G_1 = 1/numpy.sqrt(1+(f_c/f)**(2*1))
G_2 = 1/numpy.sqrt(1+(f_c/f)**(2*2))
G_4 = 1/numpy.sqrt(1+(f_c/f)**(2*4))

print('the gains in percentage are:')

print("order 1: G = %2.4f " % (G_1*100), '%')
print("order 2: G = %2.4f " % (G_2*100), '%')
print("order 4: G = %2.4f " % (G_4*100), '%')

# convert to dB:
G_1dB = 20*numpy.log10(G_1)
G_2dB = 20*numpy.log10(G_2)
G_4dB = 20*numpy.log10(G_4)

print('the gains in dB are: ')

print("order 1: G = %2.4f " % (G_1dB), 'dB')
print("order 2: G = %2.4f " % (G_2dB), 'dB')
print("order 4: G = %2.4f " % (G_4dB), 'dB')


```

    the gains in percentage are:
    order 1: G = 19.6116  %
    order 2: G = 3.9968  %
    order 4: G = 0.1600  %
    the gains in dB are: 
    order 1: G = -14.1497  dB
    order 2: G = -27.9657  dB
    order 4: G = -55.9176  dB


9.  The signal could be written analytically as:
\begin{align}
y(t) = 1.50 \sin(40 \pi t) + 0.20 \sin(20,000 \pi t)
\end{align}
So the carrier frequency is $f_{carrier} = 20$ Hz, and the noise frequency is $f_{noise} = 10,000$ Hz.  We acquire $N=2^{12}$ points.  The DAQ has $n=16$ bits.
We also have $f_s = 30,000$ Hz.

(a) The frequency resolution is: $\Delta f = f_s/N$.

The quantization error is: $Q = (V_{max}-V_{min})/2^{n+1}$


```python
f_s = 30000 # Hz
N = 2**12 # points
n = 16 # # bits
Q = 20/2**(n+1) # quantization error in V

print("\u0394 f = %4.4f" %(f_s/N), 'Hz')
print("Q = %1.4f" %(Q*1000), 'mV')
```

    Δ f = 7.3242 Hz
    Q = 0.1526 mV


(b)  This takes 3 steps.

_Step 1_ Select the type of filter and cutoff frequency, $f_c$: Here we want to remove high frequency noise, so we will use a low-pass filter.  As a rule of thumb, it should be at least $10>f_{carrier}$ and $10<f_{noise}$.  Here any values between: $f_c = [200-1,000]$ Hz is acceptable.  I would select the lowest to more efficiently filter the noise: $f_c = 200$ Hz.

_Step 2_  Select the gain of the amplifier to make the most of the DAQ system: Ideally, the amplitude of the carrier should be 60-80% of the input range of the DAQ.  So the gain should be in the range: $G = [6-8]/1.5 = 4-5.3$.  Let's select: $G = 5$.

_Step 3_  Filter the signal: We wish for the noise amplitude to be smaller than the quantization error $Q$ of our DAQ system.  Remember that the low pass filter has to be applied to the amplified signal.  So after amplification, the noise has amplitude: $A_{noise} = 5\times 0.20 = 1$ V.



```python
A_noise = 1 #V

f_c = 200 # Hz
f_noise = 10000 # Hz

# try LPF of order 1
n_LPF = 1
G = 1/numpy.sqrt(1+(f_noise/f_c)**(2*n_LPF))
print('order ',n_LPF,' : A_noise', (G*A_noise), 'V, Q/A_noise = ',Q/(G*A_noise))
# too big

# try LPF of order 2
n_LPF = 2
G = 1/numpy.sqrt(1+(f_noise/f_c)**(2*n_LPF))
print('order ',n_LPF,' : A_noise', (G*A_noise), 'V, Q/A_noise = ',Q/(G*A_noise))
# still too big

# try LPF of order 3
n_LPF = 3
G = 1/numpy.sqrt(1+(f_noise/f_c)**(2*n_LPF))
print('order ',n_LPF,' : A_noise', (G*A_noise), 'V, Q/A_noise = ',Q/(G*A_noise))

print('I need a filter of order 3')
```

    order  1  : A_noise 0.01999600119960014 V, Q/A_noise =  0.007630920257598869
    order  2  : A_noise 0.0003999999680000038 V, Q/A_noise =  0.38146975708007697
    order  3  : A_noise 7.999999999744e-06 V, Q/A_noise =  19.073486328735353
    I need a filter of order 3



```python

```

1af67d8b375454cf391710030ddf619f1e3c28fd
ipynb
Jupyter Notebook
HWs/HW03_solutions.ipynb
Dan-Hunt-r/GWU-MAE3120_2022
fe5e9f6b4f6e0bbc741901e3e812d7d6dcc4a0ed
BSD-3-Clause
HWs/HW03_solutions.ipynb
Dan-Hunt-r/GWU-MAE3120_2022
fe5e9f6b4f6e0bbc741901e3e812d7d6dcc4a0ed
BSD-3-Clause
HWs/HW03_solutions.ipynb
Dan-Hunt-r/GWU-MAE3120_2022
fe5e9f6b4f6e0bbc741901e3e812d7d6dcc4a0ed
BSD-3-Clause
Qwen/Qwen-72B
1. YES
2. YES