I'm trying to implement an IIR filter called "Shelving filter" on an embedded device. After implementation, the filter seem to function almost as expected, the gain and cut-off frequency are what I expected but there is one problem, at the frequency band where amplification is happening on the signal, there seem to be some harmonic distortion which doesn't exist in the other frequency band with 0dB gain. In the time-domain, This distortion always happens after 180 degree phase delay from the starting point of the signal for example for cosine wave, it happens around the negative peak and for sine wave, it happens when the signal is approaching the zero value. I have attached a picture of signals on oscilloscope below:
Blue one is the input signal and yellow is the output of filter.
My first thought in seeing your screen grab was "buffer glitch". And your comment:
"This distortion always happens after 180 degree phase delay from the starting point of the signal"
seems to concur. If the time from starting point of input to glitch doesn't change, and then that time continues to repeat, you may have a buffer issue somewhere; i.e. how you feed the filter or how you take its output and not the actual filter itself. Maybe try changing those buffer sizes, and see what happens.-Jeff
Yes I was suspicious of that as well but the thing is both input and output goes into the same buffer, the input is in 16 lower bits and output in upper 16 bits,( i also have tried changing their places if there was a problem with buffer then both input and out should have been affected
No, not the case at all. My guess is you can stuff all zeros or all 0xffff into the buffer and still see the glitch. Where in your code you move points in/out of the buffer you can easily have a problem, regardless of what are the point values.
If all else fails, my tried and true method of implementing (and debugging) filters on embedded devices, is:
1) first, code the filter up in "offline C" on a PC (GNU C, or whatever available)
2) feed a simulated signal into it - I've used a swept sine right within the C implementation, using the sin() function
3) using 2), confirm correct output of this version. For instance, for each frequency of the swept sine, keep track of the maximum input and output over a number of cycles, and then print out the 20*log10(output/input) ratio versus frequency to confirm expected results.
4) Once 3) is confirmed, you now know the filter design works, and can then focus on the embedded implementation for the problem. Often, the version of 2) can be used in comparison with the embedded implementation, to zero in on the source of the problem.
Since you are the implementer of said embedded system, that means you have the source code and I'm assuming an editor/debugger to go with it. If so, I recommend expanding your debugging approach beyond just a scope. I would go into the debugger and set breakpoints/single-step and/or log samples at particular nodes of the filter. You'll get a finer grain idea of where things are going wrong...if at all. The problem could possible be outside the code but you'll want to confirm that by first ruling out the code as the problem.
Other things that can make debugging easier (sometimes) in these situations is to try a simpler input signal of different amplitudes (singe shot pulse, repeating pulse/square wave, or sawtooth). And you can try a simpler IIR filter as well, e.g. a first-order leaky integrator type like the moral equivalent of an RC filter in code. The basic philosophy is: build off of success as opposed to backing out of failure.
Please let the blog know what you find.
Judging by above scope you seem to have saturation/overflow glitch issue on negative values.
can you show the sine case when the glitch occurs near zero.
I forgot to say that I investigated that issue and it wasn’t because of saturation/overflow, I tried lowering the amplitude as well but this seems to happen irrelevant of that.
I have also checked each individual sample in that range and it seemed fine and overflow was not detected.
I’ll try add the sine case next time
You don't seem to have a vertical scale on the plot (or horizontal either, but that doesn't matter). I assume that the sine wave input goes from -1 to 1, e.g. x=sin(kn) where n is sample number. If kn is a value for which sin kn = -1, you are putting -1 into the filter. But suppose your number coding for the input interprets the coding for -1 as something else. For example, a fixed point 2s complement representation of the whole scale would not be able to represent the most negative number, -2^r, and it might be interpreted as 2^r. The software producing the display may interpret -2^r correctly but the software simulating the filter may be interpreting it as +2^r.
Try using an input of (1/2)sin kn and see if the glitch disappears, or try
2 sin(kn) and see if you get glitches beginning halfway between when the input is -1 and when the input is -2.
Hi I have tried changing the amplitude of both input and output but the problem seem to be irrelevant o amplitude. Also this screenshot is for cosine wave, for the sine case the same thing happens around zero
Hi - I am irritated by the fact that this filter behaves differently for sine and cosine waves - from the point of view of the filter the only difference is at the start of the signal afterwards it is just a time delay - and since an IIR filter is linear and time invariant there cannot be a difference.
This leads me to a suspicion:
- Do you happen to process this filter in blocks of N samples?
- Can it be that you initialize the delay memories to zero at the start of each block? That would explain the error.
- If not, I suspect there is an error in the saving and/or restoring of the delay memories at the end or start of the processing block. That's what it looks like to me
Only way I would know to work the problem would be through stage debugging.
Dump vectors out of each stage and compare them against the expected values.
In the screen shot provided you say the blue waveform is the input. It appears to pass through (0,0) so it looks like a sine function. (Unless the vertical axis passes through some other sample number than 0.)
A few questions.
1) Are you using fixed point or floating point arithmetic? If fixed point, how many bits?
2) You say your filter is an IIR filter. That means that it is equivalent to the equation y[n] = a_1y[n-1] + a_2y[n-2] + ... + b_0x[n]+b_1x[n-1]+...
There are several ways to achieve the same filter with different equations. The one I gave is called the "direct form". Usually we express the equation in the frequency domain (z-plane for digital filters) with poles and zeroes of the transfer function. What realization equation are you using? How many poles and zeroes? The direct form has many numerical issues for very high order filters. Other forms are called "parallel form", "serial form", "coupled form", and some others including, more recently, "lattice form".
3) Can you show us the equations, the poles and zeroes, etc?
4) Are you realizing the filter on a computer? Programmed on a specialized computer? Simulating a realization using digital logic, such as gate arrays, etc? Whatever tool you are using, have you used it successfully for some other kinds of filters?
5) Are there some inputs that seem to give answers that correspond to your aim?