• CORDIC算法的FPGA实现


    忙了几天的毕业设计,做了256~16M点FFT窗函数的设计。今晚终于可以写下博客了,嘻嘻。在这次的设计中用到了CORDIC算法,接下来开始举一个简单的例子来说明该算法的FPGA实现。根据上一篇博客的CORDIC算法理论基础,本次设计以圆周系统的旋转模式为依据和迭代法为实现方案。为了方便说明该设计,相位输入位宽为8,迭代次数为8。

    (1)由上一篇博客可知,为了让复杂的三角函数转换成简单的移位相加,得对θi进行一定的限制,使tanθi=2-i,即θi=tan-12-i(i=0,1,2...)。这样,我们可以算出每次迭代所对应的旋转角度了。为了快速算出这些旋转角度,我们得寻找一种方便易用、计算能力强大的软件来完成,C、C++等随你选。这里以MATLAB为例:

    fid = fopen('rot.txt','w');
    for i=0:7
        x = atan(2^(-i))*2^8/(2*pi);
        rot_angle = atan(2^(-i))*180/pi;
        y = dec2bin(x,8);
        fprintf(fid,'parameter Rot%d = 8''b',i+1);
        fwrite(fid,y);
        fprintf(fid,';	//%8.5fdeg
    ',rot_angle);  
    end
    fclose(fid)

    运行后,产生rot.txt文件,打开后会发现该文件已经包含了本设计中需要的旋转角度:

    1

    (2)由于每次旋转都会使向量模长增大1/cosθi倍,n次旋转后模长将增大

    1/cosθ0*1/cosθ1*...*1/cosθn-1。为了纠正向量模长,最后得乘以因子

    cosθ0*cosθ1*...*cosθn-1。该值的计算也交给MATLAB了。

    Init_1 = 1;
    fid = fopen('Init.txt','w');
    for i = 0:7
       cos_data = cos(atan(2^(-i))); 
       Init_1 = Init_1*cos_data;
    end
    Init_expand = Init_1*2^7;
    Init_data = dec2bin(Init_expand,8);
    fprintf(fid,'parameter Init  = 8''b');
    fwrite(fid,Init_data);
    fprintf(fid,'; //%7.5f*2^%d  8次迭代:%7.5f',Init_1,i,Init_1);
    fclose(fid)

    运行后,产生Init.txt文件,内容如下:

    2

    (3)有了上面的参数,以及下面的迭代公式和初始值就可以开始设计我们的代码了。

    3

    其中di为:

    4

    设计代码如下:

    `timescale 1ns / 1ps
    /*******************************************************
    Author       :  CrazyBird
    Filename     :  cordic.v
    Data         :  2015-3-17
    Description  :  cordic 
    ********************************************************/
    module cordic
    #(
        parameter DATA_WIDTH = 8
    )
    (
        input                           clk,
        input                           rst_n,
        input       [DATA_WIDTH-1:0]    phase_in,
        output reg  [DATA_WIDTH-1:0]    sin_out,
        output reg  [DATA_WIDTH-1:0]    cos_out
    );
    //------------------------------------------------
    //定义旋转角度
    parameter Rot1 = 8'b00100000;   //45.00000deg
    parameter Rot2 = 8'b00010010;   //26.56505deg
    parameter Rot3 = 8'b00001001;   //14.03624deg
    parameter Rot4 = 8'b00000101;   // 7.12502deg
    parameter Rot5 = 8'b00000010;   // 3.57633deg
    parameter Rot6 = 8'b00000001;   // 1.78991deg
    parameter Rot7 = 8'b00000000;   // 0.89517deg
    //parameter Rot8 = 8'b00000000;   // 0.44761deg
    parameter Init = 8'b01001101;   // 0.60726*2^7  8次迭代:0.60726
    //------------------------------------------------
    //定义迭代级数
    reg    [DATA_WIDTH-1:0]    x0 ,y0 ,z0 ;
    reg    [DATA_WIDTH-1:0]    x1 ,y1 ,z1 ;
    reg    [DATA_WIDTH-1:0]    x2 ,y2 ,z2 ;
    reg    [DATA_WIDTH-1:0]    x3 ,y3 ,z3 ;
    reg    [DATA_WIDTH-1:0]    x4 ,y4 ,z4 ;
    reg    [DATA_WIDTH-1:0]    x5 ,y5 ,z5 ;
    reg    [DATA_WIDTH-1:0]    x6 ,y6 ,z6 ;
    reg    [DATA_WIDTH-1:0]    x7 ,y7 ,z7 ;
    reg    [DATA_WIDTH-1:0]    x8 ,y8 ,z8 ;
    //------------------------------------------------
    //规定区间范围
    reg     [DATA_WIDTH-1:0]   phase_in_reg;
    
    always @(posedge clk,negedge rst_n)
    begin
        if(!rst_n)
            phase_in_reg <= 8'b0;
        else 
            begin
            case(phase_in[7:6])
            2'b00: phase_in_reg <= phase_in;
            2'b01: phase_in_reg <= phase_in-8'h40;
            2'b10: phase_in_reg <= phase_in-8'h80;
            2'b11: phase_in_reg <= phase_in-8'hc0;
            default:;
            endcase
            end
    end
    //------------------------------------------------
    //初始值
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x0 <= 8'h00;
            y0 <= 8'h00;
            z0 <= 8'h00;
            end
        else
            begin
            x0 <= Init;
            y0 <= 8'h00;
            z0 <= phase_in_reg;
            end
    end
    //------------------------------------------------
    //第一级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x1 <= 8'h00;
            y1 <= 8'h00;
            z1 <= 8'h00;
            end
        else
            begin
            if(z0[7]==1'b0)
                begin
                x1 <= x0 - y0;
                y1 <= y0 + x0;
                z1 <= z0 - Rot1;
                end
            else
                begin
                x1 <= x0 + y0;
                y1 <= y0 - x0;
                z1 <= z0 + Rot1;
                end
            end
    end
    //------------------------------------------------
    //第二级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x2 <= 8'h00;
            y2 <= 8'h00;
            z2 <= 8'h00;
            end
        else
            begin
            if(z1[7]==1'b0)
                begin
                x2 <= x1 - {y1[DATA_WIDTH-1],y1[DATA_WIDTH-1:1]};
                y2 <= y1 + {x1[DATA_WIDTH-1],x1[DATA_WIDTH-1:1]};
                z2 <= z1 - Rot2;
                end
            else
                begin
                x2 <= x1 + {y1[DATA_WIDTH-1],y1[DATA_WIDTH-1:1]};
                y2 <= y1 - {x1[DATA_WIDTH-1],x1[DATA_WIDTH-1:1]};
                z2 <= z1 + Rot2;
                end
            end
    end
    //------------------------------------------------
    //第三级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x3 <= 8'h00;
            y3 <= 8'h00;
            z3 <= 8'h00;
            end
        else
            begin
            if(z2[7]==1'b0)
                begin
                x3 <= x2 - {{2{y2[DATA_WIDTH-1]}},y2[DATA_WIDTH-1:2]};
                y3 <= y2 + {{2{x2[DATA_WIDTH-1]}},x2[DATA_WIDTH-1:2]};
                z3 <= z2 - Rot3;
                end
            else
                begin
                x3 <= x2 + {{2{y2[DATA_WIDTH-1]}},y2[DATA_WIDTH-1:2]};
                y3 <= y2 - {{2{x2[DATA_WIDTH-1]}},x2[DATA_WIDTH-1:2]};
                z3 <= z2 + Rot3;
                end
            end
    end
    //------------------------------------------------
    //第四级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x4 <= 8'h00000000;
            y4 <= 8'h00000000;
            z4 <= 8'h00000000;
            end
        else
            begin
            if(z3[7]==1'b0)
                begin
                x4 <= x3 - {{3{y3[DATA_WIDTH-1]}},y3[DATA_WIDTH-1:3]};
                y4 <= y3 + {{3{x3[DATA_WIDTH-1]}},x3[DATA_WIDTH-1:3]};
                z4 <= z3 - Rot4;
                end
            else
                begin
                x4 <= x3 + {{3{y3[DATA_WIDTH-1]}},y3[DATA_WIDTH-1:3]};
                y4 <= y3 - {{3{x3[DATA_WIDTH-1]}},x3[DATA_WIDTH-1:3]};
                z4 <= z3 + Rot4;
                end
            end
    end
    //------------------------------------------------
    //第五级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x5 <= 8'h00;
            y5 <= 8'h00;
            z5 <= 8'h00;
            end
        else
            begin
            if(z4[7]==1'b0)
                begin
                x5 <= x4 - {{4{y4[DATA_WIDTH-1]}},y4[DATA_WIDTH-1:4]};
                y5 <= y4 + {{4{x4[DATA_WIDTH-1]}},x4[DATA_WIDTH-1:4]};
                z5 <= z4 - Rot5;
                end
            else
                begin
                x5 <= x4 + {{4{y4[DATA_WIDTH-1]}},y4[DATA_WIDTH-1:4]};
                y5 <= y4 - {{4{x4[DATA_WIDTH-1]}},x4[DATA_WIDTH-1:4]};
                z5 <= z4 + Rot5;
                end
            end
    end
    //------------------------------------------------
    //第六级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x6 <= 8'h00;
            y6 <= 8'h00;
            z6 <= 8'h00;
            end
        else
            begin
            if(z5[7]==1'b0)
                begin
                x6 <= x5 - {{5{y5[DATA_WIDTH-1]}},y5[DATA_WIDTH-1:5]};
                y6 <= y5 + {{5{x5[DATA_WIDTH-1]}},x5[DATA_WIDTH-1:5]};
                z6 <= z5 - Rot6;
                end
            else
                begin
                x6 <= x5 + {{5{y5[DATA_WIDTH-1]}},y5[DATA_WIDTH-1:5]};
                y6 <= y5 - {{5{x5[DATA_WIDTH-1]}},x5[DATA_WIDTH-1:5]};
                z6 <= z5 + Rot6;
                end
            end
    end
    //------------------------------------------------
    //第七级迭代
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            x7 <= 8'h00;
            y7 <= 8'h00;
            z7 <= 8'h00;
            end
        else
            begin
            if(z6[7]==1'b0)
                begin
                x7 <= x6 - {{6{y6[DATA_WIDTH-1]}},y6[DATA_WIDTH-1:6]};
                y7 <= y6 + {{6{x6[DATA_WIDTH-1]}},x6[DATA_WIDTH-1:6]};
                z7 <= z6 - Rot7;
                end
            else
                begin
                x7 <= x6 + {{6{y6[DATA_WIDTH-1]}},y6[DATA_WIDTH-1:6]};
                y7 <= y6 - {{6{x6[DATA_WIDTH-1]}},x6[DATA_WIDTH-1:6]};
                z7 <= z6 + Rot7;
                end
            end
    end
    //------------------------------------------------
    //第八级迭代
    //always @(posedge clk or negedge rst_n)
    //begin
    //    if(!rst_n)
    //        begin
    //        x8 <= 8'h00;
    //        y8 <= 8'h00;
    //        z8 <= 8'h00;
    //        end
    //    else
    //        begin
    //        if(z7[7]==1'b0)
    //            begin
    //            x8 <= x7 - {{7{y7[DATA_WIDTH-1]}},y7[DATA_WIDTH-1:7]};
    //            y8 <= y7 + {{7{x7[DATA_WIDTH-1]}},x7[DATA_WIDTH-1:7]};
    //            z8 <= z7 - Rot8;
    //            end
    //        else
    //            begin
    //            x8 <= x7 + {{7{y7[DATA_WIDTH-1]}},y7[DATA_WIDTH-1:7]};
    //            y8 <= y7 - {{7{x7[DATA_WIDTH-1]}},x7[DATA_WIDTH-1:7]};
    //            z8 <= z7 + Rot8;
    //            end
    //        end
    //end
    //------------------------------------------------
    //对界定象限的位进行缓存,为后面的输出正余弦值做区间判断
    reg [1:0] phase_in_buf [9:0];
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            phase_in_buf[0] <= 2'b0;
            phase_in_buf[1] <= 2'b0;
            phase_in_buf[2] <= 2'b0;
            phase_in_buf[3] <= 2'b0;
            phase_in_buf[4] <= 2'b0;
            phase_in_buf[5] <= 2'b0;
            phase_in_buf[6] <= 2'b0;
            phase_in_buf[7] <= 2'b0;
            phase_in_buf[8] <= 2'b0;
            phase_in_buf[9] <= 2'b0;
            end
        else
            begin
            phase_in_buf[0] <= phase_in[7:6];
            phase_in_buf[1] <= phase_in_buf[0];
            phase_in_buf[2] <= phase_in_buf[1];
            phase_in_buf[3] <= phase_in_buf[2];
            phase_in_buf[4] <= phase_in_buf[3];
            phase_in_buf[5] <= phase_in_buf[4];
            phase_in_buf[6] <= phase_in_buf[5];
            phase_in_buf[7] <= phase_in_buf[6];
            phase_in_buf[8] <= phase_in_buf[7];
            phase_in_buf[9] <= phase_in_buf[8];
            end
    end
    //------------------------------------------------
    //输出正、余弦值
    always @ (posedge clk,negedge rst_n)
    begin
        if(!rst_n)
        begin
            sin_out <= 8'b0;
            cos_out <= 8'b0;
        end
        else
            begin
            case(phase_in_buf[8])
            2'b00:
                begin
                sin_out <= y7;
                cos_out <= x7;
                end
            2'b01:
                begin
                sin_out <= x7;
                cos_out <= ~(y7)+1'b1;
                end
            2'b10:
                begin
                sin_out <= ~(y7)+1'b1;
                cos_out <= ~(x7)+1'b1;
                end
            2'b11:
                begin
                sin_out <= ~(x7)+1'b1;
                cos_out <= y7;
                end
            endcase
            end
    end
    
    
    endmodule

    测试代码:

    `timescale 1ns / 1ps
    /*******************************************************
    Author       :  CrazyBird
    Filename     :  cordic_tb.v
    Data         :  2015-3-17
    Description  :  test of cordic module
    ********************************************************/
    module cordic_tb;
    
    reg             clk;
    reg             rst_n;
    reg     [7:0]   phase_in;
    
    wire    [7:0]   sin_out;
    wire    [7:0]   cos_out;
    
    cordic u_cordic 
    (
        .clk        (clk        ), 
        .rst_n      (rst_n      ), 
        .phase_in   (phase_in   ), 
        .sin_out    (sin_out    ), 
        .cos_out    (cos_out    )
    );
        
    parameter PERIOD = 10;
        
    initial
    begin
         clk = 0;
         forever #(PERIOD/2)
            clk = ~clk;
    end
    
    initial 
    begin
        rst_n = 0;
        repeat(2)@(negedge clk);
        rst_n = 1;
    end
        
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            phase_in <= 8'b0;
        else
            phase_in <= phase_in + 1'b1;
    end
          
    endmodule

    (4)测试结果

    5

    由仿真结果可以知道功能基本实现,但精度不够高。为了提高精度,可以增加输出相位的位宽和迭代次数。

    好,总算讲完了。该睡了,晚安*^_^*

  • 相关阅读:
    pmp组织结构
    在Python中使用ArcObjects(来自Mark Cederholm UniSource Energy Services )
    C#中使用多线程访问winform的值
    白话地图投影之图解投影
    白话地图投影之初识地球
    验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保<machineKey>
    外连接
    Repeater二级绑定
    内连接
    Access多条件查询前几条数据
  • 原文地址:https://www.cnblogs.com/CrazyBirdLin/p/4357217.html
Copyright © 2020-2023  润新知