这里主要先介绍如何利用CORDIC算法计算固定角度\(\phi\)的\(cos(\phi)\)、\(sin(\phi)\)值。参考了这两篇文章[1][2]

一般利用MATLAB计算三角函数时,用\(cos\)举例,只需要输入相应的\(cos(\phi)\)便自动计算出来了。但是如果是硬件处理或者没有那么方便的函数时,该如何计算\(cos(\phi)\)的值呢?

有一种最傻瓜的方式是用rom存储\(0^o\)到\(90^o\)所有的余弦值,然后用查表的方法计算,但随着精度要求的提升,需要存储的值会越来越多,这是不合适的。那么有没有一种用较少资源且能较快计算出高精度三角函数值的方法呢?有!这就是CORDIC算法可以做的事,算法不难,有一点三角函数和移位运算的基础就能看懂了,核心思想就是把乘法运算变成移位运算。下面来仔细讲解。

首先引入一个在圆上的坐标旋转公式(不一定单位圆)

\[\begin{cases}
x_2 = x_1cos\theta - y_1sin\theta \\
y_2 = x_1sin\theta + y_1cos\theta \tag{1}\\
\end{cases}
\]

那么如何求\(cos\phi\)和\(sin\phi\)呢?我们可以看出,如果让初始坐标\((x_1, y_1)\)取\(x\)轴一个特定的位置,最后使其旋转\(\phi^o\)到坐标\((x_n,y_n)\)处,且满足\(\sqrt{x_n^2 + y_n^2} = 1\),那么\(cos\phi\)不就等于\(x_n\),\(sin\phi\)不就等于\(y_n\)了。这是后话,我们继续看式\((1)\),\((1)\)也可以写成:

\[\begin{cases}
x_2 = cos\theta(x_1 - y_1tan\theta) \\
y_2 = cos\theta(y_1 + x_1tan\theta)\tag{2} \\
\end{cases}
\]

由于对\((x_2, y_2)\)相当于同乘了一个常数\(cos\theta\),我们先不看它,不影响旋转角度,得到:

\[\begin{cases}
x_2 = x_1 - y_1tan\theta \\
y_2 = y_1 + x_1tan\theta \tag{3} \\
\end{cases}
\]

一:乘法变移位

之前说的我们要把乘法运算变成位移运算,所以我们找到\(tan\theta\)与\(2^{-i}\)之间的对应关系,注意由于是变成移位操作,所以对应旋转的角度也是几个固定的值,但是通过旋转这几个固定的角度,旋转\(i\)次,最终也一定能转到我们需要的角度\(\phi\)上(\(-99.7^o\le\phi \le 99.7^o\))。

于是把\((3)\)再改写为:

\[\begin{cases}
x(i+1) = x(i) - d(i)y(i)2^{-i} \\
y(i+1) = y(i) + d(i)x(i)2^{-i}\tag{4}
\end{cases}
\]

这样,旋转\(\theta^o\)就变成了移位、相加的操作。注意\(d(i) = ±1\)表示旋转的逆、顺时针。

比如要旋转\(\phi = 66^o\),可以先转\(+45^o\);\(45^o < 66^o\),再转\(+26.565^o\);\(45^o+26.565^o \ge 66^o\),再转\(-14.036^o \cdots\),最终会逼近\(66^o\)。而整个运算仅仅进行了\(2^{-0}、2^{-1}、2^{-2} \cdots\)移位操作和加法操作。


二:cos累乘项

现在考虑把\(cos\theta\)加回去,回到\((2)\),且考虑旋转方向\(d_i\)和旋转角度\(\theta_i\),得到:

\[\begin{cases}
x_2 = cos\theta_1(x_1 - d_1y_1tan\theta_1) \\
y_2 = cos\theta_1(y_1 + d_1x_1tan\theta_1)\tag{5.1} \\
\end{cases}
\]

进行下一次迭代(旋转),得到:

\[\begin{align}
x_3 &= cos\theta_2(x_2 - d_2y_2tan\theta_2) \\
&= cos\theta_2(cos\theta_1(x_1 - d_1y_1tan\theta_1)- d_2cos\theta_1(y_1 + d_1x_1tan\theta_1)tan\theta_2) \\
&= cos\theta_1cos\theta_2(x_1 - d_1y_1tan\theta_1 - d_2y_1tan\theta_2 - d_2d_1x_1tan\theta_1tan\theta_2)
\end{align} \\
\]
\[\begin{align}
y_3 &= cos\theta_2(y_2 + d_2x_2tan\theta_2) \\
&= cos\theta_2(cos\theta_1(y_1 + d_1x_1tan\theta_1) + d_2cos\theta_1(x_1 - d_1y_1tan\theta_1)tan\theta_2) \tag{5.2}\\
&= cos\theta_1cos\theta_2(y_1 + d_1x_1tan\theta_1 + d_2x_1tan\theta_2 - d_2d_1y_1tan\theta_1tan\theta_2)
\end{align}
\]

可以看到每次旋转都可以提取出\(cos\theta_i\)。\(tan\theta_i\)已经用移位替代了。接下来只用计算\(\prod_{i=1}^{N}cos\theta_i\)就行了,且\(\prod_{i=1}^{N}cos\theta_i\)只跟迭代次数有关,确定了迭代次数后,可以预先把\(\prod_{i=1}^{N}cos\theta_i\)算出来。


三:累计旋转角度与旋转方向

现在考虑最后一个问题,如何确定每次迭代的旋转方向\(d_i\)呢?其实定义一个累计旋转角度\(z_i\)

\[z_{i + 1} = z_i -d_i\theta_i = z_i -d_i2^{-i} \tag{6}
\]

令\(z_1\)等于目标角度值,然后每次迭代作个判断就好,如果\(z_i > 0\),说明当前旋转还没转到目标角度,\(d_{i+1} = 1\);如果\(z_i < 0\),说明当前旋转超过了目标角度,\(d_{i+1} = -1\)。

当我们最终转到了目标角度\(\phi\)时,比如\(\phi = 66^o\),可以此时\(z_i\)已经很小趋近于零了。

另外,在作比较判断时,单次旋转角度\(\theta_i\)则还是需要通过查一次\(arctan(2^{-i})\)表得到,但这个表比起文章开头说的傻瓜式查表要小太多了。


四:计算cos和sin值

进行差不多十多次迭代,最后趋近到所需旋转角度\(\phi\)时,最后一个坐标可由如下公式计算:

\[\begin{cases}
x(n) = \frac{1}{\prod_{i=1}^n cos\theta_i}(x(1)cosz_1 - y(1)sinz_1 \\
y(n) = \frac{1}{\prod_{i=1}^n cos\theta_i}(y(1)cosz_1 + x(1)sinz_1 \tag{7}
\end{cases}
\]

关于公式\((6)\)是如何通过公式\((2)(3)(4)(5)\)推出来的,暂时还不太理解。但是我们从公式\((6)\)可以看出,当我们设置初始坐标\((x_1, y_1) = (\prod_{i=1}^n cos\theta_i, 0)\),再另初始累计旋转角度\(z_1 = \phi\)时:

\[\begin{cases}
cos\phi = x(n) \\
sin\phi = y(n) \tag{8}
\end{cases}
\]

这样就只用通过\((4)(6)\)的移位、相加、一次查表,再迭代十多次,就能计算\(cos\phi\)和\(\sin\phi\)值啦!

其实用CORDIC算法还能计算arctan、sinh、cosh等值,以后学习了再来补充进阶版。


### 五:完整MATLAB代码

clc, clear, close all;

%% 初始计算cos累乘值
N = 16; % 设置迭代次数16次
Nprod(1) = 1;
for i = 1 : N
Nprod(i + 1) = Nprod(i) * cos(atan(2^(-(i - 1))));
end %% Cordic算法计算cos、sin值
x(1) = Nprod(N); % 横坐标初始值赋为cos累乘值,公式(7)
y(1) = 0; % 纵坐标初始值赋为0,公式(7)
z(1) = 66 / 180 * pi; %目标旋转角度值,66°,注意转化成弧度值
d(1) = 1; %旋转方向,初始肯定为1 for i = 1 : N
x(i + 1) = x(i) - d(i) * y(i) * 2^(-(i - 1)); %移位运算,公式(4)
y(i + 1) = y(i) + d(i) * x(i) * 2^(-(i - 1)); %移位运算,公式(4)
z(i + 1) = z(i) - d(i) * atan(2^(-(i - 1))); %计算累计旋转角度,查一次表,公式(6)
if z(i + 1) >= 0 % 判断下一次的旋转方向
d(i + 1) = 1;
else
d(i + 1) = -1;
end
end COS = x(N) % 输出cos66的值
SIN = y(N) % 输出sin66的值

六:参考文章

[1]:https://mp.weixin.qq.com/s/c4oro0bOhdDUmBt0yyLpTA

[2]:https://blog.csdn.net/qq_39210023/article/details/77456031

利用CORDIC算法计算三角函数的更多相关文章

  1. shingling算法——提取特征,m个hash函数做指纹计算,针对特征hash后变成m维向量,最后利用union-find算法计算相似性

    shingling算法用于计算两个文档的相似度,例如,用于网页去重.维基百科对w-shingling的定义如下: In natural language processing a w-shinglin ...

  2. C++ 概率算法 利用蒙特卡罗算法计算圆周率

    概率算法大致可分为4种形式: 数值概率算法: 蒙特卡罗算法: 拉斯维加斯算法: 舍伍德算法: 计算蒙特卡罗概率的算法实现: #include "stdio.h" #include ...

  3. 三角函数计算,Cordic 算法入门

    [-] 三角函数计算Cordic 算法入门 从二分查找法说起 减少乘法运算 消除乘法运算 三角函数计算,Cordic 算法入门 三角函数的计算是个复杂的主题,有计算机之前,人们通常通过查找三角函数表来 ...

  4. (转)三角函数计算,Cordic 算法入门

    由于最近要使用atan2函数,但是时间上消耗比较多,因而网上搜了一下简化的算法. 原帖地址:http://blog.csdn.net/liyuanbhu/article/details/8458769 ...

  5. CORDIC算法(1):圆周旋转模式下计算三角函数和模值

    CORDIC(Coordinate Rotation Digital Computer)坐标旋转数字计算机,是数学与计算机技术交叉产生的一种机器算法,用于解决计算机的数学计算问题.发展到现在,CORD ...

  6. Cordic 算法入门

    三角函数的计算是个复杂的主题,有计算机之前,人们通常通过查找三角函数表来计算任意角度的三角函数的值.这种表格在人们刚刚产生三角函数的概念的时候就已经有了,它们通常是通过从已知值(比如sin(π/2)= ...

  7. 定点CORDIC算法求所有三角函数及向量模的原理分析、硬件实现(FPGA)

    一.CORDIC算法 CORDIC(Coordinate Rotation DIgital Computer)是一种通过迭代对多种数学函数求值的方法,它可以对三角函数.双曲函数和平面旋转问题进行求解. ...

  8. Cordic算法——圆周系统之旋转模式

    三角函数的计算是个复杂的主题,有计算机之前,人们通常通过查找三角函数表来计算任意角度的三角函数的值.这种表格在人们刚刚产生三角函数的概念的时候就已经有了,它们通常是通过从已知值(比如sin(π/2)= ...

  9. Cordic算法简介

    作者:桂. 时间:2017-08-14  19:22:26 链接:http://www.cnblogs.com/xingshansi/p/7359940.html 前言 CORDIC算法常用来求解信号 ...

随机推荐

  1. Gym - 102861B 、Gym - 102861F、Gym 102861G、Gym 102861L、Gym 102861N、Gym 101968C、Gym 101968D

    训练赛链接:https://vjudge.net/contest/410049#problem/D Gym - 102861B 题意: 在一个二维平面上,给你一个船,问你在这个二维平面上有没有船重叠. ...

  2. Codeforces Round #608 (Div. 2) E. Common Number (二分,构造)

    题意:对于一个数\(x\),有函数\(f(x)\),如果它是偶数,则\(x/=2\),否则\(x-=1\),不断重复这个过程,直到\(x-1\),我们记\(x\)到\(1\)的这个过程为\(path( ...

  3. Round Numbers POJ - 3252

    题意: 如果你个数的二进制中1的个数要小于等于0的个数,那么这个数就符合题意.现在要你找出来区间[li,ri]这个区间内有多少这样的数 题解: 题意很明显了,是要用二进制,所以我们也把给的区间边界转化 ...

  4. 二、Python基础(input、变量名、条件语句、循环语句、注释)

    一.input用法 input在Python中的含义为永远等待,直到用户输入了值,从而将所输入的值赋值另外的一个东西. n=input('请输入......') 接下来用一个例子学习input的用法 ...

  5. python 3.7 安装 sklearn keras(tf.keras)

    # 1   sklearn  一般方法 网上有很多教程,不再赘述. 注意顺序是 numpy+mkl     ,然后 scipy的环境,scipy,然后 sklearn # 2 anoconda ana ...

  6. java8按照lamda表达式去重一个list,根据list中的一个元素

    /** * 按照指定字段给list去重 * @param list * @return */ public static List<DataModel> niqueList(List< ...

  7. Excel 如何固定表头

    Excel 如何固定表头 视图-冻结窗格-冻结首行 EXCEL如何设置固定表头 一.首先打开Excel表格,如果你的表头只有一行,那么直接选择"视图-冻结窗格-冻结首行"就可以了. ...

  8. webpack 性能优化 dll 分包

    webpack 性能优化 dll 分包 html-webpack-externals-plugin DLLPlugin https://www.webpackjs.com/configuration/ ...

  9. C# 6.0 Features , C# 7.0 Features

    1 1 1 C# 6.0 Features http://stackoverflow.com/documentation/c%23/24/c-sharp-6-0-features#t=20160828 ...

  10. what's the difference amount of pdf, epub, and mobi format

    what's the difference amount of pdf, epub, and Mobi format What is the difference between pdf, epub ...