1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
17 // Butterworth low pass IIR filter
18 // input: 8bit ADC signal, 1MS/s
19 // output: 8bit value, Fc=20khz
21 // coef: (using http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
22 // Recurrence relation:
23 // y[n] = ( 1 * x[n- 2])
27 // + ( -0.8371816513 * y[n- 2])
28 // + ( 1.8226949252 * y[n- 1])
32 // b = [-0.8371816513, 1.8226949252]
33 // b is approximated to b = [-0xd6/0x100, 0x1d3 / 0x100] (for optimization)
34 // gain = 2.761139367e2
36 // See details about its design see
37 // https://fail0verflow.com/blog/2014/proxmark3-fpga-iir-filter.html
39 module lp20khz_1MSa_iir_filter(
46 // clk is 24MHz, the IIR filter is designed for 1MS/s
47 // hence we need to divide it by 24
48 // using a shift register takes less area than a counter
52 cnt
<= {cnt
[22:0], cnt
[23]};
68 // input range is [0; 255]
69 // We want "128" to be at the center of the 17bit register
70 // (128+z)*gain = 17bit center
71 // z = (1<<16)/gain - 128 = 109
72 // We could use 9bit x registers for that, but that would be
73 // a waste, let's just add the constant during the computation
74 // (x0+109) + 2*(x1+109) + (x2+109) = x0 + 2*x1 + x2 + 436
75 x0
+ {x1
, 1'b0} + adc_d
+ 436
76 // we want "- y0 * 0xd6 / 0x100" using only shift and add
78 // so *0xd6/0x100 is equivalent to
79 // ((x << 1) + (x << 2) + (x << 4) + (x << 6) + (x << 7)) >> 8
80 // which is also equivalent to
81 // (x >> 7) + (x >> 6) + (x >> 4) + (x >> 2) + (x >> 1)
82 - ((y0
>> 7) + (y0
>> 6) + (y0
>> 4) + (y0
>> 2) + (y0
>> 1)) // - y0 * 0xd6 / 0x100
83 // we want "+ y1 * 0x1d3 / 0x100"
84 // 0x1d3 == 0b111010011
85 // so this is equivalent to
86 // ((x << 0) + (x << 1) + (x << 4) + (x << 6) + (x << 7) + (x << 8)) >> 8
87 // which is also equivalent to
88 // (x >> 8) + (x >> 7) + (x >> 4) + (x >> 2) + (x >> 1) + (x >> 0)
89 + ((y1
>> 8) + (y1
>> 7) + (y1
>> 4) + (y1
>> 2) + (y1
>> 1) + y1
);
93 // output: reduce to 8bit
94 assign out
= y1
[16:9];