首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >固定点FIR滤波器在C?

问固定点FIR滤波器在C?
EN

Stack Overflow用户
提问于 2013-10-04 23:40:53
回答 1查看 3K关注 0票数 2

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

如果我想要一个带有这个规范的不动点算法,我会怎么做呢?

FIR滤波器通过标准输入和输出接收并发送Q7格式的8位定点数字。记住,也要以十六进制格式输出测量的时间(蜱数)。按照上一节的指导方针,您的程序应该调用getchar()来读取Q7-值。应该调用putchar()来编写Q7-值。

系数是

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

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

我应该像存储结构那样存储不动点数字吗?

代码语言:javascript
复制
struct point
{
    int integer;
    int fraction;
};

我是否应该使用轮班来实现编号,特别是如何实现?

号码是32位,所以我能写如下的轮班吗?

代码语言:javascript
复制
#define SHIFT_AMOUNT 16 // 2^16 = 65536
#define SHIFT_MASK ((1 << SHIFT_AMOUNT) - 1)

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

更新

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

代码语言:javascript
复制
#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 %正确:

代码语言:javascript
复制
    #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');     
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-05 00:39:34

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

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

代码语言:javascript
复制
#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)) */

这种奇怪之处的原因在于,它可以在不依赖任何浮点四舍五入的情况下获得所需的重要位数。现在,如果:

代码语言:javascript
复制
signed char input[4];

...contain最近的4个输入值,您的输出值是:

代码语言:javascript
复制
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+sign)和16位分数,滤波器中最多可以有2^(32-16-8)= 2^8 =256个点(此时,显然有一个系数数组和一个乘法加循环来计算和。如果(输入大小)+(分数位)+log2(筛选器大小)超过32,则可以尝试将sum字段扩展到C99 long或int64_t值(如果可用的话),或者编写扩展精度添加和移位逻辑(如果没有)。硬件上的扩展精度在可用的情况下要好得多。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19192358

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档