三角函数查表法
在单片机运算中,以整数形式或说定点数形式进行运算会比以浮点数形式运算快。电机控制中,经常需要用到三角函数,正弦,余弦,或者正切,求解这一类函数对于性能没那么优秀的单片机来说十分吃力,实际表现为计算时间长,甚至超过实时运行着的电机系统控制周期,这样对电机控制是十分不利的。为此可以构建一个三角函数表,使用查表来代替计算,缩短计算所需的时间。以下为构表思路。一、计算正弦函数值考虑到在单片机中使用数组去保存三角函数值,为了最大程度节省存储空间,所以在数组中只保存正弦函数在第一象限的函数值,余弦函数和正弦函数其他象限的函数值均由他们之间的关系得出。以步长1°去构建正弦函数在第一象限的值,同时为了更快地在单片机中运算,把函数值放大1000倍取整,可以得出以下函数值。https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/a.png
补充一个值:10000*sin90 = 9999
二、正余弦函数之间的关系以下角度范围统一为 -180°~+180°在第一象限内正余弦函数有如下关系式:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/p.png
第四象限与第一象限正余弦函数的关系式:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/c.png
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/d.png第二象限与第一象限正余弦函数的关系式:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/e.png
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/f.png第三象限与第一象限正余弦函数的关系式:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/g.png
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/h.png
三、根据关系式编写代码由以上各个象限之间的关系式,编写一个查询函数,如下:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/i.png返回值的定义:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/j.png三、验证编写代码将查表的函数值与使用三角函数计算出来的值作对比,一致则建表成功。验证代码如下:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/k.png部分结果输出截图如下:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/l.png从输出来看,查表得到的值与计算的值无差异,建表成功。
四、在LPC824上对比使用查表法与实时计算的耗时单片机的系统时钟为30M,简单测试代码如下:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/m.png在循环中插入代码,然后单片机的GPIO0_13接入逻辑分析仪,高电平保持时间即为在单片机中实时计算三角函数的计算耗时。实时计算的耗时如下:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/n.png平均约414us。查表的耗时如下:
https://edit.wpgdadawant.com/uploads/news_file/blog/2021/5313/tinymce/o.png最长耗时一个查表周期约在13us,但绝大部分时间平均4us。
#include <stdio.h>
#include <math.h>
#define TABLE_SIZE 360
#define SCALE_FACTOR 1000
// 预计算sin表
float sin_table;
void init_sin_table() {
for (int i = 0; i < TABLE_SIZE; i++) {
sin_table = sin(i * M_PI / 180.0) * SCALE_FACTOR;
}
}
float sin_lookup(float angle) {
angle = fmod(angle, 360.0f); // 归一化到0-360度
if (angle < 0) angle += 360.0f;
int index = (int)(angle * (TABLE_SIZE - 1) / 360.0f);
float fraction = angle * (TABLE_SIZE - 1) / 360.0f - index;
return (sin_table + fraction * (sin_table - sin_table)) / SCALE_FACTOR;
}
int main() {
init_sin_table();
float angle = 45.0f;
float result = sin_lookup(angle);
printf("sin(%f) = %f\n", angle, result);
return 0;
} 在无FPU的MCU中优先使用Q格式定点数。 表的大小直接影响到存储空间的占用。如果存储空间有限,可以选择较低的精度或使用插值方法来提高精度。 为了提高精度,可以使用线性插值方法。对于不在表中的角度,通过线性插值计算出近似值。 在资源受限的单片机上,固定点运算可能是更好的选择,因为它比浮点运算更快且占用更少的资源。 运行时通过索引(如角度值)直接查表获取结果,避免实时计算开销。 在编译或开发阶段,使用高精度的数学库或算法计算出三角函数的值,并存储到数组中。
页:
[1]