当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) cos( 6)=0.993 (0.994522, -0.001522)
sin( 7)=0.121 (0.121869, -0.000869) cos( 7)=0.991 (0.992546, -0.001546)
sin( 8)=0.139 (0.139173, -0.000173) cos( 8)=0.989 (0.990268, -0.001268)
sin( 9)=0.156 (0.156434, -0.000434) cos( 9)=0.987 (0.987688, -0.000688)
sin(10)=0.174 (0.173648, 0.000352) cos(10)=0.985 (0.984808, 0.000192)
sin(11)=0.191 (0.190809, 0.000191) cos(11)=0.981 (0.981627, -0.000627)
sin(12)=0.208 (0.207912, 0.000088) cos(12)=0.977 (0.978148, -0.001148)
sin(13)=0.225 (0.224951, 0.000049) cos(13)=0.973 (0.974370, -0.001370)
sin(14)=0.242 (0.241922, 0.000078) cos(14)=0.969 (0.970296, -0.001296)
sin(15)=0.259 (0.258819, 0.000181) cos(15)=0.966 (0.965926, 0.000074)
sin(16)=0.275 (0.275637, -0.000637) cos(16)=0.960 (0.961262, -0.001262)
sin(17)=0.292 (0.292372, -0.000372) cos(17)=0.955 (0.956305, -0.001305)
sin(18)=0.308 (0.309017, -0.001017) cos(18)=0.950 (0.951057, -0.001057)
sin(19)=0.325 (0.325568, -0.000568) cos(19)=0.945 (0.945519, -0.000519)
sin(20)=0.342 (0.342020, -0.000020) cos(20)=0.940 (0.939693, 0.000307)
sin(21)=0.358 (0.358368, -0.000368) cos(21)=0.933 (0.933580, -0.000580)
sin(22)=0.374 (0.374607, -0.000607) cos(22)=0.926 (0.927184, -0.001184)
sin(23)=0.390 (0.390731, -0.000731) cos(23)=0.919 (0.920505, -0.001505)
sin(24)=0.406 (0.406737, -0.000737) cos(24)=0.912 (0.913545, -0.001545)
sin(25)=0.423 (0.422618, 0.000382) cos(25)=0.906 (0.906308, -0.000308)
sin(26)=0.438 (0.438371, -0.000371) cos(26)=0.898 (0.898794, -0.000794)
sin(27)=0.453 (0.453990, -0.000990) cos(27)=0.890 (0.891007, -0.001007)
sin(28)=0.469 (0.469472, -0.000472) cos(28)=0.882 (0.882948, -0.000948)
sin(29)=0.484 (0.484810, -0.000810) cos(29)=0.874 (0.874620, -0.000620)
sin(30)=0.500 (0.500000, 0.000000) cos(30)=0.866 (0.866025, -0.000025)
sin(31)=0.514 (0.515038, -0.001038) cos(31)=0.856 (0.857167, -0.001167)
sin(32)=0.529 (0.529919, -0.000919) cos(32)=0.847 (0.848048, -0.001048)
sin(33)=0.544 (0.544639, -0.000639) cos(33)=0.837 (0.838671, -0.001671)
sin(34)=0.559 (0.559193, -0.000193) cos(34)=0.828 (0.829038, -0.001038)
sin(35)=0.574 (0.573576, 0.000424) cos(35)=0.819 (0.819152, -0.000152)
sin(36)=0.587 (0.587785, -0.000785) cos(36)=0.808 (0.809017, -0.001017)
sin(37)=0.601 (0.601815, -0.000815) cos(37)=0.797 (0.798636, -0.001636)
sin(38)=0.615 (0.615661, -0.000661) cos(38)=0.787 (0.788011, -0.001011)
sin(39)=0.629 (0.629320, -0.000320) cos(39)=0.776 (0.777146, -0.001146)
sin(40)=0.643 (0.642788, 0.000212) cos(40)=0.766 (0.766044, -0.000044)
sin(41)=0.655 (0.656059, -0.001059) cos(41)=0.754 (0.754710, -0.000710)
sin(42)=0.668 (0.669131, -0.001131) cos(42)=0.742 (0.743145, -0.001145)
sin(43)=0.681 (0.681998, -0.000998) cos(43)=0.730 (0.731354, -0.001354)
sin(44)=0.694 (0.694658, -0.000658) cos(44)=0.718 (0.719340, -0.001340)
sin(45)=0.707 (0.707107, -0.000107) cos(45)=0.707 (0.707107, -0.000107)
sin(46)=0.718 (0.719340, -0.001340) cos(46)=0.694 (0.694658, -0.000658)
sin(47)=0.730 (0.731354, -0.001354) cos(47)=0.681 (0.681998, -0.000998)
sin(48)=0.742 (0.743145, -0.001145) cos(48)=0.668 (0.669131, -0.001131)
sin(49)=0.754 (0.754710, -0.000710) cos(49)=0.655 (0.656059, -0.001059)
sin(50)=0.766 (0.766044, -0.000044) cos(50)=0.643 (0.642788, 0.000212)
sin(51)=0.776 (0.777146, -0.001146) cos(51)=0.629 (0.629320, -0.000320)
sin(52)=0.787 (0.788011, -0.001011) cos(52)=0.615 (0.615662, -0.000661)
sin(53)=0.797 (0.798635, -0.001635) cos(53)=0.601 (0.601815, -0.000815)
sin(54)=0.808 (0.809017, -0.001017) cos(54)=0.587 (0.587785, -0.000785)
sin(55)=0.819 (0.819152, -0.000152) cos(55)=0.574 (0.573576, 0.000424)
sin(56)=0.828 (0.829038, -0.001038) cos(56)=0.559 (0.559193, -0.000193)
sin(57)=0.837 (0.838671, -0.001671) cos(57)=0.544 (0.544639, -0.000639)
sin(58)=0.847 (0.848048, -0.001048) cos(58)=0.529 (0.529919, -0.000919)
sin(59)=0.856 (0.857167, -0.001167) cos(59)=0.514 (0.515038, -0.001038)
sin(60)=0.866 (0.866025, -0.000025) cos(60)=0.500 (0.500000, 0.000000)
sin(61)=0.874 (0.874620, -0.000620) cos(61)=0.484 (0.484810, -0.000810)
sin(62)=0.882 (0.882948, -0.000948) cos(62)=0.469 (0.469472, -0.000472)
sin(63)=0.890 (0.891007, -0.001007) cos(63)=0.453 (0.453991, -0.000991)
sin(64)=0.898 (0.898794, -0.000794) cos(64)=0.438 (0.438371, -0.000371)
sin(65)=0.906 (0.906308, -0.000308) cos(65)=0.423 (0.422618, 0.000382)
sin(66)=0.912 (0.913545, -0.001545) cos(66)=0.406 (0.406737, -0.000737)
sin(67)=0.919 (0.920505, -0.001505) cos(67)=0.390 (0.390731, -0.000731)
sin(68)=0.926 (0.927184, -0.001184) cos(68)=0.374 (0.374607, -0.000607)
sin(69)=0.933 (0.933580, -0.000580) cos(69)=0.358 (0.358368, -0.000368)
sin(70)=0.940 (0.939693, 0.000307) cos(70)=0.342 (0.342020, -0.000020)
sin(71)=0.945 (0.945519, -0.000519) cos(71)=0.325 (0.325568, -0.000568)
sin(72)=0.950 (0.951056, -0.001056) cos(72)=0.308 (0.309017, -0.001017)
sin(73)=0.955 (0.956305, -0.001305) cos(73)=0.292 (0.292372, -0.000372)
sin(74)=0.960 (0.961262, -0.001262) cos(74)=0.275 (0.275637, -0.000637)
sin(75)=0.966 (0.965926, 0.000074) cos(75)=0.259 (0.258819, 0.000181)
sin(76)=0.969 (0.970296, -0.001296) cos(76)=0.242 (0.241922, 0.000078)
sin(77)=0.973 (0.974370, -0.001370) cos(77)=0.225 (0.224951, 0.000049)
sin(78)=0.977 (0.978148, -0.001148) cos(78)=0.208 (0.207912, 0.000088)
sin(79)=0.981 (0.981627, -0.000627) cos(79)=0.191 (0.190809, 0.000191)
sin(80)=0.985 (0.984808, 0.000192) cos(80)=0.174 (0.173648, 0.000352)
sin(81)=0.987 (0.987688, -0.000688) cos(81)=0.156 (0.156434, -0.000434)
sin(82)=0.989 (0.990268, -0.001268) cos(82)=0.139 (0.139173, -0.000173)
sin(83)=0.991 (0.992546, -0.001546) cos(83)=0.121 (0.121869, -0.000869)
sin(84)=0.993 (0.994522, -0.001522) cos(84)=0.104 (0.104528, -0.000528)
sin(85)=0.996 (0.996195, -0.000195) cos(85)=0.087 (0.087156, -0.000156)
sin(86)=0.996 (0.997564, -0.001564) cos(86)=0.069 (0.069757, -0.000757)
sin(87)=0.997 (0.998630, -0.001630) cos(87)=0.052 (0.052336, -0.000336)
sin(88)=0.998 (0.999391, -0.001391) cos(88)=0.034 (0.034900, -0.000900)
sin(89)=0.999 (0.999848, -0.000848) cos(89)=0.017 (0.017452, -0.000452)
sin(90)=1.000 (1.000000, 0.000000) cos(90)=0.000 (0.000000, 0.000000)
注:
- 以上只实现0~+/-90度操作,如果需要0~360度区间可以利用0~90的结果进行适当变换就行了
- 正切操作也可以利用该方法实现,不过角度计算可以定义最大值8800也即88.0度,从而规避超过88度的特殊情况
|