BiQuad LPF model - Q adjust doesn't seem to do anything

Algorithm development and general DSP issues

Moderator: frank

Post Reply
Digital Larry
Posts: 338
Joined: Mon Nov 12, 2012 1:12 pm
Contact:

BiQuad LPF model - Q adjust doesn't seem to do anything

Post by Digital Larry »

Here's how I am calculating my filter coefficients, from this web site

http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt

//==============================

w0 = (2.0 * Math.PI * f0)/getSamplerate();
// alpha = sin(w0)/(2*Q) (case: Q)
double alpha = Math.sin(w0)/(2.0 * q0);
// the following are for a low pass filter
// b0 = (1 - cos(w0))/2
double b0 = (1.0 - Math.cos(w0))/2;
// b1 = 1 - cos(w0)
double b1 = 1.0 - Math.cos(w0);
// b2 = (1 - cos(w0))/2
double b2 = (1.0 - Math.cos(w0))/2;
// a0 = 1 + alpha;
double a0 = 1 + alpha;
// a1 = -2*cos(w0)
double a1 = -2.0 * Math.cos(w0);
// a2 = 1 - alpha
double a2 = 1 - alpha;

And here's the actual filter code (it's ElmGen Java, I'll intersperse Spin ASM between each line):

Assume that input, output, D0 and D1 are all assigned to reasonable registers.

Code: Select all

//			sfxb.scaleOffset(0, 0);
SOF 0,0
//			sfxb.readRegister(input, b2/a0);
RDAX input, b2/a0
//			sfxb.readRegister(output, -a2/a0);
RDAX output, -a2/a0
//			sfxb.writeRegister(d1,0);
WRAX d1, 0	
		
//			sfxb.readRegister(input, b1/a0);
RDAX input, b1/a0
//			sfxb.readRegister(output, -a1/a0);
RDAX output, -a1/a0
//			sfxb.readRegister(d1, 1.0);
RDAX d1, 1.0
//			sfxb.writeRegister(d0,0);
WRAX d0, 0			

//			sfxb.readRegister(input, b0/a0);
RDAX input, b0/a0
//			sfxb.readRegister(d0, 1.0);
RDAX d0, 1.0
//			sfxb.writeRegister(output,0);
WRAX output, 0			

The frequency adjustment seems to work fine. I can adjust Q over a range of 1 to 1000 and can't hear a dang bit of difference. ???

PS This is my attempt at a Direct Form II filter.

By the way what I am looking for is a resonant LPF like you would find on a synth. Maybe the BiQuad is not good for this? It seems OK for plain filtering but it's not very exciting :lol:

I did find the resonant LPF from the "disco" patches at the Spin web site, however the coefficients for most filter patches I find here are all "magic numbers" and I can't trace what people did to get them.
Last edited by Digital Larry on Tue May 14, 2013 9:51 pm, edited 1 time in total.
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

Could be any number of reasons but check resolution, the FV-1 has a limited coefficient size and depending on the values you used for f0, Fs, etc. you may simply need coefficients that are smaller than can be resolved in the FV-1.
Frank Thomson
Experimental Noize
Digital Larry
Posts: 338
Joined: Mon Nov 12, 2012 1:12 pm
Contact:

Post by Digital Larry »

Well, I'll tell you what it was. I was calculating the 3 sections of the filter in the wrong order. I was doing it backwards.

I added some controls to let me select high pass and bandpass modes. Nothing at all came out of bandpass and highpass squeaked out a few pitiful glitches on the loudest signals. I looked back at the original example (I had taken a coding example from a different web site, that one was written in C, but same idea) and somehow got it in my mind that the example was backwards, but in fact it was right and I was wrong!

Here's what I had originally:

Code: Select all

//			sfxb.scaleOffset(0, 0);
SOF 0,0
//			sfxb.readRegister(input, b2/a0);
RDAX input, b2/a0
//			sfxb.readRegister(output, -a2/a0);
RDAX output, -a2/a0
//			sfxb.writeRegister(d1,0);
WRAX d1, 0	
		
//			sfxb.readRegister(input, b1/a0);
RDAX input, b1/a0
//			sfxb.readRegister(output, -a1/a0);
RDAX output, -a1/a0
//			sfxb.readRegister(d1, 1.0);
RDAX d1, 1.0
//			sfxb.writeRegister(d0,0);
WRAX d0, 0			

//			sfxb.readRegister(input, b0/a0);
RDAX input, b0/a0
//			sfxb.readRegister(d0, 1.0);
RDAX d0, 1.0
//			sfxb.writeRegister(output,0);
WRAX output, 0		


Here's what I wound up with that actually works!

Code: Select all

//			sfxb.scaleOffset(0, 0);
SOF 0,0
//			sfxb.readRegister(input, b0/a0);
RDAX input, b0/a0
//			sfxb.readRegister(d0, 1.0);
RDAX d0, 1.0
//			sfxb.writeRegister(output,0);
WRAX output, 0	
		
//			sfxb.readRegister(input, b1/a0);
RDAX input, b1/a0
//			sfxb.readRegister(output, -a1/a0);
RDAX output, -a1/a0
//			sfxb.readRegister(d1, 1.0);
RDAX d1, 1.0
//			sfxb.writeRegister(d0,0);
WRAX d0, 0			

//			sfxb.readRegister(input, b2/a0);
RDAX input, b2/a0
//			sfxb.readRegister(output, -a2/a0);
RDAX output, -a2/a0
//			sfxb.writeRegister(d1,0);
WRAX d1, 0	
Now the problem is that it works TOO WELL and I need to find a way to reduce the gain automatically as Q increases.
Post Reply