0
$\begingroup$

I am having issues with my implementation of a FIR high pass filter. The low pass filter has an acceptable level of attenuation in the stopband, but the high pass filter has poor attenuation in the stopband. I have not seen any mention of this occurring in the sources that I read and I am unsure why this is occurring.

I am referencing The Scientist and Engineer's Guide to Digital Signal Processing (Page 271 regarding LPF to HPF). I am using white noise to test the frequency response of the filters, and the attached image is from an external program. Here is the relevant part of my code (just audio boilerplate has been removed):

    constexpr int rate = 44100;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<float> distrib(-1.0f, 1.0f);

    constexpr int buf_len = rate * 3;
    float* in = new float[buf_len];
    float* out = new float[buf_len]();
    
    constexpr int M = 200;
    float fc = 2100.0f / rate;
    double h[M + 1]{0.0f};

    for (int i = 0; i < buf_len; i++)
    {
        in[i] = distrib(gen);
    }   

    for (int i = 0; i <= M; i++) 
    {
        if ((i - M/2) == 0) 
        {
            h[i] = 2*M_PI*fc;
        }
        else 
        {
            h[i] = std::sin(2.0*M_PI*fc*(i - M/2)) / (i - M/2);
        }
        h[i] *= 0.42 - 0.5 * std::cos((2.0*M_PI*i)/M) + 0.08 * std::cos((4.0*M_PI*i)/M);
    }

    double sum = 0;
    for (int i = 0; i <= M; i++)
    {
        sum += h[i];
    }
    for (int i = 0; i <= M; i++)
    {
        h[i] /= sum;
    }

    //change to high pass
    for (int i = 0; i <= M; i++)
    {
        h[i] *= -1.0;
    }
    h[M/2] += 1.0f;

    // Convolve 
    for (int i = M; i < buf_len; i++) 
    {
        for (int j = 0; j <= M; j++) 
        {
            out[i] += in[i - j] * h[j];
        }
    }

frequency responses of the filters

$\endgroup$
3
  • $\begingroup$ Your filter coefficients are fine. I'm assume that the problem is downstream. How do you get the signal out and how do you do the spectral analysis ? $\endgroup$
    – Hilmar
    Mar 21, 2023 at 1:19
  • $\begingroup$ I output the signal using alsa(linux sound library) and then I analyze the spectrum using an external program called Friture and I also used Audacity. Here is a link to the full code if that is helpful: Pastebin $\endgroup$ Mar 21, 2023 at 1:35
  • $\begingroup$ Then I'm guessing that either something is wrong with your sound card or you are clipping. The peak time domain gain of the highpass is about 2.48 and significantly higher than the lowpass (1.67). Divide the output by 2.5 and see if that helps. $\endgroup$
    – Hilmar
    Mar 21, 2023 at 1:56

1 Answer 1

1
$\begingroup$

It's clipping. Divide the output by 2 and you'll be fine.

The theoretical maximum amplitude gain for the lowpass is 1.67 but it's 2.48 for the highpass, the highpass is more likely to clip.

The input signal is uniformly distributed on $[-1,+1]$ and has a very low Crest factor. Any type of filtering will make the distribution more Gaussian like (according to the central limit theorem), i.e. it will increase the Crest factor until it reaches 4-5.

That's less of a problem for the lowpass output since filter removes about 90% of the (white) spectrum and hence the RMS is quite low. The high pass filter just removes 10% of the spectrum and so even a slight increase in Crest factor will result in clipping.

$\endgroup$

Your Answer

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

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