C中的定点FIR滤波器?

有一种FIR滤波器的算法,但它的浮点: C编程中的FIR滤波器实现

如果我想要一个具有此规范的定点算法,我该怎么做?

FIR滤波器通过标准输入和输出接收和发送Q7格式的8位定点数。 请记住以hex格式输出测量时间(滴答数)。 按照上一节中介绍的指导原则,您的程序应该调用getchar()来读取Q7值。 应该调用putchar()来写一个Q7值。

系数是

c0 = 0.0299c1 = 0.4701c2 = 0.4701c3 = 0.299

对于定点算法,我需要为固定点数实现自己的乘法,对吗?

我应该存储像结构一样的fixepdpoint数字

struct point { int integer; int fraction; }; 

我应该使用轮class来实现编号,具体如何?

这个数字是32位,所以我可以写下面的变化吗?

 #define SHIFT_AMOUNT 16 // 2^16 = 65536 #define SHIFT_MASK ((1 << SHIFT_AMOUNT) - 1) 

所以我认为我必须实现一个乘法算法,然后是FIR算法本身? 那是对的吗? 你能帮助我吗?

更新

我编译并运行了类似于anser的程序,但它给了我意想不到的输出。

 #include  #include "system.h" #define FBITS 16 /* number of fraction bits */ const int c0 = (( 299<<FBITS) + 5000) / 10000; /* (int)(0.0299*(1<<FBITS) + 0.5) */ const int c1 = ((4701<<FBITS) + 5000) / 10000; /* (int)(0.4701*(1<<FBITS) + 0.5) */ /* Ditto for C3 and C2 */ const int c2 = (( 4701<<FBITS) + 5000) / 10000; /* (int)(0.4701 *(1<<FBITS) + 0.5) */ const int c3 = ((299<<FBITS) + 5000) / 10000; /* (int)(0.299*(1<<FBITS) + 0.5) */ #define HALF (1 <> 1) /* Half adjust for rounding = (int)(0.5 * (1<> FBITS); printf("output: %d\n", output); } int main( void ) { int i=0; signed char inVal; while (scanf("%c", &inVal) > 0) { if (i>3) { i=0; } input[i]=inVal; firFixed(); i++; } return 0; } 

为什么输出没有正确计算,为什么在一次输入后多次写入输出?

更新

我尝试编写定点FIR滤波器,算法可能不是100%正确:

  #include  #include "system.h" #define FBITS 16 /* number of fraction bits */ const int c0 = (( 299<<FBITS) + 5000) / 10000; /* (int)(0.0299*(1<<FBITS) + 0.5) */ const int c1 = ((4701<<FBITS) + 5000) / 10000; /* (int)(0.4701*(1<<FBITS) + 0.5) */ /* Ditto for C3 and C2 */ const int c2 = (( 4701<<FBITS) + 5000) / 10000; /* (int)(0.4701 *(1<<FBITS) + 0.5) */ const int c3 = ((299<<FBITS) + 5000) / 10000; /* (int)(0.299*(1<<FBITS) + 0.5) */ #define HALF (1 <> 1) /* Half adjust for rounding = (int)(0.5 * (1<> FBITS); put_q7(output); } int main( void ) { int i=0; while(1) { if (i>3) { i=0; } input[i]=get_q7(); firFixed(); i++; } return 0; } #include  char get_q7( void ); char prompt[] = "Enter Q7 (in hex-code): "; char error1[] = "Illegal hex-code - character "; char error2[] = " is not allowed"; char error3[] = "Number too big"; char error4[] = "Line too long"; char error5[] = "Line too short"; char get_q7( void ) { int c; /* Current character */ int i; /* Loop counter */ int num; int ok = 0; /* Flag: 1 means input is accepted */ while( ok == 0 ) { num = 0; for( i = 0; prompt[i]; i += 1 ) alt_putchar( prompt[i] ); i = 0; /* Number of accepted characters */ while( ok == 0 ) { c = alt_getchar(); if( c == (char)26/*EOF*/ ) return( -1 ); if( (c >= '0') && (c <= '9') ) { num = num <= 'A') && (c <= 'F') ) { num = num <= 'a') && (c <= 'f') ) { num = num < 0 ) ok = 1; else { /* Line too short */ for( i = 0; error5[i]; i += 1 ) alt_putchar( error5[i] ); alt_putchar( '\n' ); break; /* Ask for a new number */ } } else if( (c & 0x20) == 'X' || (c  10 ) { alt_putchar( '\n' ); for( i = 0; error4[i]; i += 1 ) alt_putchar( error4[i] ); alt_putchar( '\n' ); ok = 0; break; /* Ask for a new number */ } if( num >= 0 && num <= 255 ) return( num ); for( i = 0; error3[i]; i += 1 ) alt_putchar( error3[i] ); alt_putchar( '\n' ); ok = 0; break; /* Ask for a new number */ } } } return( 0 ); /* Dead code, or the compiler complains */ } #include  void put_q7( char ); /* prototype */ char prom[] = "Calculated FIR-value in Q7 (in hex-code): 0x"; char hexasc (char in) /* help function */ { in = in & 0xf; if (in  9 ) return (in - 0x0A + 0x41); return (-1); } void put_q7( char inval) { int i; /* Loop counter */ for( i = 0; prom[i]; i += 1 ) alt_putchar( prom[i] ); alt_putchar (hexasc ((inval & 0xF0) >> 4)); alt_putchar (hexasc (inval & 0x0F)); alt_putchar ('\n'); } 

FIR滤波器结果中的每个点只是来自未滤波数据的值的加权和。 如果你有8位输入数据和32位算术,你不需要除了简单乘法和加法之外的任何东西。

快速访问维基百科告诉我,Q7本质上是一个8位2的补码整数,所以如果目标平台使用2的补码,那么简单地描述接收的字节为(带符号的字符)将在提升为一个时给出正确的数值。 INT。 如果你将系数乘以2的幂,则加权和将乘以2的相同幂。然后,舍入除法只是添加一个半调整值,然后是一个有符号的右移。 对于16位分数,预乘常数是:

 #define FBITS 16 /* number of fraction bits */ const int C0 = (( 299<> 1) /* Half adjust for rounding = (int)(0.5 * (1< 

这种奇怪的原因是它可以获得你想要的重要位而不依赖于任何浮点舍入。 现在,如果:

 signed char input[4]; 

...包含4个最新的输入值,您的输出值为:

 sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3]; output = (signed char)((sum + HALF) >> FBITS); 

由于所有系数均为正且总和为1.0,因此不存在溢出的可能性。

在简单版本工作后,您可以尝试许多优化。 具有其他系数的一个可能的小故障是针对C0-C3常数的舍入以产生不完全相加到1< 。 我测试了这些值并没有发生(你需要c0*(1<才能得到精确到0.5的小数部分;这意味着所有其他缩放系数也会有0.5作为它们的小数部分。它们全部向上并且总和将太大2.这可能会为您的filter增加非常小的意外增益。

您给出的系数不会发生这种情况。

编辑:我忘了。 在求和计算期间,整数部分和小数部分都在相同的32位int中。 使用8位输入(7 +符号)和16位分数,在滤波器中最多可以有2 ^(32 - 16 - 8)= 2 ^ 8 = 256个点(此时,您显然会有一个系数数组和乘加加循环计算总和。如果(输入大小)+(分数位)+ log2(filter大小)超过32,那么你可以尝试将sum字段扩展为长C99或int64_t值,如果可用,或写入扩展精度添加和移位逻辑,如果没有。硬件的扩展精度要好得多,如果可用的话。