Matlab过滤器实现

时间:2011-12-12 13:11:37

标签: matlab signal-processing

我读到Matlab滤波器命令用于求解差分方程。 filter()内部是使用z-Transform还是仅使用递归,即使用起始值x(0),y(0),它只是在时间上向前运行差分方程?对不起,如果这个问题没有意义,我是这个领域的新手。

谢谢,

3 个答案:

答案 0 :(得分:3)

滤波器实现可能是频域技术的一些巧妙使用,但是根据MATLAB文档,它 在数学上等同于求解差分方程:

 Y = FILTER(B,A,X) filters the data in vector X with the
    filter described by vectors A and B to create the filtered
    data Y.  The filter is a "Direct Form II Transposed"
    implementation of the standard difference equation:

    a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... + b(nb+1)*x(n-nb)
                          - a(2)*y(n-1) - ... - a(na+1)*y(n-na)

初始条件被选为全零,因为我们假设在开始过滤之前根本没有信号(全零)。如果您想指定这些初始条件,filter命令允许您指定初始(Zi)和最终(Zf)条件的向量:[Y,Zf] = FILTER(B,A,X,Zi)

答案 1 :(得分:2)

MatLab filter()函数实现了iir滤波器(递归滤波器),即它解决了差分方程。频域中的实现将具有高得多的成本。时域为O(N),频域理想情况下为log(N),如果使用FFT,则为O(N²)。

答案 2 :(得分:1)

以下是我在一段时间以前在C ++中实现MATLAB内置filter功能的方法,如果有人需要的话。在Zi中,您传递初始条件并在需要时收集最终条件。

#include <vector>
#include <exception>
#include <algorithm>

typedef vector<double> vectord;

void filter(vectord B, vectord A, const vectord &X, vectord &Y, vectord &Zi)
{
    if (A.empty())
        throw std::domain_error("The feedback filter coefficients are empty.");
    if (std::all_of(A.begin(), A.end(), [](double coef){ return coef == 0; }))
        throw std::domain_error("At least one of the feedback filter coefficients has to be non-zero.");
    if (A[0] == 0)
        throw std::domain_error("First feedback coefficient has to be non-zero.");

    // Normalize feedback coefficients if a[0] != 1;
    auto a0 = A[0];
    if (a0 != 1.0)
    {       
        std::transform(A.begin(), A.end(), A.begin(), [a0](double v) { return v / a0; });
        std::transform(B.begin(), B.end(), B.begin(), [a0](double v) { return v / a0; });
    }

    size_t input_size = X.size();
    size_t filter_order = std::max(A.size(), B.size());
    B.resize(filter_order, 0);
    A.resize(filter_order, 0);  
    Zi.resize(filter_order, 0);
    Y.resize(input_size);

    for (size_t i = 0; i < input_size; ++i)
    {
        size_t order = filter_order - 1;
        while (order)
        {
            if (i >= order)
                Zi[order - 1] = B[order] * X[i - order] - A[order] * Y[i - order] + Zi[order];
            --order;
        }
        Y[i] = B[0] * X[i] + Zi[0];
    }
    Zi.resize(filter_order - 1);
}

可以使用以下代码进行测试:

TEST_METHOD(TestFilter)
{
    vectord b_coeff = { /* Initialise your feedforward coefficients here */ };
    vectord a_coeff = { /* Initialise your feedback coefficients here */ };

    vectord input_signal = { /* Some input data to be filtered */ };
    vectord y_filter_ori = { /* MATLAB output from calling y_filter_ori = filter(b_coeff, a_coeff, input_signal); */ };

    vectord y_filter_out; vectord zi = { 0 };  // Set empty initial conditions
    filter(b_coeff, a_coeff, input_signal, y_filter_out, zi);
    Assert::IsTrue(compare(y_filter_out, y_filter_ori, 0.0001));
}

bool compare(const vectord &original, const vectord &expected, double tolerance = DBL_EPSILON)
{
    if (original.size() != expected.size())
        return false;
    size_t size = original.size();

    for (size_t i = 0; i < size; ++i)
    {
        auto diff = abs(original[i] - expected[i]);
        if (diff >= tolerance)
            return false;
    }
    return true;
}