当MCU平台资源非常紧张且只有整数运算指令时,可以通过查表近似运算来快速得到正余弦等各种三角操作。为规避浮点操作,可通过0~90度角度放大得到一个整数输入区间,相应结果也适当放大便于工程计算和精度取舍。具体实现如下。
实现框架:
1)整数对齐:
计算角度0.00~90.00度区间放大100倍取整到0~9000整数,以便于整数处理。
三角相应结果放大1000倍。
比如sin(30),实际输入时30对应3000(放大100倍),结果0.5对应500(放大1000倍)。
2)定义并实现一个通用正整数区间查表函数:
输入变量mvalue: 要计算的数值,比如30度输入3000
输入变量num: 表数组大小
输入变量value: 表参数数组,取值范围0~9000对应0~90度
输入变量data: 表结果数组,取值范围0~10000对应0~1.000
函数返回:根据value/data数组查找后,找到于md最接近的data对应的value数值,差值部分按照临近节点线性计算得到近似值,数组越多微分区间越小精度越高。
3)定义正弦函数的data/value表数组
常量数组angle:若干角度(放大100倍)
常量数组sin_data:各角度对应结果(放大1000倍)
4)定义正弦函数:
输入变量angle: 要计算的数角度值,比如30度输入3000
函数返回:根据相应常量数组利用以上查表函数返回对应的结果
5)定义余弦函数:
输入变量angle: 要计算的数角度值,比如30度输入3000
函数返回:利用cos(a)=sin(90-a)得到
代码实现:
uint16_t calc(uint16_t mvalue, uint16_t num, const uint16_t *value, const uint16_t *data) {
uint16_t i;
uint32_t data_calc;
if( mvalue <= value[0] )
data_calc = data[0];
else if( mvalue>= value[num-1] )
data_calc = data[num-1];
else {
for( i = 1; i < num-1; i++ ) {
if( mvalue<= value[i] )
break;
}
if( value[i] == value[i-1] )
data_calc = value[i];
else {
data_calc = data[i] - data[i-1];
data_calc *= mvalue - value[i-1];
data_calc /= value[i] - value[i-1];
data_calc += data[i-1];
}
}
return data_calc;
}
const uint16_t sin_data[] = {
0, 87, 174, 259,
342, 423, 500, 574,
643, 707, 766, 819,
866, 906, 940, 966,
985, 996, 1000
};
const uint16_t angle[] = {
0, 500, 1000, 1500,
2000, 2500, 3000, 3500,
4000, 4500, 5000, 5500,
6000, 6500, 7000, 7500,
8000, 8500, 9000,
};
uint16_t my_sin( uint16_t angle ) {
return calc(angle, sizeof(angle)/sizeof(angle[0]), angle, sin_data);
}
uint16_t my_cos( uint16_t angle ) {
return my_sin(9000-angle);
}
测试结果以及误差(括号里是实际SIN/COS数值,以及当前查表近似方法与实际数值的计算误差):
sin( 0)=0.000 (0.000000, 0.000000) cos( 0)=1.000 (1.000000, 0.000000)
sin( 1)=0.017 (0.017452, -0.000452) cos( 1)=0.999 (0.999848, -0.000848)
sin( 2)=0.034 (0.034899, -0.000899) cos( 2)=0.998 (0.999391, -0.001391)
sin( 3)=0.052 (0.052336, -0.000336) cos( 3)=0.997 (0.998630, -0.001630)
sin( 4)=0.069 (0.069756, -0.000756) cos( 4)=0.996 (0.997564, -0.001564)
sin( 5)=0.087 (0.087156, -0.000156) cos( 5)=0.996 (0.996195, -0.000195)
sin( 6)=0.104 (0.104528, -0.000528