【问题标题】:IIR Filter Implementation in CC 中的 IIR 滤波器实现
【发布时间】:2014-05-11 01:00:34
【问题描述】:

我正在尝试在 C 中为 FRDMKL25Z 板实现 IIR 滤波器。我当前的代码如下所示:

#include "Cpu.h"
#include "Events.h"
#include "ADC_1.h"
#include "AdcLdd1.h"
#include "DAC_1.h"
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IO_Map.h"


#define NSP 16
static uint16_t DACvalue, ADCvalue;
static LDD_TError Error;
static LDD_TDeviceData *MyDacPtr;
int N=10; // Filter order
double NumCoeff[11]={0.8017, -8.0174, 36.0785, -96.2094, 168.3664, -202.0397, 
                    168.3664, -96.2094, 36.0785, -8.0174, 0.8017};

double DenomCoeff[11]={1.0000, -9.5582, 41.1210, -104.8588, 175.5143, -201.4924,
                    160.6706 , -87.8720, 31.5447, -6.7119, 0.6428};

double Signal[NSP], FilteredSignal[NSP];


int main(void)
{
  /* Write your local variable definition here */
  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
    int j, k;
    double y, Reg[NSP];
    PE_low_level_init();
    MyDacPtr = DAC_1_Init(NULL);

    for(j=0; j<NSP; j++) Reg[j] = 0.0; // Init the delay registers
    for(;;){
      for(j=0;j<NSP;j++)
     {  
      for(k=N; k>0; k--) Reg[k] = Reg[k-1];  // Shift the delay register values.

      (void)ADC_1_Measure(TRUE);                /* do conversion and wait for the result */
      (void)ADC_1_GetValue16(&ADCvalue);            /* get the result into value variable */
      Signal[j]=(ADCvalue/65535)*3.5;               /*Convert to volts*/
      Reg[0] = Signal[j];    // The denominator

      for(k=1; k<=N; k++)  Reg[0] -= DenomCoeff[k] * Reg[k];

      y = 0;            // The numerator
      for(k=0; k<=N; k++)y += NumCoeff[k] * Reg[k];
      FilteredSignal[j] = y;

      DACvalue=(FilteredSignal[j]*65535)*3.5; //Convert back to 16 bit 
      Error = DAC_1_SetValue(MyDacPtr, DACvalue);               /* Set DA converter output */
     }
  }

部分代码细节:

  • 我正在使用飞思卡尔的 Processor Expert (PE) 对嵌入式板进行编程;
  • 使用 MATLAB 生成的 IIR 滤波器系数;
  • 由于设备需要实时过滤数据,我从

ADC 过滤后直接输出到 DAC;

一旦闪存到板上,我就无法从 DAC 端口获得任何输出。

我对所有建议和调试方法持开放态度。

【问题讨论】:

  • (ADCvalue/65535)
  • 实际上为什么要这样做呢?根本不需要在电压之间进行线性缩放,只需保持原样
  • 它看起来你的过滤器也没有通过 DC(不仅仅是 DC 的 0dB,而是 -infinity [实际上就像 -40])。但是您输入了一个无符号值,这意味着您正在处理的信号可能具有您正在接收的大直流分量。更糟糕的是,即使过滤后的信号几乎肯定会具有负值,您也会输出另一个无符号信号。那里出了点问题,但我没有足够的信息来找出正确的做法是
  • 你用整数除以 16 位值除以 65536。正如史蒂夫注意到的那样,结果为零。
  • 在 48MHz Cortex-M0 上使用双精度浮点将是处理器密集型的。您应该使用定点算法,最好使用 16 位或 32 位。即使使用单精度也会让您获得更好的性能,而保真度可能不会有明显损失。您还可以通过使用 DMA 捕获样本块并处理整个块而不是按样本处理来提高性能。

标签: c embedded digital-filter


【解决方案1】:

这就是你做错了什么

  • 您还需要跟踪以前的输出
    • 也许您正在尝试,但有趣的嵌套循环不起作用
  • 分母应用于输出,而不是输入
    • 应用系数时,分母并不是真正的分母;之所以这么称呼,是因为频率响应就像一个分母。分母系数与输出的历史相乘,然后从输出中减去它们的总和。 (考虑将所有 y(n-1)... y(n-k) 项移动到等号的另一侧,只在一侧留下过滤器输出)
    • 有趣的分母系数是第一个,它乘以您实际尝试计算的新输出!您将整个结果除以该结果,以找出新的输出。 (在大多数 IIR 过滤器中,这是 1.0,因此您可以跳过它)。
  • 16 位整数除以 65535 为零!无需转换为伏特(正如其他人提到的)。
    • 只在最后只做工程,并且只在你需要的时候;你没有

这是我的建议,同时尝试保持相同的代码结构...

unsigned int ADCvalue, 
int Reg[NSP]; // use signed values instead of unsigned, and no need for double for history of ADCvalue

for(j=0; j<NSP; j++) Reg[j] = 0; // Init the delayed input registers
for(j=0; j<NSP; j++) FilteredSignal[j] = 0.0; // Init the delayed output registers

for(;;)
{  
     for(k=N; k>0; k--) Reg[k] = Reg[k-1];  // Shift the delay register values.
     for(k=N; k>0; k--) FilteredSignal[k] = FilteredSignal[k-1];

     (void)ADC_1_Measure(TRUE);                /* do conversion and wait for the result */
     (void)ADC_1_GetValue16(&ADCvalue);            /* get the result into value variable */

     Reg[0] = ADCvalue - 0x8000;    // Save the previous inputs samples (and shift the zero value to 0)

     y = 0;
     for(k=0; k<=N; k++) y += NumCoeff[k] * Reg[k];               // The numerator
     for(k=1; k<=N; k++) y -= DenomCoeff[k] * FilteredSignal[k];  // The denominator

     FilteredSignal[0] = y/DenomCoeff[0];

     DACvalue= FilteredSignal[0] + 0x8000;   // shift the zero value back to unsigned, centered at 0x8000
     Error = DAC_1_SetValue(MyDacPtr, DACvalue);               /* Set DA converter output */
}

【讨论】:

  • 我没有测试这个。让我知道它是否不起作用并且需要更改符号或调整索引。 (即,N 的分子和分母并不总是相同的值......)
  • 嗨,迈克尔,感谢您的回答;我已经尝试了您的代码,但不幸的是它仍然无法正常工作 - 我从 DAC 获得静态而不是我正在寻找的正弦波。我一直在按照这段代码制作我自己的上面显示的代码,也许你想看看:iowahills.com/Example%20Code/IIRNthOrderImplementation.txt我会继续尝试新事物,我会让你知道什么是有效的。再次感谢,-尼克。
  • 这两行似乎有问题:FilteredSignal[0] = y/DenomCoeff[0]; DAC值=过滤信号[0];如果我删除第一行并将第二行替换为 DACvalue=y;我得到一系列方波。 - 尼克。
  • 刚起床,去看看。顺便说一句,adc 输出是有符号还是无符号?
  • 方波可能是由于不正确的整数换行,我将 ADC 更改为有符号值(如果 ADC 上的零输入给出 0x0000 或 0x8000,请告诉我)。输出历史也没有初始化;编辑它。
【解决方案2】:

C 中的二阶 IIR 滤波器实现:

 static double b[] = {1,  -1.4, 1};
 static double a[] = {1, -1.3, 0.5};
 static double v1m1 = 0, v2m1 = 0, v1m, v2m;

 static double iirfilter(double x1) {
    double y1 = 0;
    y1 = (b[0] * x1 + v1m1) / a[0];
    v1m = (b[1] * x1 + v2m1) - a[1] * y1;
    v2m = b[2] * x1 - a[2] * y1;
    v1m1 = v1m;
    v2m1 = v2m;
    return y1;
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 2016-03-22
    • 2014-04-26
    • 1970-01-01
    相关资源
    最近更新 更多