【问题标题】:Meaning of rational transfer function underlying MATLAB filter or Scipy.signal filterMATLAB 滤波器或 Scipy.signal 滤波器的有理传递函数的含义
【发布时间】:2018-11-03 19:28:28
【问题描述】:

我有一些使用filter 过滤输入信号的 MATLAB 代码:

CUTOFF = 0.05;
FS = 5000;
[b, a] = butter(1, CUTOFF / (FS / 2), 'high');
% b = [0.99996859, -0.99996859]
% a = [1.0, -0.99993717]
dataAfter = filter(b, a, dataBefore);

我正在尝试将此代码转换为 C#。我已经让butter 函数工作得很快,但现在我无法转换filter 函数。

我已阅读 MATLAB filter 文档和 Python Scipy.signal filter 文档,但传递函数定义中有一个我不理解的术语。

这是链接文档中的“有理传递函数”定义:

        b[0] + b[1]z^(-1)  + ... + b[M]z^(-M)
Y(z) = _______________________________________ X(z)
        a[0] + a[1]z^(-1)  + ... + a[N]z^(-N)

如果我错了,请纠正我,但z 是输入数据的当前元素,Y(z) 是输出?

如果上述情况属实,这个等式中的X(z) 是什么?

我想了解这一点以在 C# 中实现它,如果有等效的选项,请赐教。

【问题讨论】:

  • 我相信它可能是一个时间延迟功能,参考。 these Cal Tech notes,例子6.2和图6.8的描述。注意:我在这里没有专业知识,只在 Simulink 中使用过不需要X 函数的传递函数。
  • X是输入信号X(z)是X的z变换,z是单位移位算子。

标签: c# matlab filter signal-processing transfer-function


【解决方案1】:

正如您所指出的,在 matlab 文档的 More About 部分中,他们描述了:

在 Z 变换域中对向量进行滤波操作的输入-输出描述是一个有理传递函数。有理传递函数的形式为,

        b[0] + b[1]z^(-1)  + ... + b[M]z^(-M)
Y(z) = _______________________________________ X(z)
        a[0] + a[1]z^(-1)  + ... + a[N]z^(-N)

重新排列:

       Y(z)   b[0] + b[1]z^(-1)  + ... + b[M]z^(-M)
H(z) = ____ = _______________________________________
       X(z)   a[0] + a[1]z^(-1)  + ... + a[N]z^(-N)

因此,X(z) 是输入向量xz-domain 变换(参见Digital Filter)。值得一提的是,在文档中,他们也将传递函数的替代表示形式为difference equation

这更适合移植到代码中。 C# 中的一种可能实现是 (using this answer as reference)

public static double[] Filter(double[] b, double[] a, double[] x)
{
   // normalize if a[0] != 1.0. TODO: check if a[0] == 0
   if(a[0] != 1.0)
   {
       a = a.Select(el => el / a[0]).ToArray();
       b = b.Select(el => el / a[0]).ToArray();
   }

   double[] result = new double[x.Length];
   result[0] = b[0] * x[0];
   for (int i = 1; i < x.Length; i++)
   {
       result[i] = 0.0;
       int j = 0;
       if ((i < b.Length) && (j < x.Length))
       {
           result[i] += (b[i] * x[j]);
       }
       while(++j <= i)
       {
            int k = i - j;
            if ((k < b.Length) && (j < x.Length))
            {
                result[i] += b[k] * x[j];
            }
            if ((k < x.Length) && (j < a.Length))
            {
                result[i] -= a[j] * result[k];
            }
        }
    }
    return result;
}

驱动程序

static void Main(string[] args)
{
    double[] dataBefore = { 1, 2, 3, 4 };
    double[] b = { 0.99996859, -0.99996859 };
    double[] a = { 1.0, -0.99993717 };

    var dataAfter = Filter(b1, a, dataBefore);
}

输出

Matlab dataAfter = [0.99996859 1.999874351973491  2.999717289867956  3.999497407630634]
CSharp dataAfter = [0.99996859 1.9998743519734905 2.9997172898679563 3.999497407630634]

更新
如果系数向量ab的长度固定为2,则滤波函数可以简化为:

public static double[] Filter(double[] b, double[] a, double[] x)
{
    // normalize if a[0] != 1.0. TODO: check if a[0] == 0
    if (a[0] != 1.0)
    {
        a = a.Select(el => el / a[0]).ToArray();
        b = b.Select(el => el / a[0]).ToArray();
    }

    int length = x.Length;
    double z = 0.0;
    double[] y = new double[length];    // output filtered signal

    double b0 = b[0];
    double b1 = b[1];
    double a1 = a[1];
    for (int i = 0; i < length; i++)
    {
        y[i] = b0 * x[i] + z;
        z = b1 * x[i] - a1 * y[i];
    }
    return y;
}

【讨论】:

  • 感谢您的回答和实施!但它非常非常慢。我们正在谈论几分钟(ish)。
  • 我的输入数据 (x) 的大小是 240001,所以嵌套的 while 循环正在扼杀性能。
  • @Bjqn 的大小是ba 固定的吗?
  • 是的 b 和 a 的长度总是 2
  • @Bjqn 当系数向量都具有固定长度2 时,我已在我的答案中添加了一个优化版本。如果这种方法不能解决问题,您可能需要尝试其他方法,请参阅this answer
猜你喜欢
  • 2016-07-30
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多