<jupyter_start><jupyter_text>03. Filters(work in progress)<jupyter_code>%pylab inline
from IPython.display import Audio
style.use('seaborn') #more beautiful plots
N = 30
impulse = zeros(N)
impulse[5] = 1
stem(impulse)
title('Impulse')
show()<jupyter_output><empty_output><jupyter_text>Lets define a FIR simple lowpass:$y(n)=x(n)+x(n-1)$<jupyter_code>def simpleLowpass(x):
    #FIR lowpass
    y = zeros_like(x)
    for n in range(len(x)):
        y[n] = x[n]+x[n-1]
    return y
stem(simpleLowpass(impulse))
show()
f = linspace(0,1,int(N/2))
plot(f, 20*log10(abs(fft.fft(simpleLowpass(impulse)))[0:int(N/2)]), label='simpleLowpass')
plot(f, 20*log10(abs(fft.fft(impulse))[0:int(N/2)]), label='impulse')
xlabel('normalized frequency')
ylabel('amplitude [dB]')
ylim([-10, 10])
legend()
show()<jupyter_output><empty_output><jupyter_text>Lets define an IIR simple lowpass:$y(n)=x(n)+y(n-1)$<jupyter_code>def simpleLowpass2(x): 
    y = zeros_like(x)
    y1 = 0
    for n in range(len(x)):
        y[n] = x[n]+y1
        y1 = y[n]
    return y
stem(simpleLowpass2(impulse))
show()<jupyter_output><empty_output><jupyter_text>Notice how the ```simpleLowpass2()``` function essentially converts an impulse to a DC-signal. A DC-Signal is energy at 0Hz, so very low frequency. Changing our  ```simpleLowpass2()``` a bit lets us change its effect with a parameter $\alpha$:$y(n)=x(n)+y(n-1) \cdot \alpha$<jupyter_code>def simpleLowpass3(x,alpha):
    y = zeros_like(x)
    y1 = 0
    for n in range(len(x)):
        y[n] = x[n]+y1
        y1 = y[n]*alpha
    return y
stem(simpleLowpass3(impulse, 0.9), markerfmt='go', label = '$ alpha =0.9$')
stem(simpleLowpass3(impulse, 0.5), markerfmt='ro', label = '$ alpha =0.75$')
stem(simpleLowpass3(impulse, 0.1), markerfmt='bo', label = '$ alpha =0.5$')
legend()
show()
f = linspace(0,1,int(N/2))
plot(f, 20*log10( abs(fft.fft(simpleLowpass3(impulse, 0.5))+0.001)[0:int(N/2)]), label='simpleLowpass3, alpha = 0.5')
plot(f,  20*log10( abs(fft.fft(impulse))[0:int(N/2)]), label='impulse')
xlabel('normalized frequency')
ylabel('amplitude [dB]')
ylim([-10, 10])
legend()
show()<jupyter_output><empty_output><jupyter_text>Analytic Frequency Response Via a process called the [z transform ](https://en.wikipedia.org/wiki/Z-transform) we can transform *difference Equations* to *Transfer Functions*.For example:$$ y(n) = x(n)+x(n-1)\cdot\alpha $$$$ Y = X + \alpha \cdot X \cdot z^{-1} $$Basically we re-write the formula as a polynomial of $z^{-1}$. Every multiplication with $z^{-1}$ means a delay by one sample. This is a bit of a simlpification, one should write $X(z)$ instead of just $X$ to be exact, but it doesn't matter and makes the formula a bit crowded.There is a couple of nice advantages about the transfer functions:- We can calculate the Frequency magnitude and phase response- We can think out a filters stability easily (via pole/zero analysis)- we can multiply transfer functions to cascade filters or multiply a sigal by a complex transfer function to get the output.For a transfer Function , $H(z)$:$$X(z) \cdot H(z) = Y(z)$$That means:$$ H(z) = \frac{Y(z)}{X(z)}$$So we need to rewrite/solve our formula for $\frac{Y}{X}$ :$$Y = X(1 + \alpha \cdot z^{-z})$$$$ \frac{Y}{X} = 1 + \alpha \cdot z^{-z} $$$$ H(z) = 1 + \alpha \cdot z^{-z} $$We can then evaluate $H$ to get the frequency response using complex sinusoids:<jupyter_code>i = 1j #imaginary number
omega = linspace(0, pi, int(N/2)) # Creating the same amount of evaluation points as with the other filters 
z = cos(omega) + i*sin(omega)
alpha = 1
magResp = 1+alpha*z**-1
plot(omega, magResp)
title('Magnitude Response')
xlabel('$\omega$')
show()<jupyter_output>/root/miniconda2/envs/findRefrain3/lib/python3.6/site-packages/numpy/core/numeric.py:531: ComplexWarning: Casting complex values to real discards the imaginary part
  return array(a, dtype, copy=False, order=order)<jupyter_text>Or we can put in a complex sinusoid and say that the frequency response $H(\omega)$  is:$$ H(\omega) =  1 + \frac{1} {cos\omega) + i sin(\omega)}  $$Using the absolute value of this gves us teh Magnitude response, usingthe argument of teh complex result gives us the phase response. Below we find a comparison between the fft of the impulse response of the filter and our analytic magnitude response. Both are now in dB. thats why the curve looks different than above.<jupyter_code># First, we create a new, longer imulse signal to reduce measurement errors:
N = 300
impulse = zeros(N)
impulse[5] = 1

# Then we compute the impulse response, take its fft and plot it:
f = linspace(0,1,int(N/2))
plot(f, 20*log10( abs(fft.fft(simpleLowpass(impulse))+0.001)[0:int(N/2)]), label='fft of impulse response')
# and plot the analytic one in dB
plot(f, 20*log10( abs(magResp)), label='analytic')
ylim([-30,10])
xlabel('Normalized frequency []')
ylabel('Amplitude [dB]')
legend()
show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1571749336599306, 'fraction_numerical': 0.02776076750357216, 'mean_word_length': 5.257982120051086, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '253636', 'license': 'MIT', 'n_tokens_mistral': 1860, 'n_tokens_neox': 1748, 'n_words': 527, 'path': 'notebooks/03_Filters.ipynb', 'repo_name': 'hrtlacek/dspCourse', 'size': '4899'}