View Full Version : IIR Direct Form 2 C Code
Paul Swearingen
04-13-2002, 01:53 PM
Hi, Chris, Mike, or anyone else who can help...
I'm using 2 - 4 cascaded sections of IIR Direct form 2 for my music design. I designed a general purpose filter sweep routine that plots each pixel of magnitude for each freq and am having problems that seem to point to the actual filter code I'm using. All the coefficients are correct.
I've tried 2 different styles of routines and neither of them appear to work correctly.
Thanks,
Paul Swearingen
408-258-0233
psps@ix.netcom.com
cstrahm
04-13-2002, 04:03 PM
I'm not sure I understand what you're doing. Is this an implementation code in a DSP? If so that's going to be somewhat specific to how your DSP works. Another thing to watch out for is the confusion between A/B numerator/denominator. Some people define them opposite. Make sure you are using the right sets where they belong. IIR filters can also be very sensitive to roundoff errors. I don't know if you are using fixed or floating point or what word/coef size. Not much more I can say without more information.
Paul Swearingen
04-13-2002, 05:14 PM
Hi Chris,
I'm using a Macintosh with a C++ environment.
I used coefficient groups that I cut and pasted
using FilterShop set to 32 bit floating
point mode during the coefficient calculations.
I grabbed and placed into tables 1200 sets of
coefficients going from 5 Hz to 80 something
kHz with a sample freq of 192kHz.
(as an aside)
Looking at the tables I realized I could simply shift left or right a place to effectively change the sample rate since powers of 2 are the same, just shifted.
Anyway, a float in c is 32 bits. I saw from your
tables that you had an added 0 added to the right of each number, which I deleted.
I chose the simplest form (Direct Form 2) since it was the simplest and I figured even if it was slightly less accurate in certain circumstances, it would run quickest. (just a guess that it may have some inaccuracies over other forms. It didn't seem to when I plotted the curves.)
For the code I used your small schematic showing summers, multipliers, and unit delays as a model.
I placed the coefficients where I did because that is what is shown.
If there are roundoff errors I'd expect to find them mostly on the low and high ends. The curves I get with my curve drawing routine show basically garbage. Your curves were great, except, usually they would crap out at the way low end (5Hz).
Except for the trailing 0 on the coefficients, I grabbed the entire width of the them. I found it
curious they were greater then 32 bits of resolution even when set to 32 bit resolution using FilterShop. I figured more couldn't hurt.
I built a 256 entry sin lookup table that I index through with a floating point index and generate 8 sin waves worth of input for each freq by choosing the correct floating point increment I add to an accumulator that I "and" with 0xff to point into the table. As I sweep I reset the filter memory each time first, and take the largest of the max and abs(min) output excursions. There is probably a faster way to sweep the frequencies, but I haven't figured it out.
Hope this helps. Thanks,
Paul
cstrahm
04-13-2002, 10:27 PM
My guess is you have some sort of bug in your code. You've got enough things going on that there is no way I can tell you what is wrong without seeing the whole picture. That's hard to do without being there.
I would suggest that you start with a very low order ultra simple coef set that you can track the operations through yourself step by step. With sine lookup tables etc. there are plenty of locations for errors.
It sounds like you are making a digital IIR eq. If so, there is already a IIR Equalizer design dialog which will give you your table of coefs vs. parameter sweeps.
Some of your statements didn't sound quite right. It would be useful to check your coefs with what is produced from the EQ dialog result tables.
Sorry I can't be more help.
Douglas Marsh
04-14-2002, 09:45 AM
I couldn't tell you if the routines are correct or not. I would have to see a book or the math from a verified source before I can tell if the translation into 'C'/'C++' is correct.
I do have a question as to resolution/detail... Is a 32-bit (IEEE?) float(-ing) number fine enough?
Assuming math is correct, everything 'C'/'C++' looks good. No mixing numeric types so no casting problems. Casting problems occur with the compiler tries to optimize the code based on numeric type (adding an integer to a floating point number for example, this got me a few times with older compilers, MIX C anyone? I now perfer GNU C/C++).
The only thing that stands out is the way the function has been prologed. Why are you not passing a0-a5,b1,b2,b4,b5,m0-m5? I assume these are globals that never change, all except m1-m5 in the first approach and m0-m5 in the second approach.
You may want to disable compiler optimization or (depending on compiler) look at the output in assembler (with 'C' source comments). GNU compiler is -O0 if I remember correctly.
I suspect one of two things: compiler error, or code / math "translation" error (human).
P.S. Did you prime the loop / global vars before calling these functions?
--Doug
Paul Swearingen
04-14-2002, 11:32 AM
Hi Doug,
Thanks for replying.
I preset the coefs, beforehand and they are
global and don't change, for each filter type.
The real code uses arrays, internally, so each filter simply has an index to refer to it.
And yes, I clear out the working memory before it's used.
I'll look into the compiler optimization issue...
I'm using the latest Code Warrior development
system.
Thanks for your input,
Paul
cstrahm
04-14-2002, 04:48 PM
Glad you found the bug. Sometimes it's the simplest things that are easiest to overlook.
vBulletin® v3.8.4, Copyright ©2000-2012, Jelsoft Enterprises Ltd.