我正在尝试实施IIR过滤器。
我尝试实现以下过滤器,但
FIR : y(n) = b0(x[n]) + ... +bM-1(x[n-M+1])
IIR : y(n) = {b0(x[n]) + ... +bM-1(x[n-M+1])} - {a1(y[n-1]) + ... +aN(y[n-N}
我对如何实施y[n-1].....
感到困惑。
这是我的代码。
void IIRFloat(double *coeffs_B, double *coeffs_A, double *input, double *output, int length, int filterLength)
{
double bcc, acc;
double *coeffa, *coeffb;
double *inputp;
double *outputp;
int n,k;
//filter length =7
for (n = 0; n < length; n++) {
coeffa = coeffs_A;
coeffb = coeffs_B;
inputp = &insamp[filterLength - 1 + n]; //insamp[6]~insamp[85]
acc = 0;
bcc = 0;
for (k = 0; k < filterLength; k++) {
bcc += (*coeffb++) * (*inputp--); //b[0] * x[6] + b[1] * x[5]...+b[6] * x[0]
}
for (k = 1; k < filterLength; k++) {
acc += (*coeffa++) * (*output--); //a[1] * y[5] + a[2] * y[4]...+a[6] * y[0]
}
output[n] = bcc-acc;
}
}
我不会在这里复制memove
函数的代码以寻求简洁。
答案 0 :(得分:1)
IIR滤波器是递归的,这意味着它采用输出的过去值(相当于它可以表示为输入的无限序列)。
假设您有过滤器
y[n] = b*x[n]-a*y[n-1]
通常,第一个输出初始化为给定值,例如0。
假设您要过滤长度为N
的信号x,那么您应该执行以下操作:
double out[N]; //output vector
double a = 0.3, b=0.5; //assign the coefficients a value
out[0] = 0; //initialize the first element
for (int i=1; i<N; i++)
{
out[i] = b*x[i] -a*[i-1];
}
对于您的代码,我无法知道您在第inputp = &insamp[filterLength - 1 + n];
行中正在做什么,这可能是个问题。
我将假设inputp
是您要过滤的信号。
另一个问题:您使用过滤器filterLength
来指示输入元素和输出元素的长度:通常不在IIR过滤器中。
从0到filterlength
的输出元素应该以某种方式初始化,假设为0.然后在第二个循环中,你使循环索引从1开始,但系数数组应该从0开始。
(DOUBT:如果最旧的元素是y[5]
,那么长度如何为7?)
使用索引而不是取消引用数组,您的代码应该是这样的:
void IIRFloat(double *coeffs_B, double *coeffs_A, double *input, double *output, int length, int filterLength)
{
double bcc, acc;
double *inputp;
int n,k;
for (int ii=0; ii<filterLength; ii++)
{
output[ii] = 0;
}
//filter length =7
for (n = 0; n < length; n++) {
inputp = &insamp[filterLength - 1 + n]; //insamp[6]~insamp[85]
acc = 0;
bcc = 0;
for (k = 0; k < filterLength; k++)
{
bcc += coeffb[k] * inputp[filterLength-k-1]; //b[0] * x[6] + b[1] * x[5]...+b[6] * x[0]
}
for (k = 0; k < filterLength; k++)
{
acc += coeffa[k] * output[filterLength-k-1]; //a[1] * y[5] + a[2] * y[4]...+a[6] * y[0]
}
output[n] = bcc-acc;
}
}
修改强>
我认为长度相同的两个for
可以合并在一起:
for (k = 0; k < filterLength; k++)
{
output[n] += (coeffb[k] * inputp[filterLength-k-1] - coeffa[k] * output[filterLength-k-1]);
}
答案 1 :(得分:1)
如果你真的想用指针做这件事:
void filter1(const double *b, const double *a, size_t filterLength, const double *in, double *out, size_t length) {
const double a0 = a[0];
const double *a_end = &a[filterLength-1];
const double *out_start = out;
a++;
out--;
size_t m;
for (m = 0; m < length; m++) {
const double *b_macc = b;
const double *in_macc = in;
const double *a_macc = a;
const double *out_macc = out;
double b_acc = (*in_macc--) * (*b_macc++);
double a_acc = 0;
while (a_macc <= a_end && out_macc >= out_start) {
b_acc += (*in_macc--) * (*b_macc++);
a_acc += (*out_macc--) * (*a_macc++);
}
*++out = (b_acc - a_acc) / a0;
in++;
}
}
我将此算法的结果与MATLAB的过滤函数进行了比较。
注意:如果您对系数进行标准化(即a0 == 1
),则可以获得较大的性能提升。为此,您只需将a
和b
向量除以a0
,然后在每次迭代时不必将b_acc - a_acc
除以a0
答案 2 :(得分:0)
y[n-1]
只是上一个时间步骤ex的结果:output[n-1]
(y[n-N]
是从当前时间开始的第N个时间步长)。因此,您需要使用适当的output[n-k]
(?)量来索引输出数组(注意避免索引超出数组的开头,但是,您需要代码来防止这种情况)。
你也没有正确地索引你的coeffa / coeffb系数(我认为)。要获得您想要的结果,您可能需要执行此操作*(coeffa ++)以确保在取消引用之前递增指针。我会敦促你通过直接索引到数组coeff_A[k]
来做到这一点,但是,因为它更容易看到发生了什么。
最后一点注意:操作(* output--)正在以我认为无意的方式移动输出指针。索引到数组中。
答案 3 :(得分:0)
我只想回答 iir 过滤器,因为它比 fir 过滤器更容易实现,并且在许多情况下就足够了。最重要的是,你永远不想分别指定 A 和 B,因为 B 应该总是等于 (1-A)。因此,可以说基本 IIR 滤波器的实现是:
class IIR_Filter
{
IIR_Filter(double _alpha, double initialValue = 0)
{
alpha = _alpha;
lastVal = initialValue;
}
double processNextStep(double newVal)
{
lastVal = alpha * newVal + (1.0 - alpha) * lastVal;
return lastVal;
}
private:
double alpha;
double lastVal;
};