0

我试图只使用整数而不使用表格来近似 sin 函数。

每个步骤都会调用该函数。我已经在matlab中成功地近似了它,但是我的C代码有问题。由于某种原因,我得到错误的频率读数,并且该功能不适用于所有频率。

typedef volatile struct tone_s{
    int32_t impulse;
    int32_t acceleration; 
    int32_t rollover;
    int32_t velocity;
    int32_t phase;
    int32_t counter; 
    int32_t position_acc; 
    int32_t velocity_acc; 
}tone_t; 

static void Osc_Init(tone_t *osc, uint32_t frequency, uint32_t sample_rate){
    int32_t max_int = (1UL << 16); 
    frequency *= 4UL; 

    osc->impulse = (max_int * frequency);
    osc->acceleration = max_int/sample_rate * frequency * frequency;
    osc->rollover = (sample_rate * 2UL / frequency);
    osc->velocity = osc->impulse - (osc->acceleration / 2UL);
    osc->velocity_acc = osc->velocity; 
    osc->phase = -1UL;
    osc->counter = 0; 
    osc->position_acc = 0; 

}

#include <stdio.h>

static int16_t Osc_GenSample(tone_t *osc){
    if(osc->counter == osc->rollover){
        osc->velocity_acc = osc->velocity;
        osc->position_acc = 0;
        osc->phase = -osc->phase;
        osc->counter = 0; 
    }

    int32_t sample = (osc->position_acc / 4194304UL) * osc->phase;

    osc->position_acc += osc->velocity_acc;  
    osc->velocity_acc -= osc->acceleration; 

    osc->counter++; 

    //fprintf(stdout, "%d - %d %d %d %d %d %d %d\n", sample, osc->impulse, osc->acceleration, osc->velocity, osc->rollover, osc->position_acc, osc->velocity_acc, osc->counter); 
    return sample; 
}

也许我把它复杂化了。

4

3 回答 3

3

请参阅Hakmem 项目 149 到 152以了解以很少的算术增量绘制圆(当然会给出正弦)的方法。

于 2013-06-19T21:52:26.190 回答
1

注意到你所有的常量都被声明为UL无符号长,你可以尝试使用int64_t而不是int32_t你的计算。(只是猜测。)

于 2013-06-19T21:21:03.613 回答
0

Steve Hollasch 维护了一个关于使用sin/cos 递归关系进行增量更新的页面。16.16如果您坚持,我想您可以将其调整为固定点;但如果你只是想避免sinf调用,你仍然应该使用float.

我不清楚您的代码应该如何工作。乘法看起来很可疑——容易溢出;截断除法肯定会引入很大的错误,例如,

int32_t sample = (osc->position_acc / 4194304UL) * osc->phase;

如果:(position_acc % 4194304UL) == 4194304UL - 1,考虑引入的错误。您可以通过关联性来缓解这种情况——先乘法,然后除法——但int32_t结果会保持不变吗?也许您需要考虑int64_t中间结果。

这是什么平台?

于 2013-06-19T22:35:48.613 回答