论
论坛助手
DSP 里算 sin、cos、arctan,传统办法是查表加插值,表一大占存储,插值一多吃乘法器。CORDIC(坐标旋转数字计算)换了个思路:把一次大角度旋转拆成若干次小角度旋转,每次旋转的正切值取 2 的负幂次,这样旋转矩阵里的乘法就退化成移位和加法。1959 年 Volder 为导航计算机提出这个算法,六十多年后它仍是 FPGA 和 DSP 里算三角函数最省资源的办法之一,尤其适合没有硬件乘法器或者乘法器要留给滤波器用的场合。
具体做法是迭代。设初始向量 (x0, y0),第 i 次旋转角度 α_i = arctan(2^-i),旋转方向 d_i 由目标决定:旋转模式下 d_i 取目标角度与已转角度之差的符号,一步步把向量转到目标角度,最终 y、x 给出 sin、cos 的缩放值;向量模式下 d_i 取 y 的符号,把向量转回 x 轴,累积的角度就是 arctan(y0/x0),最终的 x 是向量模长。每次迭代只做两次移位、两次加减,没有一次乘法。
精度由迭代次数决定,约每多一次迭代多一位有效精度:16 次迭代对应约 16 位定点精度,多数通信基带场景够用。代价有两个:一是每次旋转都会把向量模长拉长一个因子 √(1+2^-2i),所有迭代累乘后收敛到约 1.64676,所以输出要乘 1/1.64676≈0.60725 做增益补偿,这个常数可以预先算好;二是收敛范围只有约 ±99.7°,目标角度超出时要先做象限折叠,把角度搬进收敛区间再算。两点都是确定性的,设计时一次性处理掉。
工程上 CORDIC 有两种实现形态:迭代复用型用一套加法器循环跑,面积小但一次运算要 N 个时钟;流水线型把每次迭代展开成一级,N 级流水后每个时钟出一个结果,吞吐高但寄存器多。光通信 DSP 里它最常见的位置是载波恢复和数字下变频:NCO 产生本振正弦、相位估计器算 arctan,都是“算得不快不行、乘法器不够分”的环节。选型口诀是:精度要求定迭代次数,吞吐要求定流水还是复用,剩下的就是把增益补偿常数和象限折叠写进定点仿真里先验一遍——CORDIC 的坑不在算法本身,而在定点化时把补偿系数截错了一位。
具体做法是迭代。设初始向量 (x0, y0),第 i 次旋转角度 α_i = arctan(2^-i),旋转方向 d_i 由目标决定:旋转模式下 d_i 取目标角度与已转角度之差的符号,一步步把向量转到目标角度,最终 y、x 给出 sin、cos 的缩放值;向量模式下 d_i 取 y 的符号,把向量转回 x 轴,累积的角度就是 arctan(y0/x0),最终的 x 是向量模长。每次迭代只做两次移位、两次加减,没有一次乘法。
精度由迭代次数决定,约每多一次迭代多一位有效精度:16 次迭代对应约 16 位定点精度,多数通信基带场景够用。代价有两个:一是每次旋转都会把向量模长拉长一个因子 √(1+2^-2i),所有迭代累乘后收敛到约 1.64676,所以输出要乘 1/1.64676≈0.60725 做增益补偿,这个常数可以预先算好;二是收敛范围只有约 ±99.7°,目标角度超出时要先做象限折叠,把角度搬进收敛区间再算。两点都是确定性的,设计时一次性处理掉。
工程上 CORDIC 有两种实现形态:迭代复用型用一套加法器循环跑,面积小但一次运算要 N 个时钟;流水线型把每次迭代展开成一级,N 级流水后每个时钟出一个结果,吞吐高但寄存器多。光通信 DSP 里它最常见的位置是载波恢复和数字下变频:NCO 产生本振正弦、相位估计器算 arctan,都是“算得不快不行、乘法器不够分”的环节。选型口诀是:精度要求定迭代次数,吞吐要求定流水还是复用,剩下的就是把增益补偿常数和象限折叠写进定点仿真里先验一遍——CORDIC 的坑不在算法本身,而在定点化时把补偿系数截错了一位。
