gpt4 book ai didi

c - C 中的定点 FIR 滤波器?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:51:30 28 4
gpt4 key购买 nike

FIR 滤波器有一个算法,但它是 float : FIR filter implementation in C programming

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

the FIR-filter receives and sends 8-bit fixed-point numbers in the Q7-format via the standard input and output. Remember to output the measured time (number of ticks) also in hex format. Following the guidelines presented in the previous section, your program should call getchar() to read a Q7-value. should call putchar() to write a Q7-value.

系数是

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

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

我应该像结构一样存储固定点数吗?

struct point
{
int integer;
int fraction;
};

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

数字是 32 位的,所以我可以像下面这样写移位吗?

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

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

更新

我在 anser 中编译并运行了一个程序,但它给了我意想不到的输出。

#include <stdio.h>
#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 << (FBITS) >> 1) /* Half adjust for rounding = (int)(0.5 * (1<<FBITS)) */
signed char input[4]; /* The 4 most recent input values */
int output = 0;

void firFixed()
{
signed char sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3];
output = (signed char)((sum + HALF) >> 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 <stdio.h>
#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 << (FBITS) >> 1) /* Half adjust for rounding = (int)(0.5 * (1<<FBITS)) */
signed char input[4]; /* The 4 most recent input values */

char get_q7( void );
void put_q7( char );

void firFixed()
{
int sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3];
signed char output = (signed char)((sum + HALF) >> 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 <sys/alt_stdio.h>

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 << 4;
num = num | (c & 0xf);
i = i + 1;
}
else if( (c >= 'A') && (c <= 'F') )
{
num = num << 4;
num = num | (c + 10 - 'A');
i = i + 1;
}
else if( (c >= 'a') && (c <= 'f') )
{
num = num << 4;
num = num | (c + 10 - 'a');
i = i + 1;
}
else if( c == 10 ) /* LF finishes line */
{
if( i > 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 < 0x20) )
{
/* Ignored - do nothing special */
}
else
{ /* Illegal hex-code */
for( i = 0; error1[i]; i += 1 )
alt_putchar( error1[i] );
alt_putchar( c );
for( i = 0; error2[i]; i += 1 )
alt_putchar( error2[i] );
alt_putchar( '\n' );
break; /* Ask for a new number */
}
if( ok )
{
if( i > 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 <sys/alt_stdio.h>

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 + 0x30);
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 的补码,那么简单地将接收到的字节描述为 (signed char) 将在以下情况下为其提供正确的数值提升为 int。如果您将系数预乘以 2 的幂,则加权和将乘以 2 的相同幂。然后,舍入除法只是简单地添加一个半调整值,然后是一个带符号的右移。对于 16 位小数,预乘常量为:

#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 */
#define HALF (1 << (FBITS) >> 1) /* Half adjust for rounding = (int)(0.5 * (1<<FBITS)) */

这种奇怪的原因是在不依赖任何浮点舍入的情况下获得您想要的有效位。现在,如果:

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<<FBITS。 .我测试了这些值并没有发生这种情况(你需要 c0*(1<<LBITS) 的小数部分恰好是 0.5;这意味着所有其他缩放系数也将 0.5 作为它们的小数部分。它们都是圆的向上,总和将太大 2。这可能会给您的过滤器增加一个非常小的意外增益。

您提供的系数不会发生这种情况。

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

关于c - C 中的定点 FIR 滤波器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19192358/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com