CORDIC(坐标旋转数字算法)是一种计算三角、双曲和其他数学函数的有效方法。它是一种数字算法,每次运算均产生一次结果输出。这使我们能够根据应用需求调整算法精度;增加运算迭代次数可以得到更精确的结果。
CORDIC是只使用加法、减法、移位和查找表实现的简单算法,这种算法在FPGA中实现效率高,在硬件算法实现中经常用到。
在这里,CORDIC算法从X轴正半轴开始,对应的角度为0度,然后执行四次或顺时针或逆时针的旋转,每次旋转的角度越来越小,最终得到目标角度φ。一旦旋转完成,得到的角度就与理论的角度十分接近了,如下图所示。如果我们假设向量的长度为1,从(x,y) = (1,0)即0°角开始,那么最终向量在x,y的分量就分别对应cosφ和sinφ。我们改善CORDIC算法的关键在于提升以上过程的计算效率。
在二维中,旋转矩阵为:
R ( θ ) = [ cos θ − sin θ sin θ cos θ ] R(θ) = \begin{bmatrix}\cosθ&-\sinθ\\\sinθ&\cosθ\\ \end{bmatrix} R(θ)=[cosθsinθ−sinθcosθ]
在CORDIC的每次迭代中,我们执行以下操作来执行一次旋转,即矩阵向量乘法:
[ cos θ − sin θ sin θ cos θ ] [ x i − 1 y i − 1 ] = [ x i y i ] \begin{bmatrix}\cosθ&-\sinθ\\\sinθ&\cosθ\\ \end{bmatrix} \begin{bmatrix} x_{i-1}\\y_{i-1}\\ \end{bmatrix}= \begin{bmatrix} x_i\\y_i\\ \end{bmatrix} [cosθsinθ−sinθcosθ][xi−1yi−1]=[xiyi]
写出线性方程,新旋转矢量的坐标是:
x i = x i − 1 cos θ − y i − 1 sin θ x_i = x_{i-1}\cos\theta - y_{i-1}\sin\theta xi=xi−1cosθ−yi−1sinθ
y i = x i − 1 sin θ − y i − 1 cos θ y_i = x_{i-1}\sin\theta - y_{i-1}\cos\theta yi=xi−1sinθ−yi−1cosθ
如上可以发现还是有四个乘法在其中,对于实现硬件代价较高。
例如,可以考虑**乘以2的任意幂可以转变为移位操作。**如果我们将旋转矩阵中的常量设置为2的幂,我们可以非常容易地执行旋转而不需要乘法。
即只进行加/减和2的幂次乘法运算(即移位操作)。
再考虑旋转矩阵
如果我们限制tan(θi) 的值是2的幂次,那么旋转运算可以简化为数据移位(乘法)和加法。具体为,我们设tan(θi)=2^(−i) 。旋转矩阵就变成了
2^(−*i)*相当于数据向右移动i位,即等效于2的幂次除法。这基本上可以等效为一个简单的不需要任何资源的结构,在硬件实现上,它基本上是“无消耗”的.
但它也存在一些缺点。首先,我们受限只能旋转角度θ,其中tan(θi)=2^(−i) 。后续我们将证明这不是什么严重问题。第二,我们只展示了一个方向的旋转;而CORDIC要求能够旋转±θ,这个可以通过添加σ值(1或−1)来表示正向或者逆向旋转来修正这个错误。我们可能在每次迭代/旋转中有不同的σi 。因此旋转操作可概括为
x i = K i ( x i − 1 − σ i 2 − i y i − 1 ) x_i = K_i (x_{i-1}-\sigma_i2^{-i}y_{i-1}) xi=Ki(xi−1−σi2−iyi−1)
y i = K i ( σ i 2 − i x i − 1 + y i − 1 ) y_i = K_i (\sigma_i2^{-i}x_{i-1}+y_{i-1}) yi=Ki(σi2−ixi−1+yi−1)
旋转矩阵需要乘以ki,在迭代过程中ki 通常被省略,然后在一系列旋转完成后进行补偿。比例因子累积为
不同迭代的比例因子可以预先计算并存储。如果我们总是做固定次数的旋转,这个比例因子就是一个常数。
在每次迭代中,我们需要知道刚刚执行的旋转角θi。其中θi=arctan(2^−i)。我们可以提前计算每一个i对应的θi 值,然后把它们存储在片上内存中,之后我们可以像用查找表一样用这些值.
为了计算正弦和余弦值,我们从x轴正方向上的一个矢量开始(例如,初始角度45度),然后执行一系列旋转直到我们逼近给定角θ。之后,我们可以直接读取旋转矢量的x和y值,这两个值即为对应cosθ和sinθ。这里假设最终矢量幅度等于1,你会看到计算正余弦并不难实现。
用CORDIC算法计算 cos60 和 sin60 。使用递增数i(0,1,2,3,4)来表示执行五次旋转,最终旋转结果为61.078度 。这个矢量对应的x和y值可以近似为指定角度的余弦和正弦值。
如上对于计算sin cos的起始点为(1,0)点,若我们从任意一个(x,y)作为除法,那么基于其迭代公式最终起始实现了一个 θ \theta θ角度的旋转
X = x cos θ − y sin θ X = x\cos\theta - y\sin\theta X=xcosθ−ysinθ
Y = x sin θ − y cos θ Y = x\sin\theta - y\cos\theta Y=xsinθ−ycosθ
输出(X,Y)即旋转后的角度,注意 θ \theta θ值取值范围为[-90°,90°]
#define THETA_TYPE float
#define COS_SIN_TYPE float
#define NUM_ITERATIONS 50
// The cordic_phase array holds the angle for the current rotation
// The data type of cordic & the iterations number of cordic
THETA_TYPE cordic_phase[] = {
45.0, 26.565051177077986, 14.036243467926479, 7.125016348901799, 3.5763343749973515,
1.7899106082460694, 0.8951737102110744, 0.4476141708605531, 0.22381050036853808,
0.1119056770662069, 0.05595289189380367, 0.02797645261700368, 0.013988227142265015,
0.006994113675352919, 0.003497056850704011, 0.0017485284269804495, 0.0008742642136937803,
0.00043713210687233457, 0.00021856605343934782, 0.00010928302672007149, 5.464151336008544e-05,
2.732075668004893e-05, 1.3660378340025243e-05, 6.830189170012718e-06, 3.4150945850063712e-06,
1.7075472925031871e-06, 8.537736462515938e-07, 4.2688682312579694e-07, 2.1344341156289847e-07,
1.0672170578144923e-07, 5.336085289072462e-08, 2.668042644536231e-08, 1.3340213222681154e-08,
6.670106611340577e-09, 3.3350533056702886e-09, 1.6675266528351443e-09, 8.337633264175721e-10,
4.1688166320878607e-10, 2.0844083160439303e-10, 1.0422041580219652e-10, 5.211020790109826e-11,
2.605510395054913e-11, 1.3027551975274565e-11, 6.513775987637282e-12, 3.256887993818641e-12,
1.6284439969093206e-12, 8.142219984546603e-13, 4.0711099922733015e-13, 2.0355549961366507e-13,
1.0177774980683254e-13, 5.088887490341627e-14, 2.5444437451708134e-14, 1.2722218725854067e-14,
6.3611093629270335e-15, 3.1805546814635168e-15, 1.5902773407317584e-15, 7.951386703658792e-16,
3.975693351829396e-16, 1.987846675914698e-16, 9.93923337957349e-17, 4.969616689786745e-17,
2.4848083448933725e-17, 1.2424041724466862e-17, 6.212020862233431e-18, 3.1060104311167156e-18,
1.5530052155583578e-18, 7.765026077791789e-19, 3.8825130388958945e-19, 1.9412565194479472e-19,
9.706282597239736e-20, 4.853141298619868e-20, 2.426570649309934e-20, 1.213285324654967e-20,
6.066426623274835e-21, 3.0332133116374176e-21, 1.5166066558187088e-21, 7.583033279093544e-22,
3.791516639546772e-22, 1.895758319773386e-22, 9.47879159886693e-23, 4.739395799433465e-23,
2.3696978997167325e-23, 1.1848489498583662e-23, 5.924244749291831e-24, 2.9621223746459156e-24,
1.4810611873229578e-24, 7.405305936614789e-25, 3.7026529683073945e-25, 1.8513264841536972e-25,
9.256632420768486e-26, 4.628316210384243e-26, 2.3141581051921216e-26, 1.1570790525960608e-26,
5.785395262980304e-27, 2.892697631490152e-27, 1.446348815745076e-27, 7.23174407872538e-28,
3.61587203936269e-28, 1.807936019681345e-28, 9.039680098406725e-29
};
// 在趋近于无穷大的时候,K值变为恒定
THETA_TYPE cordic_K = 0.6072529350088814
void cordic(COS_SIN_TYPE x = 1, COS_SIN_TYPE y = 0, THETA_TYPE theta, COS_SIN_TYPE &s, COS_SIN_TYPE &c)
{
// Set the initial vector that we wil rorate
// current_cos = I; current = Q
COS_SIN_TYPE current_cos = x;
COS_SIN_TYPE current_sin = y;
// Factor is the 2^(-L) value
COS_SIN_TYPE factor = 1.0;
// This loop iteratively rotates the initial vector to find the
// sine and cosine vlaue corresponding to the input theta angle
int j = 0;
for(;j < NUM_ITERATIONS; j++){
// Determine if we are rotating by a positive or negative angle
int sigma = (theta < 0) ? -1 : 1;
// Save ther current_cos, so that it can be used in the sine calculation
COS_SIN_TYPE temp_cos = current_cos;
// Perform ther roation
current_cos = current_cos - current_sin * sigma * factor;
current_sin = temp_cos * sigma * factor + current_sin;
// Determin the new theta
theta = theta - sigma * cordic_phase[j];
// calculate newxt 2^(-L) value
factor = factor >> 1;
}
// Set ther final sine and cosine values
s = current_sin * cordic_K;
c = current_cos * cordic_K;
}
对于factor变量有关的乘法器,通过限制代码只工作在定点数下,我们可以用移位和加法操作来替代。
void cordic(COS_SIN_TYPE x = 1, COS_SIN_TYPE y = 0, THETA_TYPE theta, COS_SIN_TYPE &s, COS_SIN_TYPE &c)
{
COS_SIN_TYPE current_cos = x;
COS_SIN_TYPE current_sin = y;
for(int j = 0; j < NUM_ITERATIONS; j++) {
COS_SIN_TYPE cos_shift = current_cos >> j;
COS_SIN_TYPE sin_shift >> j;
if(theta >=0 ){
current_cos = current_cos - sin_shift;
current_sin = current_sin + cos_shift;
theta = theta - cordic_phase[j];
} else {
current_cos = current_cos + sin_shift;
current_sin = current_cos - sin_shift;
theta = theta + cordic_phase[j];
}
}
s = current_sin;
c = current_cos;
}
在HLS的代码实现思路,chisel需要对整个硬件的结构、数据存储和时钟等进行设计规划。这里用触发器来存储每一次迭代层级的结果,然后形成迭代N次的N级流水;将旋转角度和迭代的因子事先存储在rom中。实现代码如下:
首先定义定点数,注意在chisel.experimental包里有定点数的类
import chisel3._
import chisel3.util._
import chisel3.experimental._
import scala.collection.immutable
import scala.math._
/* 定点数的位宽定义 */
trait HasDataConfig {
val DataWidth = 24
val BinaryPoint = 10
}
然后实现cordic算法计算sin cos:
class CORDIC_SIN_COS_ORIGIN(NUM_ITERATIONS: Int = 20) extends Module with HasDataConfig {
/*
* @NUM_ITERATIONS : 输入的迭代次数 Int类型
* @theta : 输入的角度,以°为单位 定点数类型 输入范围[-90°,90°]
* @cos : 输出的余弦值 定点数类型
* @sin : 输出的正弦值 定点数类型
* details: 利用cordic圆坐标系的迭代得到三角函数的近似值,
建议迭代次数不超过30,在25次时,K值的变化已经
在超过了float的范围
**/
val io = IO(new Bundle {
val theta: FixedPoint = Input(FixedPoint(DataWidth.W, BinaryPoint.BP))
val sin: FixedPoint = Output(FixedPoint(DataWidth.W, BinaryPoint.BP))
val cos: FixedPoint = Output(FixedPoint(DataWidth.W, BinaryPoint.BP))
/* Debug */
// val sin_o: Vec[FixedPoint] = Output(Vec(NUM_ITERATIONS, FixedPoint(DataWidth.W, BinaryPoint.BP)))
// val cos_o: Vec[FixedPoint] = Output(Vec(NUM_ITERATIONS, FixedPoint(DataWidth.W, BinaryPoint.BP)))
// val theta_o: Vec[FixedPoint] = Output(Vec(NUM_ITERATIONS, FixedPoint(DataWidth.W, BinaryPoint.BP)))
})
/* 旋转度数表 */
val inits_cordic_phase: immutable.Seq[FixedPoint] = (0 until NUM_ITERATIONS).map(
t => FixedPoint.fromDouble(atan(pow(2, -t).toDouble) / Pi * 180, DataWidth.W, BinaryPoint.BP))
val cordic_phase: Vec[FixedPoint] = VecInit(inits_cordic_phase)
/* 在趋近于无穷大的时候,K值变为恒定 */
val cordic_K: FixedPoint = FixedPoint.fromDouble(0.6072529350088814, DataWidth.W, BinaryPoint.BP)
/* 初始化计算的寄存器数组,形成NUM_ITERATIONS级流水 */
val current_x: Vec[FixedPoint] = RegInit(VecInit(Seq.fill(NUM_ITERATIONS)(FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)))) // cos
val current_y: Vec[FixedPoint] = RegInit(VecInit(Seq.fill(NUM_ITERATIONS)(FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)))) // sin
val current_theta: Vec[FixedPoint] = RegInit(VecInit(Seq.fill(NUM_ITERATIONS)(FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)))) // 目标角度
/* Factor is the 2^(-L) value */
val factor_table: immutable.Seq[FixedPoint] = (0 until NUM_ITERATIONS).map(
t => FixedPoint.fromDouble(pow(2, -t).toDouble, DataWidth.W, BinaryPoint.BP))
for (i <- 0 until NUM_ITERATIONS) {
val factor = factor_table(i)
/*
* x[i] = K(x[i-1] - sigma * 2^(-i) * y[i-1])
* y[i] = K(y[i-1] + sigma * 2^(-i) * x[i-1])
**/
if (i == 0) {
/* 流水线第一级直接对(1,0)点做运算 */
current_x(i) := FixedPoint.fromDouble(1.0, DataWidth.W, BinaryPoint.BP) // - 0*factor
when(io.theta < FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)) {
current_y(i) := FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP) -
FixedPoint.fromDouble(1.0, DataWidth.W, BinaryPoint.BP) * factor
current_theta(i) := io.theta + cordic_phase(i)
}.otherwise {
current_y(i) := FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP) +
FixedPoint.fromDouble(1.0, DataWidth.W, BinaryPoint.BP) * factor
current_theta(i) := io.theta - cordic_phase(i)
}
} else {
when(current_theta(i - 1) < FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)) {
current_x(i) := current_x(i - 1) + current_y(i - 1) * factor
current_y(i) := current_y(i - 1) - current_x(i - 1) * factor
current_theta(i) := current_theta(i - 1) + cordic_phase(i)
}.otherwise {
current_x(i) := current_x(i - 1) - current_y(i - 1) * factor
current_y(i) := current_y(i - 1) + current_x(i - 1) * factor
current_theta(i) := current_theta(i - 1) - cordic_phase(i)
}
}
/* Debug */
// io.cos_o(i) := current_x(i)
// io.sin_o(i) := current_y(i)
// io.theta_o(i) := current_theta(i)
}
io.cos := current_x(NUM_ITERATIONS - 1) * cordic_K
io.sin := current_y(NUM_ITERATIONS - 1) * cordic_K
}
同样这里对于factor变量有关的乘法器,通过限制代码只工作在定点数下,我们可以用移位和加法操作来替代。
class CORDIC_SIN_COS_ORIGIN(NUM_ITERATIONS: Int = 20) extends Module with HasDataConfig {
/*
* @NUM_ITERATIONS : 输入的迭代次数 Int类型
* @theta : 输入的角度,以°为单位 定点数类型 输入范围[-90°,90°]
* @cos : 输出的余弦值 定点数类型
* @sin : 输出的正弦值 定点数类型
* details: 利用cordic圆坐标系的迭代得到三角函数的近似值,
建议迭代次数不超过30,在25次时,K值的变化已经
在超过了float的范围
**/
val io = IO(new Bundle {
val theta: FixedPoint = Input(FixedPoint(DataWidth.W, BinaryPoint.BP))
val sin: FixedPoint = Output(FixedPoint(DataWidth.W, BinaryPoint.BP))
val cos: FixedPoint = Output(FixedPoint(DataWidth.W, BinaryPoint.BP))
/* Debug */
// val sin_o: Vec[FixedPoint] = Output(Vec(NUM_ITERATIONS, FixedPoint(DataWidth.W, BinaryPoint.BP)))
// val cos_o: Vec[FixedPoint] = Output(Vec(NUM_ITERATIONS, FixedPoint(DataWidth.W, BinaryPoint.BP)))
// val theta_o: Vec[FixedPoint] = Output(Vec(NUM_ITERATIONS, FixedPoint(DataWidth.W, BinaryPoint.BP)))
})
/* 旋转度数表 */
val inits_cordic_phase: immutable.Seq[FixedPoint] = (0 until NUM_ITERATIONS).map(
t => FixedPoint.fromDouble(atan(pow(2, -t).toDouble) / Pi * 180, DataWidth.W, BinaryPoint.BP))
val cordic_phase: Vec[FixedPoint] = VecInit(inits_cordic_phase)
/* 在趋近于无穷大的时候,K值变为恒定 */
val cordic_K: FixedPoint = FixedPoint.fromDouble(0.6072529350088814, DataWidth.W, BinaryPoint.BP)
/* 初始化计算的寄存器数组,形成NUM_ITERATIONS级流水 */
val current_x: Vec[FixedPoint] = RegInit(VecInit(Seq.fill(NUM_ITERATIONS)(FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)))) // cos
val current_y: Vec[FixedPoint] = RegInit(VecInit(Seq.fill(NUM_ITERATIONS)(FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)))) // sin
val current_theta: Vec[FixedPoint] = RegInit(VecInit(Seq.fill(NUM_ITERATIONS)(FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)))) // 目标角度
for (i <- 0 until NUM_ITERATIONS) {
/*
* x[i] = K(x[i-1] - sigma * 2^(-i) * y[i-1])
* y[i] = K(y[i-1] + sigma * 2^(-i) * x[i-1])
**/
if (i == 0) {
/* 流水线第一级直接对(1,0)点做运算 */
current_x(i) := FixedPoint.fromDouble(1.0, DataWidth.W, BinaryPoint.BP) // - 0*factor
when(io.theta < FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)) {
current_y(i) := FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP) -
FixedPoint.fromDouble(1.0, DataWidth.W, BinaryPoint.BP) // * factor = 1
current_theta(i) := io.theta + cordic_phase(i)
}.otherwise {
current_y(i) := FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP) +
FixedPoint.fromDouble(1.0, DataWidth.W, BinaryPoint.BP) // * factor = 1
current_theta(i) := io.theta - cordic_phase(i)
}
} else {
when(current_theta(i - 1) < FixedPoint.fromDouble(0.0, DataWidth.W, BinaryPoint.BP)) {
current_x(i) := current_x(i - 1) + (current_y(i - 1) >> i) // 移位替代乘法
current_y(i) := current_y(i - 1) - (current_x(i - 1) >> i)
current_theta(i) := current_theta(i - 1) + cordic_phase(i)
}.otherwise {
current_x(i) := current_x(i - 1) - (current_y(i - 1) >> i)
current_y(i) := current_y(i - 1) + (current_x(i - 1) >> i)
current_theta(i) := current_theta(i - 1) - cordic_phase(i)
}
}
/* Debug */
// io.cos_o(i) := current_x(i)
// io.sin_o(i) := current_y(i)
// io.theta_o(i) := current_theta(i)
}
io.cos := current_x(NUM_ITERATIONS - 1) * cordic_K
io.sin := current_y(NUM_ITERATIONS - 1) * cordic_K
}
如上的计算注意到theta
: 输入的角度,以°为单位 定点数类型 输入范围[-90°,90°],这是由于2^(-i)次方得到的旋转角度求级数和无法达到360°的效果,所以我们在外部封装一层解决这个问题
class cordic_sin_cos(NUM_ITERATIONS: Int = 20) extends Module with HasDataConfig {
/*
* @NUM_ITERATIONS : 输入的迭代次数 Int类型
* @theta : 输入的角度,以°为单位 定点数类型 输入范围[-360,360°]
* @cos : 输出的余弦值 定点数类型
* @sin : 输出的正弦值 定点数类型
* details: 利用cordic圆坐标系的迭代得到三角函数的近似值,
建议迭代次数不超过30,在25次时,K值的变化已经
在超过了float的范围
**/
val io = IO(new Bundle{
val theta: FixedPoint = Input(FixedPoint(DataWidth.W, BinaryPoint.BP))
val sin: FixedPoint = Output(FixedPoint(DataWidth.W, BinaryPoint.BP))
val cos: FixedPoint = Output(FixedPoint(DataWidth.W, BinaryPoint.BP))
})
/* 将度数映射到[-180,180]*/
val temp_theta: FixedPoint = Wire(FixedPoint(DataWidth.W, BinaryPoint.BP))
when(io.theta > FixedPoint.fromDouble(180,DataWidth.W, BinaryPoint.BP)){
temp_theta := io.theta - FixedPoint.fromDouble(360,DataWidth.W, BinaryPoint.BP)
}.elsewhen(io.theta < FixedPoint.fromDouble(-180,DataWidth.W, BinaryPoint.BP)){
temp_theta := io.theta + FixedPoint.fromDouble(360,DataWidth.W, BinaryPoint.BP)
}.otherwise{
temp_theta := io.theta
}
/* 将度数映射到[-90,90]*/
val sigma_cos: Bool = Wire(Bool()) // 1 表示正数, 0表示负数
val real_theta: FixedPoint = Wire(FixedPoint(DataWidth.W, BinaryPoint.BP))
when(temp_theta > FixedPoint.fromDouble(90,DataWidth.W, BinaryPoint.BP)
){
sigma_cos := 0.B
real_theta := FixedPoint.fromDouble(180,DataWidth.W, BinaryPoint.BP) - temp_theta
}.elsewhen(temp_theta < FixedPoint.fromDouble(-90,DataWidth.W, BinaryPoint.BP)){
sigma_cos := 0.B
real_theta := FixedPoint.fromDouble(-180,DataWidth.W, BinaryPoint.BP) - temp_theta
}.otherwise{
sigma_cos := 1.B
real_theta := temp_theta
}
val cordic_unit: CORDIC_SIN_COS_ORIGIN = Module(new CORDIC_SIN_COS_ORIGIN(NUM_ITERATIONS))
cordic_unit.io.theta := real_theta
io.sin := cordic_unit.io.sin
when(sigma_cos){
io.cos := cordic_unit.io.cos
}.otherwise{
io.cos := -cordic_unit.io.cos
}
}
运行查看一下verilog代码
object cordicApp extends App {
println(getVerilogString(new cordic_sin_cos))
(new chisel3.stage.ChiselStage).emitVerilog(new cordic_sin_cos(10))
}
最后我们定义三个伴生对象工厂方法来方便直接调用函数,无需多加连线
/*
* 定义这个类的伴生对象,并定义一个工厂方法来简化模块的例化和连线。
* 注意定义了伴生对象后,无法对原类进行测试实例化
**/
object cordic_sin_cos extends HasDataConfig{
def apply(theta: FixedPoint, NUM_ITERATIONS: Int = 20):(FixedPoint, FixedPoint) = {
/*
* @NUM_ITERATIONS : 输入的迭代次数 Int类型
* @theta : 输入的角度,以°为单位 定点数类型 输入范围[-360,360°]
* @return cos : 输出的余弦值 定点数类型
* @return sin : 输出的正弦值 定点数类型
* details: 利用cordic圆坐标系的迭代得到三角函数的近似值,
建议迭代次数不超过30,在25次时,K值的变化已经
在超过了float的范围
**/
val cordic_unit = Module(new cordic_sin_cos(NUM_ITERATIONS))
cordic_unit.io.theta := theta
(cordic_unit.io.sin, cordic_unit.io.cos)
}
}
object cordic_sin extends HasDataConfig{
def apply(theta: FixedPoint, NUM_ITERATIONS: Int = 20):FixedPoint = {
/*
* @NUM_ITERATIONS : 输入的迭代次数 Int类型
* @theta : 输入的角度,以°为单位 定点数类型 输入范围[-360,360°]
* @return sin : 输出的正弦值 定点数类型
* details: 利用cordic圆坐标系的迭代得到三角函数的近似值,
建议迭代次数不超过30,在25次时,K值的变化已经
在超过了float的范围
**/
val (sin,cos) = cordic_sin_cos(theta, NUM_ITERATIONS)
sin
}
}
object cordic_cos extends HasDataConfig{
def apply(theta: FixedPoint, NUM_ITERATIONS: Int = 20):FixedPoint = {
/*
* @NUM_ITERATIONS : 输入的迭代次数 Int类型
* @theta : 输入的角度,以°为单位 定点数类型 输入范围[-360,360°]
* @return cos : 输出的余弦值 定点数类型
* details: 利用cordic圆坐标系的迭代得到三角函数的近似值,
建议迭代次数不超过30,在25次时,K值的变化已经
在超过了float的范围
**/
val (sin,cos) = cordic_sin_cos(theta, NUM_ITERATIONS)
cos
}
}