diff --git a/index.html b/index.html index e4a1940..fd5616c 100644 --- a/index.html +++ b/index.html @@ -161,6 +161,7 @@ + diff --git a/infotro/Eln/labs/06-filters/README.md b/infotro/Eln/labs/06-filters/README.md index 62c6491..dbbbb8f 100644 --- a/infotro/Eln/labs/06-filters/README.md +++ b/infotro/Eln/labs/06-filters/README.md @@ -17,6 +17,7 @@ In according to the sample theory, we have to choose at least 2 times the maximu In this case, the maximum frequency is 1 kHz, so we have to choose a sample frequency at least at 2 kHz. We take 10 time $f_c$ for the sample frequency, so we choose 20 kHz. + ## Transfer function For calculate the transfer function, we have to calculate the poles and zeros of the filter. @@ -29,64 +30,104 @@ Be careful, $k_a$ is not the DC gain. For a low pass filter without zeros, the "digital" gain is : $$k_{d} = k_{a}\cdot \prod_{i} \frac{1-e^{P_{ai}\cdot T}}{P_{ai}}$$ ----------- +We can apply the bilinear transformation to the poles and zeros of the analog filter to obtain the poles and zeros of the digital filter. +$$ +p_{di} = \frac{1+p_{ai}\cdot \frac{T}{2}}{1-p_{ai}\cdot \frac{T}{2}} +\qquad \qquad +z_{di} = \frac{1+z_{ai}\cdot \frac{T}{2}}{1-z_{ai}\cdot \frac{T}{2}} +$$ +And for the low pass filter, the "bilinear" gain is : +$$k_{d} = k_{a}\cdot \frac{1}{\prod_{i}\left( \frac{2}{T}-p_{ai} \right)}$$ -fc = 1000; -wc = 2*pi*fc; -fs = 10*fc; -ts = 1/fs; - -num = [0 0 1]; -den = [1/(wc*wc) 1.414/wc 1]; -sysa = tf(num, den) -[za,pa,ka] = tf2zp(num, den); -%fvtool(num,den,'polezero') - - -kd = ka .* ((1-exp(pa(1).*ts))./pa(1)) .* ((1-exp(pa(2).*ts))./pa(2)); -kd = real(kd); -pd = (1+pa.*(ts./2)) ./ (1-pa.*(ts./2)); -zd = (1+za.*(ts/2)) ./ (1-za.*(ts/2)); -sysd = zpk(zd, pd, kd, ts) -[zdb, pdb, kdb] = bilinear(za, pa, ka, fs); -sysdb = zpk(zdb, pdb, kdb, ts) - -bode(sysa, sysd, sysdb); +On the following diagram, we can see the bode diagram of the analog, digital filter and the filter with the bilinear transformation. ![bode_design_filter.svg](bode_design_filter.svg) ------------ -clear; -close all; -clc; +# IIR filter design -H0 = 0; % dB -H1 = -3; % dB -H2 = -40; % dB -fn.p = 7000; % Hz -fn.s = 9000 % Hz -fs = 48000; % Hz +We must design an IIR filter with the following specifications : -fa.p = (fs/pi) * tan((pi*fn.p)/fs); -fa.s = (fs/pi) * tan((pi*fn.s)/fs) +- $H_0 = 0 [dB]$ +- $H_1 = -3 [dB]$ +- $H_2 = -40 [dB]$ +- $f_{pass} = 7 [kHz]$ +- $f_{stop} = 9 [kHz]$ +- $f_s = 48 [kHz]$ -wp = 2*pi*fa.p; -ws = 2*pi*fa.s; -ts = 1/fs; - -[n, wp] = ellipord(wp, ws, 3, 40, 's') -[z, p, k] = ellip(n, 3, 40, wp, 's'); -sys = zpk(z, p, k); -[zd, pd, kd] = bilinear(z, p, k, fs); -sysd = zpk(zd, pd, kd, ts) -bode(sys, sysd) -title('Bode Diagram', 'Color', '#808080'); -xlabel('Frequency (rad/s)', 'Color', '#808080'); -ylabel('Magnitude (dB)', 'Color', '#808080'); -ylabel('Phase (deg)', 'Color', '#808080'); -legend('digital','bilinear', 'Color', 'white') -sos = zp2sos(z,p,k); +We first calculate the analog filter for search the order with the function *ellipord*. +Then, we calculate the poles and zeros with the function *ellip*. +We apply the bilinear transformation to the poles and zeros to obtain the poles and zeros of the digital filter. +Finally, we can plot the bode diagram of the digital filter and the filter with the bilinear transformation. ![iir_filter.svg](iir_filter.svg) +# DSP implementation + +We will implement the previously designed digital filter using a C program that will run in real-time on a fixed-point DSP. +We will employ a cascade structure, consisting of 2 second-order stages. +We will use the TMS320C6211 DSK from Texas Instruments. + +The following equation represent an universal transfer function of a second-order filter : +$$H(z) = \frac{b_{0}+b_{1}\cdot z^{-1}+b_{2}\cdot z^{-2}}{a_{0}+a_{1}\cdot z^{-1}+a_{2}\cdot z^{-2}}$$ + +The following figure depicts the block diagram of this implementation in the case where a0 = 1 +This structure is commonly referred to as "Direct Form I." It requires the storage of past values of both the input and output. + +![direct_form_1.png](direct_form_1.svg) + +So we have the difference equation : +$$y(n) = b_{0}\cdot x(n)+b_{1}\cdot x(n-1)+b_{2}\cdot x(n-2)-a_{1}\cdot y(n-1)-a_{2}\cdot y(n-2)$$ + +It exists a second structure called "Direct Form II" which is more efficient in terms of computation and memory usage. + +![direct_form_2.png](direct_form_2.svg) + +The difference equation is : +$$\begin{align} +y(n) &= tmp\cdot b_{0}+w[0]\cdot b_{1}+w[1]\cdot b_{2} \\ +\\ +tmp &= x(n)-a_{1}\cdot w[0]-a_{2}\cdot w[1] \\ +\\ +w[0] &= tmp_{prev} \\ +\\ +w[1] &= w[0]_{prev} +\end{align}$$ + +The variables can be translated into code by shifting the coefficients 14 positions to the left to enhance precision +after the decimal point, as the DSP only works with integers. + +Structures for the coefficients and the state variables are defined as follows : +```c +typedef struct { + short b0; + short b1; + short b2; + short a0; + short a1; + short a2; +} coeff_sec_order; + +short w3[2]; +short w4[2]; + +coeff_sec_order stage1 = { 469, 349, 469, 16384, -23699, 10692}; +coeff_sec_order stage2 = {16384, -11187, 16384, 16384, -19657, 14890}; +``` + +The following code is the implementation of the Direct Form II function : +```c +void iir_sec_order_dir_s(coeff_sec_order Coeff, short*w, short* Input, short* Output) { + register short tmp; + + tmp = (long)* Input - (( (Long)Coeff.a1 * (long)w[0]) >> SHIFT) - (( (long)Coeff.a2 * (long)w[1]) >> SHIFT); + *Output = (( (long)Coeff.b0 * (long)tmp >> SHIFT) + (( (long)Coeff.b1 * (long)w[0]) >> SHIFT) + (( (long)Coeff.b2 * (long)w[1]) >> SHIFT); + + w[1] = w[0]; + w[0] = tmp; +} +``` + +For a better effect of the filter, the function can be called several times. + + diff --git a/infotro/Eln/labs/06-filters/bode_design_filter.svg b/infotro/Eln/labs/06-filters/bode_design_filter.svg index ace78c8..cc95726 100644 --- a/infotro/Eln/labs/06-filters/bode_design_filter.svg +++ b/infotro/Eln/labs/06-filters/bode_design_filter.svg @@ -21,9 +21,9 @@ inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" showgrid="false" - inkscape:zoom="0.66684046" - inkscape:cx="717.56294" - inkscape:cy="398.14621" + inkscape:zoom="0.94305482" + inkscape:cx="1042.3572" + inkscape:cy="236.99577" inkscape:window-width="1918" inkscape:window-height="1008" inkscape:window-x="953" @@ -2037,86 +2037,90 @@ id="path643" /> - - - - analog - - - - - - digital - - - - - - bilinear - - - - + id="g644" + transform="translate(-23.865014,-350.98702)"> + + + + + analog + + + + + + digital + + + + + + bilinear + + + + + + + +
\ No newline at end of file diff --git a/infotro/Eln/labs/06-filters/direct_form_2.svg b/infotro/Eln/labs/06-filters/direct_form_2.svg new file mode 100644 index 0000000..3229880 --- /dev/null +++ b/infotro/Eln/labs/06-filters/direct_form_2.svg @@ -0,0 +1,4 @@ + + + +
w[0]
w[1]
tmp
\ No newline at end of file diff --git a/infotro/Eln/labs/06-filters/iir_filter.svg b/infotro/Eln/labs/06-filters/iir_filter.svg index d2f72b1..0826d1f 100644 --- a/infotro/Eln/labs/06-filters/iir_filter.svg +++ b/infotro/Eln/labs/06-filters/iir_filter.svg @@ -21,9 +21,9 @@ inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" showgrid="false" - inkscape:zoom="0.66684046" - inkscape:cx="477.62549" - inkscape:cy="398.14621" + inkscape:zoom="1.3336809" + inkscape:cx="1340.6505" + inkscape:cy="283.80102" inkscape:window-width="1918" inkscape:window-height="1008" inkscape:window-x="953" @@ -1764,63 +1764,67 @@ id="path2559" />
- - - - digital - - - - - - bilinear - - - - + id="g1415" + transform="translate(-5.2643303,-359.90618)"> + + + + + digital + + + + + + bilinear + + + + +