我的低通滤波器有啥问题?

Posted

技术标签:

【中文标题】我的低通滤波器有啥问题?【英文标题】:What is wrong with my low pass filter?我的低通滤波器有什么问题? 【发布时间】:2011-03-03 15:09:51 【问题描述】:

我有一系列 int 样本,范围从 32766 到 -32767。在尝试创建包络检测器的过程中,我编写了一个低通滤波器,但它似乎并没有起到作用。请记住,我正在尝试一次性过滤整个数组(无缓冲区)。

这不是流式传输的,而是应用于录制的音频以供以后播放。它是用 C 语言编写的。一个示例截止参数是 0.5。

void lopass(int *input, float cutoff, int *output) 


float sample = 0;

for (int i=1 ; i < (1430529-10); i++) // we will go through all except the last 10 samples 

    for (int j = i; j < (i+10); j++)  // only do this for a WINDOW of a hundred samples

        float _in = (float)input[j];
        float _out = (float)output[j-1];

         sample = (cutoff * _in) + (32766 - (32766*cutoff)) * _out;

    

    output[i] = (int)sample;



我想我会在 10 个样本的窗口上运行我的过滤语句。它不仅超级慢,而且它并没有真正做太多,但似乎降低了整体幅度。 \

如果您对如何正确执行此操作有任何建议或建议(或代码!),那就太好了!

【问题讨论】:

【参考方案1】:

低通滤波器基本上是将多个值平均在一起的某种变体。这意味着至少在正常情况下,您的内部循环将累积一个值。很难从你的代码中猜出确切的意图,但你最终会得到一些非常一般的东西:

sample = 0;
for (int j=i; j<i+10; j++)
    sample += input[j];
output[i] = sample / 10;

就目前而言,这个只是进行平均,没有指定截止 - 这意味着它有一个固定的(并且相当慢的)截止曲线。截止值由窗口中的样本数控制。

要控制截止,您不会(至少通常)将所有输入值乘以相同的数量——这基本上只会修改比例因子。相反,您获取要应用的截止曲线的一组样本(在您的情况下为 10 个),通过逆 FFT 运行它们,并获得一组 10 个系数。然后在循环中应用这些系数:

sample = 0;
for (j=0; j<10; j++)
   sample += input[i+j] * coefficients[j];
output[i] = sample;

您窗口中的样本数量通常不是设计过程的输入,而是输出。首先指定截止频率(作为采样频率的一部分)和截止宽度,然后根据这些值计算必要的窗口大小。

计算系数有很多不同的技术。然而,不管你如何计算它们,你通常会得到这个一般顺序的东西——在窗口中累积样本的总和,每个样本乘以其各自的系数。

几年前,EE 时代在滤波器设计方面有相当不错的article。

【讨论】:

【参考方案2】:

不知道它是否相关,但在您的代码中,内部循环什么都不做

for (j=???; j<???; j++) 
  sample = ???;

一样
// for (j=???; j<???; j++) 
  sample = ???; // for last j
// 

【讨论】:

【参考方案3】:

过滤器中的算术看起来是错误的,正如@pmg 已经指出的那样,您没有正确存储输出值。应该是:

void lopass(int *input, float cutoff, int *output) 

    float sample = 0.0f;

    output[0] = 0.0f;

    for (int i = 1 ; i < (1430529 - 10); i++)
    
        for (int j = i; j < (i + 10); j++)
         
            float _in = (float)input[j];
            float _out = (float)output[j-1];

            sample = (cutoff * _in) + (1.0f - cutoff) * _out;

            output[i] = (int)sample;
        
    

仍有一些小问题需要解决,但这至少应该可以作为一个相当粗糙的单极递归 (IIR) 滤波器。

【讨论】:

谢谢,我喜欢这篇文章。我再次写了一个小的改动,我用浮点数替换了整数输入和输出作为函数变量,因为它们被用作循环中的浮点数。然后我尝试了从 0 到 1 的截止值,但没有听到任何过滤效果,如果我在测试中将截止值设置为 -5 和 90,我只是听到了一些高端的添加。尽管如此,它让我意识到我将能够为我的程序设置一个过滤器,我非常高兴。【参考方案4】:

这是一个损坏的移动窗口过滤器,内部循环中有 10 个样本(实际上您只使用了 10 个样本中的最后一个样本),当您在 cmets 中说您希望矩形过滤器窗口中有 100 个样本时。

第一个错误会使您的过滤器转换频率高出 10 倍。

【讨论】:

以上是关于我的低通滤波器有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

具有 FFT 卷积的低通 FIR 滤波器 - 重叠相加,为啥以及如何

MATLAB 中的低通/带通滤波器设计

使用 Avaudioengine iOS 的低通滤波器 + 采样率转换

如何将 5Hz 的低通滤波器应用于 pandas 数据帧?

常规和自适应低通滤波器有啥区别?

Android 低通滤波器和高通滤波器