【问题标题】:FIR filter implementation in C programmingC 编程中的 FIR 滤波器实现
【发布时间】:2013-02-21 08:42:07
【问题描述】:

谁能告诉我如何使用 c 编程语言实现 FIR 滤波器。

【问题讨论】:

标签: c signal-processing


【解决方案1】:

设计一个 FIR 滤波器不是一个简单的话题,但是实现一个已经设计好的滤波器(假设你已经有了 FIR 系数)也不错。该算法称为convolution。这是一个幼稚的实现......

void convolve (double *p_coeffs, int p_coeffs_n,
               double *p_in, double *p_out, int n)
{
  int i, j, k;
  double tmp;

  for (k = 0; k < n; k++)  //  position in output
  {
    tmp = 0;

    for (i = 0; i < p_coeffs_n; i++)  //  position in coefficients array
    {
      j = k - i;  //  position in input

      if (j >= 0)  //  bounds check for input buffer
      {
        tmp += p_coeffs [i] * p_in [j];
      }
    }

    p_out [k] = tmp;
  }
}

基本上,卷积对输入信号进行移动加权平均。权重是滤波器系数,假设总和为 1.0。如果权重总和不是 1.0,则会得到一些放大/衰减以及滤波。

顺便说一句 - 这个函数有可能将系数数组向后 - 我没有仔细检查过,我已经有一段时间没有考虑这些事情了。

对于如何计算特定滤波器的 FIR 系数,这背后有相当多的数学知识 - 您确实需要一本关于数字信号处理的好书。 This one 可免费获得 PDF,但我不确定它有多好。我有RorabaughOrfandis,它们都在九十年代中期发布,但这些东西并没有真正过时。

【讨论】:

  • 是的,我已经有了滤波器系数。如果你有阻带和通带规格,它很容易生成。还有一个问题,您知道如何在级联中实现 FIR 滤波器。就像假设我有输入 x(n) 并且我想要一个输出 y(n) 所以我的整体传递函数将是一个由 3 个小 FIR 滤波器块组成的块,即 (H(z)=Y(z)*X(z) *A(z))。我真正的问题是如何将所有这三个过滤器级联合并在一起以获得输出 y(n)。给我一个粗略的想法或伪代码,或者如果你有代码,请粘贴它。
  • 您的选择基本上是 (1) 为整体传递函数设计单个滤波器,或 (2) 重复调用卷积函数,级联中的每个滤波器一次。据我所知,(1)结果也是卷积(对于每对过滤器的组合),但我必须回到我的教科书才能确定。
  • 您能否检查一下,因为我花了很多时间思考这个问题,但无法提出解决方案。如果你能帮我解决这个问题那就太好了:)
  • 不应该是p_out [k] = tmp;吗?
  • @Shailesh - 看起来你是对的 - 在应该有 i 的一行中还有一个 k。立即修复。
【解决方案2】:

组合多个过滤器:

以单位脉冲开始(第一个位置为 1,其他位置为 0 的信号)。应用第一个过滤器。应用第二个过滤器。继续,直到应用所有过滤器。结果显示了组合滤波器如何对单位脉冲进行卷积(假设数组足够长以至于没有数据丢失),因此其中的值是一个滤波器的系数,它是其他滤波器的组合。

这里是示例代码:

#include <stdio.h>
#include <string.h>


#define NumberOf(a) (sizeof (a) / sizeof *(a))


/*  Convolve Signal with Filter.

    Signal must contain OutputLength + FilterLength - 1 elements.  Conversely,
    if there are N elements in Signal, OutputLength may be at most
    N+1-FilterLength.
*/
static void convolve(
    float *Signal,
    float *Filter, size_t FilterLength,
    float *Output, size_t OutputLength)
{
    for (size_t i = 0; i < OutputLength; ++i)
    {
        double sum = 0;
        for (size_t j = 0; j < FilterLength; ++j)
            sum += Signal[i+j] * Filter[FilterLength - 1 - j];
        Output[i] = sum;
    }
}


int main(void)
{
    //  Define a length for buffers that is long enough for this demonstration.
    #define LongEnough  128


    //  Define some sample filters.
    float Filter0[] = { 1, 2, -1 };
    float Filter1[] = { 1, 5, 7, 5, 1 };

    size_t Filter0Length = NumberOf(Filter0);
    size_t Filter1Length = NumberOf(Filter1);


    //  Define a unit impulse positioned so it captures all of the filters.
    size_t UnitImpulsePosition = Filter0Length - 1 + Filter1Length - 1;
    float UnitImpulse[LongEnough];
    memset(UnitImpulse, 0, sizeof UnitImpulse);
    UnitImpulse[UnitImpulsePosition] = 1;


    //  Calculate a filter that is Filter0 and Filter1 combined.
    float CombinedFilter[LongEnough];

    //  Set N to number of inputs that must be used.
    size_t N = UnitImpulsePosition + 1 + Filter0Length - 1 + Filter1Length - 1;

    //  Subtract to find number of outputs of first convolution, then convolve.
    N -= Filter0Length - 1;
    convolve(UnitImpulse,    Filter0, Filter0Length, CombinedFilter, N);

    //  Subtract to find number of outputs of second convolution, then convolve.
    N -= Filter1Length - 1;
    convolve(CombinedFilter, Filter1, Filter1Length, CombinedFilter, N);

    //  Remember size of resulting filter.
    size_t CombinedFilterLength = N;

    //  Display filter.
    for (size_t i = 0; i < CombinedFilterLength; ++i)
        printf("CombinedFilter[%zu] = %g.\n", i, CombinedFilter[i]);


    //  Define two identical signals.
    float Buffer0[LongEnough];
    float Buffer1[LongEnough];
    for (size_t i = 0; i < LongEnough; ++i)
    {
        Buffer0[i] = i;
        Buffer1[i] = i;
    }


    //  Convolve Buffer0 by using the two filters separately.

    //  Start with buffer length.
    N = LongEnough;

    //  Subtract to find number of outputs of first convolution, then convolve.
    N -= Filter0Length - 1;
    convolve(Buffer0, Filter0, Filter0Length, Buffer0, N);

    //  Subtract to find number of outputs of second convolution, then convolve.
    N -= Filter1Length - 1;
    convolve(Buffer0, Filter1, Filter1Length, Buffer0, N);

    //  Remember the length of the result.
    size_t ResultLength = N;


    //  Convolve Buffer1 with the combined filter.
    convolve(Buffer1, CombinedFilter, CombinedFilterLength, Buffer1, ResultLength);


    //  Show the contents of Buffer0 and Buffer1, and their differences.
    for (size_t i = 0; i < ResultLength; ++i)
    {
        printf("Buffer0[%zu] = %g.  Buffer1[%zu] = %g.  Difference = %g.\n",
            i, Buffer0[i], i, Buffer1[i], Buffer0[i] - Buffer1[i]);
    }

    return 0;
}

【讨论】:

    【解决方案3】:

    我发现这段代码 sn-p 对我不起作用(Visual Studio 2005)。

    我最终发现卷积问题有一个很好的答案:

    1d linear convolution in ANSI C code?

    对于那些不知道的人 - 卷积与 FIR 滤波的操作完全相同 - “内核”是 FIR 滤波器脉冲响应,信号是输入信号。

    我希望这可以帮助一些正在寻找 FIR 代码的可怜的 sap :-)

    【讨论】:

    • 您可能想在此处提取其他问题的相关部分(以防其他问题被删除)。它还让您有机会指出您认为有用的部分:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    相关资源
    最近更新 更多