Search

All Sections

Products

Order

Company

Community

Share

Learn

Login / Register

Change password

Forgot password?

Hi all!

This code was adapted from a Motorola App Note, and I have recoded it to avoid dividing by zero and infinity in the coefficient values [(cos-sin)/(cos+sin)] instead of [(1-tan)/(1+tan)]. The transfer function is really quite simple --

Actually the name "Biquad" is a misnomer with respect to my filters. They are all really just Direct Form implementations of IIR filters. I permit up to 8 or 9 sections, I believe, but the basic standard filters are all just 2-pole, 2-zero filters, and lower order. On occaision I will implement cascaded sections as one filter block using more than the 5 coefficients per 2nd order section.

I originally started out implementing my filters as biquadratic sections, but Kurt convinced me to forego the effort as Direct Form systems on the DSP's are just as accurate. Biquadratic forms attempt to control the gain of interior nodes to prevent overflow distortion. But the DSP's already permit 8 guard bits in the upper end of the accumulators, so this is unnecessary here.

As for the "Reson" filter, (terminology borrowed from CSound), you can take any one of my filters that I have provided and substitute the following code in the DSPWithInputs? sound block:

"BPF filter coefficients." | b0 b1 b2 a1 a2 fc cf sq cq alpha beta gamma mu sigma | fc := ?Fc / SignalProcessor halfSampleRate. cf := fc normCos. fc := fc / 2 / ?Q. sq := fc normSin. cq := fc normCos. beta := 0.5 * (cq - sq) / (cq + sq). gamma := (0.5 + beta) * cf. alpha := ?Level * 0.5 * (0.5 - beta). mu := 0. sigma := -1. b0 := alpha. b1 := mu * alpha. b2 := sigma * alpha. a1 := gamma. a2 := beta negated. self initialValueAt: 0 xPut: 0 yPut: 1. self initialValueAt: 1 xPut: 0 yPut: b0 translatedTo24BitInteger. self initialValueAt: 2 xPut: 0 yPut: b1 translatedTo24BitInteger. self initialValueAt: 3 xPut: 0 yPut: b2 translatedTo24BitInteger. self initialValueAt: 4 xPut: 0 yPut: a1 translatedTo24BitInteger. self initialValueAt: 5 xPut: 0 yPut: a2 translatedTo24BitInteger.

This code was adapted from a Motorola App Note, and I have recoded it to avoid dividing by zero and infinity in the coefficient values [(cos-sin)/(cos+sin)] instead of [(1-tan)/(1+tan)]. The transfer function is really quite simple --

H(z) = (1 - 1/z^2)/(1 - 2*R*cos(theta)/z + R^2/z^2)

That numerator helps keep the gain more or less constant with center frequency. Angle theta is the angle corresponding to the pole location (center frequency) in the Z-domain (theta = 2*Pi*fc/fsamp), and radius R (which must always be less than 1) can be computed as roughly R = 1 - 1/Q, for filter Q. The center frequency is actually a little offset from the posiiton I mentioned here, but as R approaches 1, Q -> high, and the center frequency aligns more closely with the value you requested. Details can be found in Ken Steiglitz's wonderful little book, "A Digital Signal Processing Primer".

In addition to the gain correction mentioned by previous writers on this page, my Reson filter incorporates zeros at +/-1 in the Z-plane. That helps level out the gain response of the filter as you sweep its center frequency. Without those zeros, the gain varies with frequency.

-- DavidMcClain - 22 Jan 2004