Forum Discussion
input to IIR filter in Verilog
Just a quick question regarding implementing an IIR filter in Verilog...
At the moment, I am using the Wolfson ADC on the DE2-70 to convert analogue sound input from Line In to digital bits - that's all working perfectly (with a sample rate of 8000 kHz and 24-bit resolution). I understand that these 24-bit values from the ADC are in two's complement form - i.e. each sample is represented by a number between -2^23 and (2^23)-1. My question is, can this two's complement value be fed directly into a fixed-point IIR filter designed in Matlab's FDAtool? Looking at FDAtool, there are options to set the "Input Word Length" & "Input Fraction Length"... This leads me to believe that I have to convert my 24-bit two's complement value from the ADC to a fixed point value that will be 24 + no. of fraction bits long... Is this reasoning correct? It would be much appreciated if someone could point me in the right direction on this one! Cheers14 Replies
- Altera_Forum
Honored Contributor
You can't expect anything but "VERY noisy output" with 8 bit data length, particularly, when the ADC input level keeps a headroom. I don't understand the purpose of using such a low resolution. 12 bit would be fair, 16 bit standard CD audio quality.
--- Quote Start --- if I set "one_minus_a" to zero, I still have the input passing through the filter to the output --- Quote End --- Doesn't sound reasonable with the shown code. Regarding the said application, a first order low-pass isn't a very selective filter. - Altera_Forum
Honored Contributor
Thanks again Kaz!
Basically I want a filter that, for example, can attenuate 160Hz more so than 80Hz (second and first harmonics of E string respectively). I was planning on expanding on the IIR code above to get an appropriate filter response to acheive this (so those values of "a" are just values to test with at this stage) - however that code is still giving me a VERY noisy output - something is not right. Interestingly enough, if I set "one_minus_a" to zero, I still have the input passing through the filter to the output - how can this be?module test_filter(clk,filter_in,filter_out); parameter W=7; // bit width - 1 parameter signed a=10'b0100000000; //256 parameter signed one_minus_a=11'b01100000000; //768 input clk; input signed filter_in; output signed filter_out; reg signed y; reg signed x; initial begin x=0; y=0; end always@(posedge clk) begin x <= filter_in; y <= (one_minus_a*x) + (a*y); // y=(1-a)*x+(a*y) end assign filter_out=y; endmodule // test_filter - Altera_Forum
Honored Contributor
My only worry is that 1100000000 assumed 768, but you made it negative.
add sign bit, keep your scaling. I checked your filter in Matlab. it cuts off at(say .2 FS) and stop band attenuation is 4.5 dB. Is that what you want? - Altera_Forum
Honored Contributor
How's this now:
Thanks again!module test_filter(clk,filter_in,filter_out); parameter W=7; // bit width - 1 parameter signed a=10'b0100000000; //256 parameter signed one_minus_a=10'b1100000000; //768 input clk; input signed filter_in; output signed filter_out; reg signed y; reg signed x; initial begin x=0; y=0; end always@(posedge clk) begin x <= filter_in; y <= (one_minus_a*x) + (a*y); // y=(1-a)*x+(a*y) end assign filter_out=y; endmodule // test_filter - Altera_Forum
Honored Contributor
--- Quote Start --- Thanks Kaz! Like this:
See anything that looks wrong there? (think there might be as my audio output is now really noisy!) By the way, a=0.25 in this code. Thanks! --- Quote End --- Basically it looks ok. My mistake was the 20 bit width. we scaled (a) by 2^10 but scaled (y) by 2^-8 leading to 12 dB gain. so make y 18 bits and truncate feedback to 8 bits. also note 1-a can be precomputed and scaled to 1-.25 = .75 = .75*1024 check in matlab your filter cutoff: den = [1 -.25]; nu = .75; freqz(num,den)module test_filter(clk,filter_in,filter_out); parameter W=7; // bit width - 1 parameter signed a=10'b0100000000; input clk; input signed filter_in; output signed filter_out; reg signed x,y; initial begin x=0; y=0; end always@(posedge clk) begin x <= filter_in; y <= ({x,10'b0000000000}) - (a*x) + (a*y); // y=(1-a)*x+(a*y) end assign filter_out=y; endmodule // test_filter - Altera_Forum
Honored Contributor
I don't think, that you can't use FIR filters succesfully without some minimal understanding of number representation in HDL or digital logic generally. But this has been the problem so far. A 1st order low-pass, as addressed with the above code, is the most simple filter of the world and doesn't involve issues with coefficient sensitivity or stability.
I won't say: Oops, you don't manage to design a 1st order IIR, it's much easier with FIR... Also the FIR tool requires some basic knowledge of filters, e.g. relation of fs, fc and number of coefficients. Previous Altera forum discussions demonstrate some attempts to ignore these basics. - Altera_Forum
Honored Contributor
--- Quote Start --- ...All I want to do is implement a simple low-pass filter to attenuate all harmonics (except the 1st - the fundamental) from an guitar audio signal when a string is plucked - i.e. I'm making a digital guitar tuner. I've designed all the other components of the circuit and am now just trying to get the filter working. A low order IIR low-pass should be fine and shouldn't be too hard to implement... I'm just trying to figure out what to do with the fractions! Nick --- Quote End --- Why do you want to implement an IIR filter and not a FIR? If it is to get a minimal latency, then its fine, but simple to do, - NO!. IIR filters are deceptively difficult to implement, especially in fixed point arithmetic, as you can get internal oscillations and gross offset errors if you dont apply the proper scaling. In practice you probably find that you need surprisingly much extra internal precision. I bet this is the reason Altera abandonned their IIR filter design tool kit many years ago. So although you need fewer multiplications, additions and storage for an IIR compared to FIR, it is offset by the mentioned implementation difficulty and large internal word width. And be carefull not to slip additional delays into your feedback loop! This can easily happen when using pipelined building blocks, with the result that your filter will work differently than designed, but in a subtle manner. The FIR filter design tool in Quartus is excellent and your done in minutes, but if you require a filter with low latency, then IIR filter is the right and maybe more fun due to the difficulty:) - depends on your point of view. Fixed point or integer - its simply a matter of how you map the binary code to a physical value. The hardware is the same. Good luck - Altera_Forum
Honored Contributor
Thanks Kaz!
Like this:
See anything that looks wrong there? (think there might be as my audio output is now really noisy!) By the way, a=0.25 in this code. Thanks!module test_filter(clk,filter_in,filter_out); parameter W=7; // bit width - 1 parameter signed a=10'b0100000000; input clk; input signed filter_in; output signed filter_out; reg signed x,y; initial begin x=0; y=0; end always@(posedge clk) begin x <= filter_in; y <= ({x,10'b0000000000}) - (a*x) + (a*y); // y=(1-a)*x+(a*y) end assign filter_out=y; endmodule // test_filter - Altera_Forum
Honored Contributor
a of 0.7 need to be scaled up for hardware:
You can set (y) as 20 bits, (a) as 10 bits magnitude. then chop off output back to 8 bits by discarding LSBs of result(after optional rounding) Then a = round (0.7 * 1024) = 717 (1-a)*x becomes x*1024 - x*717 the term x*1024 = x*2^10 i.e. just insert 10 zeros infront. Figured out in a rush, I hope I am correct... - Altera_Forum
Honored Contributor
Thanks for both of your replies! Cleared a few things up! :)
I really should explain what I'm trying to do: All I want to do is implement a simple low-pass filter to attenuate all harmonics (except the 1st - the fundamental) from an guitar audio signal when a string is plucked - i.e. I'm making a digital guitar tuner. I've designed all the other components of the circuit and am now just trying to get the filter working. A low order IIR low-pass should be fine and shouldn't be too hard to implement... I'm just trying to figure out what to do with the fractions! For example:
This is just a test IIR filter I wrote - my question is: How would Verilog treat the 0.7 in the above code? Would the value of y be rounded? Do I need to add extra code if I want to multiply by fractions? (Also, my output from the ADC is now 8-bits (two's complement)! ;)) Cheers, Nickmodule test_filter(clk,filter_in,filter_out); parameter W=7; // bit width - 1 parameter signed a=0.7; input clk; input signed filter_in; output signed filter_out; reg signed x,y; initial begin x=0; y=0; end always@(posedge clk) begin x <= filter_in; y <= (1-a)*x + a*y; end assign filter_out=y; endmodule // test_filter