1
$\begingroup$

I want to design/implement a simple feedforward/feedback all-pass filter, and I am having some troubles and questions with it.

From Shroeder design (based on J. Smith article here):
Feedback/feedforward all-pass

I came up with the following pseudocode (for first-order all-pass filter, meaning the delay was set to 1 sample, and b0 = aM):

float allPassGain = aM, value from [0.0, 1.0);

float allPassFeedback = 0.0;
float allPassDelayedSample = 0.0;

float processAllPass(float x)
{
    float delayInput = x + allPassFeedback;
    float feedForward = delayInput * allPassGain;

    float delayOutput = allPassDelayedSample;
    allPassDelayedSample = delayInput;

    allPassFeedback = delayOutput * -allPassGain;

    return delayOutput + feedForward;
}

Here x is an input sample, to process some signal with this all-pass I am going through the signal feeding it sample-by-sample into processAllPass, and store the outputs in the parallel output signal.

But unfortunately it seems like this approach doesn't work. For example, if I create a simple Phaser with a set of successful all-pass filters designed like that, I don't get the desired effect, instead the signal becomes unstable and shoots through the roof.

Does the pseudo-code have issues? I am setting aM to an arbitrary value and the delay line length is strictly 1.


Matt L.'s answer helped me to fix the code, and here is the fixed pseudo-code if that would be interesting (please also note that for the Phaser effect I find it better to switch coefficients' signs, it is slightly different version of the all-pass filter, presented in e.g. "Reducing Artificial Reverberation Algorithm Requirements using FDN" by Jasmin Frenette):

float allPassGain = aM, value from [0.0, 1.0);

float allPassDelayedSample = 0.0;

float processAllPass(float x)
{
    float delayOutput = allPassDelayedSample;
    float feedBack = delayOutput * allPassGain;

    float delayInput = inSamp + feedBack;
    float feedForward = delayInput * -allPassGain;
    allPassDelayedSample = delayInput;

    return delayOutput + feedForward;
}
$\endgroup$
2
$\begingroup$

First of all make sure that the magnitude of $a_M$ is strictly less than $1$; this is necessary for the filter's stability. Second, you use several unnecessary variables. This is no serious problem, but it makes it harder to see what's going on. For $M=1$ a simple pseudo-code would be

v = x - aM * v_old;
y = v * b + v_old;
v_old = v;

The important thing is that the state variable v_old must be remembered between function calls. Are you sure that your variables allPassFeedback and allPassDelayedSample are not reset to $0$ every time you call the function?

$\endgroup$
  • $\begingroup$ Thanks for the answer! aM is less than 1, yes, so better would be value from [0.0, 1.0). As for the unnecessary variables -- I did that for clearer (diagram-pseudo code) transition, but I will check if my code could be simplified to yours. The variables you're asking about are not reset to 0 everytime, I checked that $\endgroup$ – DSPguy Jan 13 '15 at 11:47
  • $\begingroup$ Hm, yours pseudocode is a bit different than mine it seems, in mine I have additional delay, so the feedback seems to act like additional delay line (I am calculating/storing the feedback after I get the delay line outputs, but use the feedback earlier), probably that's the difference that hurts, I will check! $\endgroup$ – DSPguy Jan 13 '15 at 12:00
  • $\begingroup$ Yes! This was the difference ruining everything, so after I quickly re-done the feedback line to contain immediate outputs from the delay line (/w gain), the filter worked, thanks for your answer! Can't upvote it since I have no reputation though :( $\endgroup$ – DSPguy Jan 13 '15 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.