help with simple resonant RC_filter in AVR ASM

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

hello all,
i started experimenting with some simple DSP routines on an Atmega644
works surprisingly well so far - allready got 1 FM pair and 1 PWM/Saw Osc with separate vol EGs...

my problem is the filter. I decided to implement a simple RC filter:

Code: Select all

a += f * ((in - a) + q * (a - b));
b += f * (a - b);  
without resonance the filter is working like a charm. but as soon as i raise Q
i get horrible clipping. since i'm quite new to assembler, heres my source, maybe someone spots my error.

http://chipmusik.de/lp.txt

have a nice day,
nemuri

Post

Code: Select all

a += f * ((in - a) + q * (a - b));
b += f * (a - b);  
If I understand correctly you have two 1 pole lowpass sections, with the 2nd one taped as highpass (in-out), so the feedback is bandpass?

What looks odd to me is where you actualy adding in the feedback.

I think it'd probably be better like this..

in += q * (a - b);
a += f * (in - a);
b += f * (a - b);

Assuming you dont already know of it, there is a famous dsp version of the State Variable Filter. It's done in the same way, replacing electronic components with digital equivelants. Anyway here's some info on it...

http://www.earlevel.com/Digital%20Audio/StateVar.html
http://vellocet.com/dsp/svf/svf-stability.html

plenty of code for filters, a few versions of the SVF

http://www.musicdsp.org/archive.php?classid=3

Post

how the resonance comes in is explained in the famous thread
here

but thanks for the links

Post

Nemuri wrote:how the resonance comes in is explained in the famous thread
here
Heh, I was going to post a link to that thread. :) Since you're familiar with aciddose's post in the above thread, I'm assuming you're using the provided formula for calculating the 'q' coefficient?

Code: Select all

q = feedback + feedback / (1.0 - f); 

Post

Nemuri wrote:how the resonance comes in is explained in the famous thread
here

but thanks for the links
Ok,

lossy integrator == 1 pole lowpass filter.

Now I understand why the resonance was done like that. He's scaling the resonance / feedback relative to frequency. Likey for stability reasons.

[edit] it'd be like altering what i wrote to this..

in += f * (q * (a - b));

ermm.. so that looks fine, i guess it must be some issue with your assembler.

Looks like you're using an 8 bit microcontroler :shock:

Ok it's do-able, but rather you than me.

Are you calculating f and q correctly? And it looks like your multiply instructions are only 8 bit? At least you're using the registers in 8 bit add/sub in one part and them in a multiply. I cant see that working very well, if at all.

Code: Select all

sub	temp, ZL;\
sbc	r21, ZH	;/ (a-b) signed

mulsu	r21,r22		;mul signed:unsigned -> (a-b) * Q
Looks to me like the result of (a-b) is spread across two registers.

"temp|r21"

But you're only using "r21" in the multiply. Which is the just the bottom half of the result and will cause some weirdness. In part cause it's basicly like extreme foldback clipping. Second cause the sign bit is now bit 8 of what was a 16 bit integer. Which actualy means the sign bit is now nothing to do with the sign of the original 16 bit number.

Then again I dont know that particular microcontroler, so i could be completely wrong.

*shrug*

Post

you need a minimum of a twelve-bit register to do a multimode filter if my memory is accurate. (often not, experiment for yourself..)

"Likey for stability reasons."

actually that function adjusts the amplitude of the feedback to account for group-delay in the filter. each integrator introduces one sample of delay in a digital filter (generally) and this means the maximum frequency of the filter is (samplerate/4). "stability" actually is another issue, and the practical range of a filter like this is actually (samplerate/6.5), due to numerical stability issues. (classic newton issue.)

the multimode / "state-variable" (#1) filter generally is uncompensated as it has only a single sample delay in it's feedback path meaning that a full range can be managed with 2x oversample. the first filter which is a sallen-key filter is much more unstable due to two samples of delay in it's feedback path.

it simply isnt possible to correctly calculate a filter in dsp - period. you can only ever approximate the values that you should be getting to the point where noise, quantization and so on make it irrelevant. this is generally achieved via oversampling and a minimum of 2x oversampling is generally needed in every filter. additional oversampling can sometimes help, but it often does not. approximate compensations are generally used instead while the real phase error introduced into the filter is ignored. the only way to absolutely overcome this issue is to use infinite, or practically infinite (1024x or something?) oversample.

1) (this name isnt perfectly accurate as it can refer to other filters as well)

the solution to your PROBLEM however is that you simply must hard-clip the feedback path. a hard-clip will introduce no distortion, avoiding aliasing while the feedback level remains below or equal to 1.0. a waveshaper/saturation will introduce distortion and result in aliasing - you should try to use a band-limited waveshaper.

for example, if you use 2x oversample, you should use a waveshaping function with a band limit of 0.5. if you introduce frequencies above nyquist you will need to filter/convolve your output before decimating.

Post

juggled a little bit with the scaling...
now i've got this
AVRfilter

still not exactly resonating, and tends to overshoot, but i will try to limit the feedback like recomended :)

Post

btw, i think the "theoretical" frequency limit of a filter like this without oversampling is sr/[2pi].

the "practical" limit however is like i said, sr/[6.5].

Post

heres another avr synth demo...
the 2nd channel with the fm pair is working nice
fm+saw

:)
nemuri

Post

@aciddose:

great! the tip with the harclipping really solved the problem :D

ringin-filter

finally :)

thank you very much!

Post

if the chip doesn't have a clipping function, you should try something like this for fast clipping without a branch:

#define _B (15) //bits - 1
#define _SIGN(N) ((N)>>(_B))

#define _ABS(N) ((N)^_SIGN(N))
#define _CLIP(N,R) ((_ABS((N)+(R))-_ABS((N)-(R)+1))/2)

lots of instructions though, (should be 12) you might want to use a branch (4 inst) if the chip does branching OK.

Post

aciddose wrote: "Likey for stability reasons."

actually that function adjusts the amplitude of the feedback to account for group-delay in the filter. each integrator introduces one sample of delay in a digital filter (generally) and this means the maximum frequency of the filter is (samplerate/4). "stability" actually is another issue, and the practical range of a filter like this is actually (samplerate/6.5), due to numerical stability issues. (classic newton issue.)
What I meant was that the point at which resonance occurs in your filter, and the SVF, and the moog variations you'll find online, doesnt stay fixed at the 3db point. (or 12 db in 4 pole ect) The gain at which resonance occurs varies with cutoff frequency. So you have to adjust the resonance gain in respect to frequency in order to keep the the resonance steady, and to stop it tipping over into a chaotic exploding filter.

This is not instability because of numerical issues, truncation / rounding or such like. This is instability because mapping of the input parameters to the actual coeficients took them into unstable teritory. I mean you only have to go from an overall feedback gain of 0.99 to 1.01, to go from a 40db resonant peak, to broken tweeters and bleeding eardrums.

The problem is that the resonance & frequency controls are never completely uncoupled. At least not in any of the filters whose code you'll find online.

For example the way you tap the second pole to grab a highpass from it results in a filter that looses overall gain as it gets near to nyquist. Which actualy means the 3db point of the first pole and the 3db point of the highpass tap off the 2nd pole actualy start to drift apart the nearer you get to nyquist. Add into that mix the extra phase shift of the 1 sample delay, and the gain needed for a certain level of resonance is no longer the same across all frequencys.

Post

I ran the formulas for calculating the aciddose's filter in Excel:

Code: Select all

f = 1.0 - exp(-2*pi * hz/rate); 
q = resonance + resonance / (1.0 - f); 

Code: Select all

Freq    f               q               Resonance
0       0               1.5             0.75
500	0.068759647	1.555377471		
1000	0.132791405	1.614843827		
1500	0.192420362	1.678700978		
2000	0.247949252	1.747273126		
2500	0.299659996	1.82090841		
3000	0.347815128	1.899980676		
3500	0.392659129	1.98489137		
4000	0.434419673	2.076071584		
4500	0.473308777	2.173984238		
5000	0.509523879	2.279126431		
5500	0.543248844	2.39203197		
6000	0.574654892	2.513274072		
6500	0.603901472	2.643468283		
7000	0.631137067	2.783275595		
7500	0.656499952	2.933405808		
8000	0.680118894	3.094621129		
8500	0.702113806	3.267740045		
9000	0.722596355	3.453641479		
9500	0.741670532	3.653269247		
10000	0.759433175	3.867636857		
The sample rate is 44100.

What I notice is that q increases as cutoff frequency increases.
nollock wrote: What I meant was that the point at which resonance occurs in your filter, and the SVF, and the moog variations you'll find online, doesnt stay fixed at the 3db point. (or 12 db in 4 pole ect) The gain at which resonance occurs varies with cutoff frequency. So you have to adjust the resonance gain in respect to frequency in order to keep the the resonance steady, and to stop it tipping over into a chaotic exploding filter.
So the formula is designed so that q will increase the resonance gain with respect to the cutoff frequency to keep the overall resonance gain even?

I've used this filter quite a bit. Can someone enlighten me as to how this formula:

Code: Select all

q = resonance + resonance / (1.0 - f); 
is arrived at? Could be the answer is over my head, but I'd love to hear it anyway.

Post

Leslie Sanford wrote: So the formula is designed so that q will increase the resonance gain with respect to the cutoff frequency to keep the overall resonance gain even?
Yes. Although the problem is different with different filters. The basic issue is that it's the phase of the feedback that defines where the resonance peaks. With positive feedback the peak will be where the feeback signal is in phase (phase = 0, 2PI, 4PI ect), with negative feeback it is where the feedback signal is out of phase (phase = PI, 3PI, 5PI ect)

But that point doesnt stay at a fixed gain. With ADs filter, it moves to lower gain as cuttoff increases so you need to bump the resonance up to compensate.

With the 4 pole moog variants it increases gain with higher cutoff. This is basicly because as cuttoff frequency increases, the one sample delay in the feedback path add's more and more phase shift, so the point at which the total pahse shift = PI starts to lag behind the 12db point of the filter.

ADs filter is a bit more complicated as it's a bandpass feedback, and the highpass off the 2nd pole causes different gain issues.

So it's a combination of the filters phase/magnitude not tracking properly, and of the extra phase shift from the delay in the feedback.

I've used this filter quite a bit. Can someone enlighten me as to how this formula:

q = resonance + resonance / (1.0 - f);

is arrived at? Could be the answer is over my head, but I'd love to hear it anyway.
I dont know how AD came up with that, but I've been using pole/zero analysis to map the phase/gain which is then used to generate lookup tables. By that i mean I wrote a program that that does all the number crunching. It locates where the resonance occurs and what the overall gain in the feedback path is at that point. Thats basicly what it does anyway.

Post

aciddose wrote:btw, i think the "theoretical" frequency limit of a filter like this without oversampling is sr/[2pi].

the "practical" limit however is like i said, sr/[6.5].
Well, you can take it higher, but once you put in clipping, the aliasing starts causing trouble. Pink has essentially a tweaked version (more non-linearities and some minor tweaks) and oversamples by two times (with crappy filtering); at 44.1kHz it'll lose self oscillation at around 6k or so which means around sr/(7.35). It's damped down on purpose though, but back when I played with it, there was simply no reasonable way to make it track properly much higher so who cares.

It's a nice filter though; here is a old test of my somewhat tweaked version in self-oscillation, with some white noise added (it would self-oscillate just as well without, but then it wouldn't sound so much like a whistle; live played from keyboard with oscillators fully turned off).

Post Reply

Return to “DSP and Plugin Development”