]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - fpga/lp20khz_1MSa_iir_filter.v
Merge remote-tracking branch 'origin/master' into iclass-fixes
[proxmark3-svn] / fpga / lp20khz_1MSa_iir_filter.v
diff --git a/fpga/lp20khz_1MSa_iir_filter.v b/fpga/lp20khz_1MSa_iir_filter.v
new file mode 100644 (file)
index 0000000..a227a90
--- /dev/null
@@ -0,0 +1,81 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Butterworth low pass IIR filter
+// input: 8bit ADC signal, 1MS/s
+// output: 8bit value, Fc=20khz
+//
+// coef: (using http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
+// Recurrence relation:
+// y[n] = (  1 * x[n- 2])
+//      + (  2 * x[n- 1])
+//      + (  1 * x[n- 0])
+
+//      + ( -0.8371816513 * y[n- 2])
+//      + (  1.8226949252 * y[n- 1])
+//
+// therefore:
+// a = [1,2,1]
+// b = [-0.8371816513, 1.8226949252]
+// b is approximated to b = [-0xd6/0x100, 0x1d3 / 0x100] (for optimization)
+// gain = 2.761139367e2
+//
+// See details about its design see
+// https://fail0verflow.com/blog/2014/proxmark3-fpga-iir-filter.html
+module lp20khz_1MSa_iir_filter(input clk, input [7:0] adc_d, output rdy, output [7:0] out);
+
+       // clk is 24Mhz, the IIR filter is designed for 1MS/s
+       // hence we need to divide it by 24
+       // using a shift register takes less area than a counter
+       reg [23:0] cnt = 1;
+       assign rdy = cnt[0];
+       always @(posedge clk)
+               cnt <= {cnt[22:0], cnt[23]};            
+
+       reg [7:0] x0 = 0;
+       reg [7:0] x1 = 0;
+       reg [16:0] y0 = 0;
+       reg [16:0] y1 = 0;
+
+       always @(posedge clk)
+       begin
+               if (rdy)
+               begin
+                       x0 <= x1;
+                       x1 <= adc_d;
+                       y0 <= y1;
+                       y1 <=
+                               // center the signal:
+                               // input range is [0; 255]
+                               // We want "128" to be at the center of the 17bit register
+                               // (128+z)*gain = 17bit center
+                               // z = (1<<16)/gain - 128 = 109
+                               // We could use 9bit x registers for that, but that would be
+                               // a waste, let's just add the constant during the computation
+                               // (x0+109) + 2*(x1+109) + (x2+109) = x0 + 2*x1 + x2 + 436
+                               x0 + {x1, 1'b0} + adc_d + 436
+                               // we want "- y0 * 0xd6 / 0x100" using only shift and add
+                               // 0xd6 == 0b11010110
+                               // so *0xd6/0x100 is equivalent to
+                               // ((x << 1) + (x << 2) + (x << 4) + (x << 6) + (x << 7)) >> 8
+                               // which is also equivalent to
+                               // (x >> 7) + (x >> 6) + (x >> 4) + (x >> 2) + (x >> 1)
+                               - ((y0 >> 7) + (y0 >> 6) + (y0 >> 4) + (y0 >> 2) + (y0 >> 1)) // - y0 * 0xd6 / 0x100
+                               // we want "+ y1 * 0x1d3 / 0x100"
+                               // 0x1d3 == 0b111010011
+                               // so this is equivalent to
+                               // ((x << 0) + (x << 1) + (x << 4) + (x << 6) + (x << 7) + (x << 8)) >> 8
+                               // which is also equivalent to
+                               // (x >> 8) + (x >> 7) + (x >> 4) + (x >> 2) + (x >> 1) + (x >> 0)
+                               + ((y1 >> 8) + (y1 >> 7) + (y1 >> 4) + (y1 >> 2) + (y1 >> 1) + y1);
+               end
+       end
+
+       // output: reduce to 8bit
+       assign out = y1[16:9];
+
+endmodule
Impressum, Datenschutz