Значение рациональной передаточной функции, лежащей в основе фильтра MATLAB или фильтра Scipy.signal
У меня есть код MATLAB, который фильтрует входной сигнал, используя filter
:
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 и документацию по фильтру Python Scipy.signal, но в определении передаточной функции есть термин, который я не понимаю.
Вот определение "рациональной передаточной функции" из связанной документации:
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#, если есть эквивалентная опция, пожалуйста, просветите меня.
1 ответ
В More About
В разделе документации Matlab, как вы указали, они описывают:
Описание ввода-вывода операции фильтрации для вектора в области 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)
это z-domain
преобразование входного вектора x
(увидеть 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]
ОБНОВИТЬ
Если коэффициенты векторов a
а также b
иметь фиксированную длину 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;
}