Forum Rule: Always post complete source code & details to reproduce any issue!

biquad output noise
Hello *,
im am working on a SDR receiver based on the Teensy 3.6.
The receiver is based on the Weaver Mothod for SSB reception.
Bascialy I do filter and process the I2S audio signal comming from the SGTL5000.
I observed the following strage behaviour:
 The RMS level is lower at the I2S input (30 digits peak to peak ~ 4bits) than at the output of the biquad filter (150 digits peak to peak ~ 6 bits)
 The biquad is a low pass fc=6khz 8 pole 96ks
I checked the frequency response of the filter and it seems ok, filter coeffs have been calculated with iowahils.
What could that be?

Hi,
I found out the same a little while ago...
I think it is something called limit cycles. It is present when the input to the filter is very low. The filter itself will make the noise. With fixed points it will be a quite uniform/stable noise. But if you use floating points it will jump up and down in level...
There are several ways to "fix" it. But it is in the nature of IIR filters. So the simple solution is to use FIR filters...
You can read more about it here:
https://www.rane.com/note157.html#ref
or here:
http://freeverb3vst.osdn.jp/tips/iir_filter.shtml

Hi,
thanks for your answer.
I am still using the IIR because they are very god, knowing this (noisy output round 60 dB under max output) you can work on a work around.....thats what I did :)

Senior Member
On my lowpriority list of issues to investigate is a "noise shaping" feature in the biquad filter, which may not be implemented properly. Or it may not even be the right thing to do at all?
https://forum.pjrc.com/threads/55190...l=1#post198535

Senior Member
Summarizing the main points from the links given above and summing this up with my own experience with IIR filters on the Teensy and having read pages 280ff in the excellent book by Rick Lyons (Understanding Digital Processing), maybe there is a simple solution to the problem:
* it seems the main problem in implementing IIR filters is the arithmetic accuracy of
1.) the filter coefficients (= coefficient quantization = limited precision coefficients),
2.) overflow errors in fixedpoint calculations,
3.) roundoff errors = limit cycles = deadband effects
They cause "ringing" of the filter, also called "filter makes the noise", "selfoscillations", "stable noise", "biquad noise" etc.
(So it seems we also have a multitude of nomenclatural problems here ;), but I personally think it breaks down to some simple recommendations.)
re 1.)
* using single precision floating point precision seems to be a good solution. 16bit coefficients do not seem to provide enough precision (one of the sources says we need at least 20 bits for the recursive path and 16 bits for the nonrecursive part)
2.) / 3.)
* use cascaded 2ndorder IIRs > thats perfectly implemented in the audio lib by using cascaded biquad filters ! However, the user should ensure that the filter stages with the highest Q are placed first [but that is only possible in floating point implementations . . .]
* "the MAC operation should have at least 52 bits integer or double floating point precision" > now thats really a hard criterion, eg. the variables in the Teensy audio lib are only 32bit precision
* to be honest, I have not understood noise shaping/dithering, so I will not comment on that, but it seems a possibility to improve the filters SNR for low frequencies, but increases SNR at high frequencies
CONCLUSION ("SIMPLE" SOLUTION):
* for most applications, the audio lib with 16bit fixed point coeffs as it is now, will be of sufficient quality!
* however, if you want lower noise, use float coefficients with single precision AND use floating point implementation of the calculations, as provided by the CMSIS implementations:
https://www.keil.com/pack/doc/CMSIS/...ascadeDF1.html
Coefficients can be calculated by Iowa Hills IIR Filter designer (if you want fixed filter responses) or can be dynamically calculated (for 2nd order filters) by using these formulae http://www.musicdsp.org/files/AudioEQCookbook.txt
For testing your filters and as a didactical excercise I would recommend the option "TestFilter" in the Iowa Hills IIR filter designer. Click on fixed point and change precision to 16bit. You will see that caused by the limited precision the filter response is entirely different than what you intended it to be . . . If you designed for 60dB stopband attenuation, it can easily be that the noise is 15 dB higher at only 45dB below the signal (especially for more exotic filter responses like the elliptic filter). This is the effect of the imprecision of the coeffs and the calculations that can be simulated and visualized in that program (however, I understand only part of the options that can be tweaked in the simulation program. Test it by yourself: try a lowpass with 80dB stopband attenuation and compare the output of a sinewave with 16bit fixed point and 32bit floating point respectively in the "TestFilter" option).
All the best,
Frank DD4WH
Last edited by DD4WH; 03242019 at 11:12 AM.

Senior Member
Originally Posted by
DD4WH
* for most applications, the audio lib with 16bit fixed point coeffs as it is now, will be of sufficient quality!
We're already using 32 bit coefficients and all 32 bit calculations within the biquad filter.
The 32 bits are truncated to 16 bit for the final output, and the low 16 bit are (perhaps incorrectly) fed back using the "noise shaping" technique described at this page. Scroll down to "Direct form I with firstorder noise shaping".
http://www.earlevel.com/main/2003/02/28/biquads/
The audio lib's biquad coefficients have never been 16 bits.

Senior Member
Sorry, my mistake, I thought "int" was 16bit. So the coeffs have 32bit precision, I agree.
So, we boiled the problem down to the internal precision of the calculations:
The link you mentioned states:
In general, 16bit fixed point processing is not suitable for audio without double precision coefficients and computation.
So, I think we would need double = 64bit calculations inside the code, which is 32bit at the moment.
This is also highlighted by http://freeverb3vst.osdn.jp/tips/iir_filter.shtml
The MAC operation should have at least 52 bits integer or double floating point precision.
As far as I can interpret the code with those highly optimized calculations, it has 32bit precision at the moment, but please correct me, if I am wrong.
How much performance you can gain from "noise shaping" and whether that is good for every desired frequency bandwidth, I simply do not know.
However, as I already stated, the current implementation of the biquad in the audio lib is still good enough for most applications!
But in the special case highlighted by the OP DO7JBH, to use IIRs as the main filter in an SDR, you will soon run into noise problems, especially if you design steep filter skirts with elliptic filter response.
However, I do not know if that is the filter response you chose in your design, DO7JBH? And what do you mean by "workaround", would be interesting to know!

Originally Posted by
PaulStoffregen
We're already using 32 bit coefficients and all 32 bit calculations within the biquad filter.
The 32 bits are truncated to 16 bit for the final output, and the low 16 bit are (perhaps incorrectly) fed back using the "noise shaping" technique described at this page. Scroll down to "Direct form I with firstorder noise shaping".
http://www.earlevel.com/main/2003/02/28/biquads/
The audio lib's biquad coefficients have never been 16 bits.
Seems like this is dithering? As dithering use a random signal injected into the filter. And the lowest bits are random(the noise floor) it should be about the same. But maybe worth a try to use white noise instead?
I don't fully understand the code, but is this feedback on every stage inside the filter or is it only a feedback at the end of the four stages?

But in the special case highlighted by the OP DO7JBH, to use IIRs as the main filter in an SDR, you will soon run into noise problems, especially if you design steep filter skirts with elliptic filter response.
However, I do not know if that is the filter response you chose in your design, DO7JBH? And what do you mean by "workaround", would be interesting to know!
Hi everyone,
I was not aware of the noise, I expected similar response to FIR at this point.
And because I build a receiver as described to be the third method (Weaver) I had not have to use the FIR Hilberts. In this case the IIR should offer better shape factors for less computing power.
At this point I measured the input signal direct after the filter with a regular bandwidth of e.g. 3kHz, I was wondering about the high noise level, this noise level was higher than at the input of the SGTL5000 which at this point had more than facto 30 higher bandwidth.
My workaround is like using the FFT (before any filtering) and only compute the energy at the bins representing the filter bandwidth.
daba

Senior Member
Originally Posted by
omjanger
I don't fully understand the code, but is this feedback on every stage inside the filter or is it only a feedback at the end of the four stages?
Each biquad stage is implemented as the "Direct form I with firstorder noise shaping" diagram on the Earlevel Biquads page.
Seems like this is dithering?
No, not dithering. This is feedback of the difference between the full 32 bit output state and the truncated 16 bits output (of each biquad stage).
But maybe worth a try to use white noise instead?
Seems unlikely to do anything but add noise, but who knows, maybe? Are you going to implement this and then carefully verify the result with and without the noise source added? Would you do this by actually running the code on Teensy? Or running numerically identical integeronly code on a PC? Or some other simulation that's not numerically identical to the actual implementation on Teensy?

Originally Posted by
PaulStoffregen
Each biquad stage is implemented as the "Direct form I with firstorder noise shaping" diagram on the
Earlevel Biquads page.
No, not dithering. This is feedback of the difference between the full 32 bit output state and the truncated 16 bits output (of each biquad stage).
Seems unlikely to do anything but add noise, but who knows, maybe? Are you going to implement this and then carefully verify the result with and without the noise source added? Would you do this by actually running the code on Teensy? Or running numerically identical integeronly code on a PC? Or some other simulation that's not numerically identical to the actual implementation on Teensy?
I am running my code on Teensy yes. At the moment I am working on the HW on my project, but I will investigate this further when I get to the programming again and publish the results here.
Posting Permissions
 You may not post new threads
 You may not post replies
 You may not post attachments
 You may not edit your posts

Forum Rules