2. CORDIC旋转模式基础
任务目标
实现CORDIC旋转模式(Rotation Mode)的Verilog模块,输入初始向量坐标(x_in, y_in)与目标旋转角度angle_in,经过N级迭代后输出旋转后的坐标(x_out, y_out)。旋转模式的核心思想是通过一系列固定角度的微旋转,逐步逼近目标角度,最终将向量旋转指定角度。
实现原理
CORDIC旋转模式通过迭代完成向量旋转。每次迭代将当前向量旋转一个预先计算好的固定角度(atan(2-i)),并根据剩余角度决定旋转方向(顺时针或逆时针)。经过N次迭代后,向量旋转的总角度逼近目标角度,同时需要乘以增益因子K≈1.64676进行幅度补偿。本案例采用16级流水线迭代,角度精度约0.001°,坐标精度满足多数定点应用需求。
Verilog实现
module cordic_rotation #(
parameter DATA_WIDTH = 16,
parameter ITER_NUM = 16
)(
input wire clk,
input wire rst_n,
input wire valid_in,
input wire signed [DATA_WIDTH-1:0] x_in,
input wire signed [DATA_WIDTH-1:0] y_in,
input wire signed [DATA_WIDTH-1:0] angle_in, // 角度量化: 角度值 * 2^15 / 90°
output reg signed [DATA_WIDTH-1:0] x_out,
output reg signed [DATA_WIDTH-1:0] y_out,
output reg valid_out
);
// 预定义旋转角度表: atan(2^-i) 量化到 16bit (角度*2^15/90°)
// 例如 atan(1)=45° → 45*32768/90 = 16384
localparam signed [DATA_WIDTH-1:0] ANGLE_TABLE [0:15] = '{
16384, // atan(2^0) = 45.000°
9672, // atan(2^-1) = 26.565°
5110, // atan(2^-2) = 14.036°
2594, // atan(2^-3) = 7.125°
1302, // atan(2^-4) = 3.576°
652, // atan(2^-5) = 1.790°
326, // atan(2^-6) = 0.895°
163, // atan(2^-7) = 0.448°
81, // atan(2^-8) = 0.224°
41, // atan(2^-9) = 0.112°
20, // atan(2^-10) = 0.056°
10, // atan(2^-11) = 0.028°
5, // atan(2^-12) = 0.014°
3, // atan(2^-13) = 0.007°
1, // atan(2^-14) = 0.0035°
1 // atan(2^-15) = 0.0018°
};
// 流水线寄存器
reg signed [DATA_WIDTH-1:0] x_pipe [0:ITER_NUM];
reg signed [DATA_WIDTH-1:0] y_pipe [0:ITER_NUM];
reg signed [DATA_WIDTH-1:0] angle_pipe [0:ITER_NUM];
reg valid_pipe [0:ITER_NUM];
integer i;
// 第0级:输入采样
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
x_pipe[0] <= 0;
y_pipe[0] <= 0;
angle_pipe[0] <= 0;
valid_pipe[0] <= 0;
end else begin
x_pipe[0] <= x_in;
y_pipe[0] <= y_in;
angle_pipe[0] <= angle_in;
valid_pipe[0] <= valid_in;
end
end
// 16级迭代流水线
generate
genvar g;
for (g = 0; g < ITER_NUM; g = g + 1) begin : iter_stage
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
x_pipe[g+1] <= 0;
y_pipe[g+1] <= 0;
angle_pipe[g+1] <= 0;
valid_pipe[g+1] <= 0;
end else begin
// 根据剩余角度符号决定旋转方向
if (angle_pipe[g] >= 0) begin
// 逆时针旋转(d=+1)
x_pipe[g+1] <= x_pipe[g] - (y_pipe[g] >>> g);
y_pipe[g+1] <= y_pipe[g] + (x_pipe[g] >>> g);
angle_pipe[g+1] <= angle_pipe[g] - ANGLE_TABLE[g];
end else begin
// 顺时针旋转(d=-1)
x_pipe[g+1] <= x_pipe[g] + (y_pipe[g] >>> g);
y_pipe[g+1] <= y_pipe[g] - (x_pipe[g] >>> g);
angle_pipe[g+1] <= angle_pipe[g] + ANGLE_TABLE[g];
end
valid_pipe[g+1] <= valid_pipe[g];
end
end
end
endgenerate
// 输出:乘以增益补偿因子 1/K ≈ 0.60725(量化到16bit: 0.60725*32768≈19900)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
x_out <= 0;
y_out <= 0;
valid_out <= 0;
end else begin
x_out <= (x_pipe[ITER_NUM] * 19900) >>> 15;
y_out <= (y_pipe[ITER_NUM] * 19900) >>> 15;
valid_out <= valid_pipe[ITER_NUM];
end
end
endmodule
测试平台与验证
module tb_cordic_rotation;
reg clk = 0;
reg rst_n = 0;
reg valid_in = 0;
reg signed [15:0] x_in, y_in, angle_in;
wire signed [15:0] x_out, y_out;
wire valid_out;
cordic_rotation dut (
.clk(clk), .rst_n(rst_n),
.valid_in(valid_in),
.x_in(x_in), .y_in(y_in), .angle_in(angle_in),
.x_out(x_out), .y_out(y_out),
.valid_out(valid_out)
);
always #5 clk = ~clk;
initial begin
// 复位
#20 rst_n = 1;
// 测试用例1: 向量(100, 0) 旋转 90° → 期望(0, 100)
@(posedge clk);
valid_in = 1;
x_in = 16'd100;
y_in = 16'd0;
angle_in = 16'sd16384; // 90° 量化值
@(posedge clk);
valid_in = 0;
// 等待流水线完成
repeat (20) @(posedge clk);
$display("Test1: x_out=%0d, y_out=%0d (期望约 0, 100)", x_out, y_out);
// 测试用例2: 向量(100, 0) 旋转 45° → 期望(70.7, 70.7)
@(posedge clk);
valid_in = 1;
x_in = 16'd100;
y_in = 16'd0;
angle_in = 16'sd8192; // 45° 量化值
@(posedge clk);
valid_in = 0;
repeat (20) @(posedge clk);
$display("Test2: x_out=%0d, y_out=%0d (期望约 71, 71)", x_out, y_out);
#100;
$finish;
end
endmodule
运行与验证方法
- 仿真运行:使用Vivado/ModelSim/Verilator等工具,将上述两个模块加入工程,运行仿真。
- 观察输出:检查
valid_out拉高后的x_out和y_out值。 - 通过标准:
- Test1:输入(100,0)旋转90°,输出应接近(0,100),误差在±2以内(定点量化误差);
- Test2:输入(100,0)旋转45°,输出应接近(71,71),误差在±2以内。
若输出值在上述误差范围内,说明CORDIC旋转模式功能正确。误差主要来源于角度量化(16bit)和迭代次数有限(16级),增大DATA_WIDTH和ITER_NUM可提高精度。