0
$\begingroup$

In a related question a probable solution was given to build a first-order digital filter and then cascade three of them in order to turn white noise into pink. I have applied the C++ as follows but still the signal sounds and looks like white noise.

I would like to know what is wrong with my implementation and why I don't hear pink noise. For reference, the poles and zeros come from Robert Bristow-Johnson's work here.

Header:

float *state = nullptr;

Implementation:

state = new float[0.0]; in Constructor.

Then in the loop, for (int i=0; i < numSamples; i++)

float first = first_order_filter(whiteNoise, 0.99572754, 0.98443604, state);
float second = first_order_filter(first, 0.94790649, 0.83392334, state);
float third = first_order_filter(second, 0.53567505, 0.07568359, state);
out1 = third;

Where first_order_filter is defined as in Robert's answer here:

https://dsp.stackexchange.com/a/70963/11391

I would love to know if this code is approximately correct/ where the problem lies.

$\endgroup$
2
  • 2
    $\begingroup$ Each filter needs its own state. Try it first with a sine wave and make sure the output is a sine wave as well. $\endgroup$
    – Hilmar
    Oct 20, 2020 at 22:48
  • 1
    $\begingroup$ and you have to pass the function the pointer to a state using the "&" operator. $\endgroup$ Oct 20, 2020 at 23:04

1 Answer 1

2
$\begingroup$

My late night brain made foolish mistakes, for the record, if anyone needs this, the working code is as follows:

Header:

float state1;
float state2;
float state3;

Implementation:

In Constructor:

state1 = 0;
state2 = 0;
state3 = 0;

Robert's function:

// this processes one sample

float first_order_filter(float input, float pole, float zero, float *state)
{
    float new_state = input + pole*(*state);
    float output = new_state - zero*(*state);
    *state = new_state;
    return output;
}

Then in the loop, for (int i=0; i < numSamples; i++)

float first = first_order_filter(whiteNoise, 0.99572754, 0.98443604, &state1);
float second = first_order_filter(first, 0.94790649, 0.83392334, &state2);
float third = first_order_filter(second, 0.53567505, 0.07568359, &state3);
out1 = third;

Of course this works like a charm, producing Pink Noise and if the poles and zeros are swapped it produces Blue/ Azure Noise.

$\endgroup$
6
  • 2
    $\begingroup$ Glad you got it sorted. Remember that all Single precision floating point decimal numbers Should have an ‘F’ character appended, or the compiler will assume its a double. It won’t break your code but will slow it down a bunch, especially if you don’t have a 64bit FPU $\endgroup$
    – Dan Szabo
    Oct 21, 2020 at 8:58
  • $\begingroup$ @Dan Szabo Thanks Dan. Good advice. $\endgroup$ Oct 21, 2020 at 10:08
  • $\begingroup$ or you can change the float to double everywhere in the code. $\endgroup$ Oct 21, 2020 at 17:21
  • $\begingroup$ @robert bristow-johnson Out of interest, is there any difference, performance wise? $\endgroup$ Oct 21, 2020 at 17:37
  • $\begingroup$ normally you get the best performance when the word width (in bits) is the same as the width of the data bus of the machine you're using. in the olden days (and still today with some embedded processors), float was 32-bit and the same width of the data bus of the CPU. i presume if you have a 64-bit processor, you will get the best performance using double or real64. if using a 32-bit processor, you will get the fastest performance with float or real32. you could also do this in fixed-point, but you have to be more careful with scaling. $\endgroup$ Oct 21, 2020 at 19:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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