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

运行与验证方法

  1. 仿真运行:使用Vivado/ModelSim/Verilator等工具,将上述两个模块加入工程,运行仿真。
  2. 观察输出:检查valid_out拉高后的x_out和y_out值。
  3. 通过标准:
    • Test1:输入(100,0)旋转90°,输出应接近(0,100),误差在±2以内(定点量化误差);
    • Test2:输入(100,0)旋转45°,输出应接近(71,71),误差在±2以内。

若输出值在上述误差范围内,说明CORDIC旋转模式功能正确。误差主要来源于角度量化(16bit)和迭代次数有限(16级),增大DATA_WIDTH和ITER_NUM可提高精度。