Weave.jl/previews/PR341/examples/FIR_design.html

128 lines
59 KiB
HTML
Raw Normal View History

2020-05-23 20:02:12 +02:00
<h1>Introduction</h1>
2020-05-23 15:57:18 +02:00
<p>This an example of a julia script that can be published using <a href="http://mpastell.github.io/Weave.jl/latest/usage/">Weave</a>. The script can be executed normally using Julia or published to HTML or pdf with Weave. Text is written in markdown in lines starting with &quot;<code>#&#39;</code> &quot; and code is executed and results are included in the published document.</p>
<p>Notice that you don&#39;t need to define chunk options, but you can using <code>#&#43;</code>. just before code e.g. <code>#&#43; term&#61;True, caption&#61;&#39;Fancy plots.&#39;</code>. If you&#39;re viewing the published version have a look at the <a href="FIR_design_plots.jl">source</a> to see the markup.</p>
<!-- this setup dependencies, but doesn't appear in the generated document -->
<h1>FIR Filter Design</h1>
<p>We&#39;ll implement lowpass, highpass and &#39; bandpass FIR filters. If you want to read more about DSP I highly recommend <a href="http://www.dspguide.com/">The Scientist and Engineer&#39;s Guide to Digital Signal Processing</a> which is freely available online.</p>
<h2>Calculating frequency response</h2>
<p>DSP.jl package doesn&#39;t &#40;yet&#41; have a method to calculate the the frequency response of a FIR filter so we define it:</p>
<pre class='hljl'>
<span class='hljl-k'>using</span><span class='hljl-t'> </span><span class='hljl-n'>Plots</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>DSP</span><span class='hljl-t'>
</span><span class='hljl-nf'>gr</span><span class='hljl-p'>()</span><span class='hljl-t'>
</span><span class='hljl-k'>function</span><span class='hljl-t'> </span><span class='hljl-nf'>FIRfreqz</span><span class='hljl-p'>(</span><span class='hljl-n'>b</span><span class='hljl-oB'>::</span><span class='hljl-n'>Array</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>w</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>range</span><span class='hljl-p'>(</span><span class='hljl-ni'>0</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>stop</span><span class='hljl-oB'>=</span><span class='hljl-n'>π</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>length</span><span class='hljl-oB'>=</span><span class='hljl-ni'>1024</span><span class='hljl-p'>))</span><span class='hljl-t'>
</span><span class='hljl-n'>n</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>length</span><span class='hljl-p'>(</span><span class='hljl-n'>w</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-n'>h</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>Array</span><span class='hljl-p'>{</span><span class='hljl-n'>ComplexF32</span><span class='hljl-p'>}(</span><span class='hljl-n'>undef</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>n</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-n'>sw</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-ni'>0</span><span class='hljl-t'>
</span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>i</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-n'>n</span><span class='hljl-t'>
</span><span class='hljl-k'>for</span><span class='hljl-t'> </span><span class='hljl-n'>j</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-ni'>1</span><span class='hljl-oB'>:</span><span class='hljl-nf'>length</span><span class='hljl-p'>(</span><span class='hljl-n'>b</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-n'>sw</span><span class='hljl-t'> </span><span class='hljl-oB'>+=</span><span class='hljl-t'> </span><span class='hljl-n'>b</span><span class='hljl-p'>[</span><span class='hljl-n'>j</span><span class='hljl-p'>]</span><span class='hljl-oB'>*</span><span class='hljl-nf'>exp</span><span class='hljl-p'>(</span><span class='hljl-oB'>-</span><span class='hljl-n'>im</span><span class='hljl-oB'>*</span><span class='hljl-n'>w</span><span class='hljl-p'>[</span><span class='hljl-n'>i</span><span class='hljl-p'>])</span><span class='hljl-oB'>^-</span><span class='hljl-n'>j</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-n'>h</span><span class='hljl-p'>[</span><span class='hljl-n'>i</span><span class='hljl-p'>]</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-n'>sw</span><span class='hljl-t'>
</span><span class='hljl-n'>sw</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-ni'>0</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span><span class='hljl-t'>
</span><span class='hljl-k'>return</span><span class='hljl-t'> </span><span class='hljl-n'>h</span><span class='hljl-t'>
</span><span class='hljl-k'>end</span>
</pre>
<pre class="output">
FIRfreqz &#40;generic function with 2 methods&#41;
</pre>
<h2>Design Lowpass FIR filter</h2>
<p>Designing a lowpass FIR filter is very simple to do with DSP.jl, all you need to do is to define the window length, cut off frequency and the window. We will define a lowpass filter with cut off frequency at 5Hz for a signal sampled at 20 Hz. We will use the Hamming window, which is defined as: <span class="math">$w(n) = \alpha - \beta\cos\frac{2\pi n}{N-1}$</span>, where <span class="math">$\alpha=0.54$</span> and <span class="math">$\beta=0.46$</span></p>
<pre class='hljl'>
<span class='hljl-n'>fs</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-ni'>20</span><span class='hljl-t'>
</span><span class='hljl-n'>f</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>digitalfilter</span><span class='hljl-p'>(</span><span class='hljl-nf'>Lowpass</span><span class='hljl-p'>(</span><span class='hljl-ni'>5</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>fs</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-n'>fs</span><span class='hljl-p'>),</span><span class='hljl-t'> </span><span class='hljl-nf'>FIRWindow</span><span class='hljl-p'>(</span><span class='hljl-nf'>hamming</span><span class='hljl-p'>(</span><span class='hljl-ni'>61</span><span class='hljl-p'>)))</span><span class='hljl-t'>
</span><span class='hljl-n'>w</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>range</span><span class='hljl-p'>(</span><span class='hljl-ni'>0</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>stop</span><span class='hljl-oB'>=</span><span class='hljl-n'>pi</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>length</span><span class='hljl-oB'>=</span><span class='hljl-ni'>1024</span><span class='hljl-p'>)</span><span class='hljl-t'>
</span><span class='hljl-n'>h</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>FIRfreqz</span><span class='hljl-p'>(</span><span class='hljl-n'>f</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>w</span><span class='hljl-p'>)</span>
</pre>
<pre class="output">
1024-element Array&#123;Complex&#123;Float32&#125;,1&#125;:
1.0f0 &#43; 0.0f0im
0.99546844f0 &#43; 0.095055714f0im
0.98191506f0 &#43; 0.1892486f0im
0.95946306f0 &#43; 0.28172377f0im
0.9283168f0 &#43; 0.37164196f0im
0.8887594f0 &#43; 0.45818728f0im
0.84115064f0 &#43; 0.54057467f0im
0.7859234f0 &#43; 0.618057f0im
0.72357976f0 &#43; 0.6899319f0im
0.65468615f0 &#43; 0.7555481f0im
0.00043952762f0 - 0.00041908873f0im
0.0005152718f0 - 0.00040521423f0im
0.0005873293f0 - 0.00037745363f0im
0.0006531789f0 - 0.0003367371f0im
0.0007105166f0 - 0.00028444792f0im
0.0007573364f0 - 0.00022237403f0im
0.0007920005f0 - 0.00015264557f0im
0.0008132961f0 - 7.766036f-5im
0.0008204784f0 - 3.1148685f-18im
</pre>
<h2>Plot the frequency and impulse response</h2>
<p>The next code chunk is executed in term mode, see the <a href="FIR_design.jl">script</a> for syntax.</p>
<pre class='hljl'>
<span class='hljl-nB'>julia&gt; </span><span class='hljl-n'>h_db</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-n'>log10</span><span class='hljl-oB'>.</span><span class='hljl-p'>(</span><span class='hljl-n'>abs</span><span class='hljl-oB'>.</span><span class='hljl-p'>(</span><span class='hljl-n'>h</span><span class='hljl-p'>));</span><span class='hljl-t'>
1024-element Array{Float32,1}:
0.0
-1.5272748f-6
-6.0314724f-6
-1.3538573f-5
-2.394518f-5
-3.7173842f-5
-5.3121257f-5
-7.165827f-5
-9.257809f-5
-0.00011577748
-3.2165928
-3.1834154
-3.1560452
-3.1337893
-3.1161458
-3.102753
-3.0933545
-3.0877802
-3.0859327
</span><span class='hljl-nB'>julia&gt; </span><span class='hljl-n'>ws</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-n'>w</span><span class='hljl-oB'>/</span><span class='hljl-n'>pi</span><span class='hljl-oB'>*</span><span class='hljl-p'>(</span><span class='hljl-n'>fs</span><span class='hljl-oB'>/</span><span class='hljl-ni'>2</span><span class='hljl-p'>)</span><span class='hljl-t'>
0.0:0.009775171065493646:10.0</span>
</pre>
<pre class='hljl'>
<span class='hljl-nf'>plot</span><span class='hljl-p'>(</span><span class='hljl-n'>ws</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>h_db</span><span class='hljl-p'>,</span><span class='hljl-t'>
</span><span class='hljl-n'>xlabel</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;Frequency (Hz)&quot;</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>ylabel</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;Magnitude (db)&quot;</span><span class='hljl-p'>)</span>
</pre>
<img src="data:image/png;base64,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
<p>And again with default options</p>
<pre class='hljl'>
<span class='hljl-n'>h_phase</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-nf'>unwrap</span><span class='hljl-p'>(</span><span class='hljl-oB'>-</span><span class='hljl-n'>atan</span><span class='hljl-oB'>.</span><span class='hljl-p'>(</span><span class='hljl-n'>imag</span><span class='hljl-oB'>.</span><span class='hljl-p'>(</span><span class='hljl-n'>h</span><span class='hljl-p'>),</span><span class='hljl-n'>real</span><span class='hljl-oB'>.</span><span class='hljl-p'>(</span><span class='hljl-n'>h</span><span class='hljl-p'>)))</span><span class='hljl-t'>
</span><span class='hljl-nf'>plot</span><span class='hljl-p'>(</span><span class='hljl-n'>ws</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>h_phase</span><span class='hljl-p'>,</span><span class='hljl-t'>
</span><span class='hljl-n'>xlabel</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;Frequency (Hz)&quot;</span><span class='hljl-p'>,</span><span class='hljl-t'> </span><span class='hljl-n'>ylabel</span><span class='hljl-t'> </span><span class='hljl-oB'>=</span><span class='hljl-t'> </span><span class='hljl-s'>&quot;Phase (radians)&quot;</span><span class='hljl-p'>)</span>
</pre>
<img src="data:image/png;base64,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