我试图仅使用整数并且不使用表来近似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;
}
也许我过于复杂了。
答案 0 :(得分:3)
请参阅Hakmem items 149 to 152,了解以渐进方式绘制圆的方法(当然,这给出了正弦),算法很少。
答案 1 :(得分:1)
注意到所有常量都声明为UL
,即无符号长,您可以尝试使用int64_t
代替int32_t
进行计算。 (只是一个猜测。)
答案 2 :(得分:0)
Steve Hollasch维护了一个关于使用sin/cos recurrence relations进行增量更新的页面。如果你坚持的话,我想你可以将它调整到16.16
固定点;但如果您只是想避免sinf
来电,则仍应使用float
。
我不清楚你的代码应该如何工作。乘法看起来很可疑 - 容易溢出;截断分区肯定会引入大错误,例如,
int32_t sample = (osc->position_acc / 4194304UL) * osc->phase;
如果:(position_acc % 4194304UL) == 4194304UL - 1
,请考虑引入的错误。您可以通过关联性来缓解这种情况 - 首先乘以,然后除以 - 但int32_t
会保持结果吗?也许你需要考虑int64_t
来获得中间结果。
这是为什么平台?