參考文獻
[1].碎碎思
項目簡述
我們上一篇文章已經講解了CORDIC的向量模式,通過算法的向量模式我們可以計算向量的幅值與相位角,那麼通過算法的旋轉模式我們可以計算一個角度的正餘弦值。兩個模式的不同點就是初始條件與終止條件的設置,相同點都是利用座標旋轉來實現的。這篇博客將結合向量模式的推到原理來進一步說明旋轉模式的推導過程。
本次實驗我們將使用MATLAB與FPGA同時利用CORDIC算法生成正弦波、餘弦波,本次實驗所用到的軟硬件工具如下:
1、VIVADO 2019.1
2、MATLAB 2015b
3、Modelsim 10.7
旋轉模式的推導過程
CORDIC算法旋轉模式和向量模式都是不停的對座標進行旋轉,不一樣的是向量模式我們的角度變化Z的初值是0,目標是爲了將縱座標軸Y的值經過多次旋轉之後變成0,然後通過X的最終值可以求解出,通過Z的最終值可以求解出。其中包含的數學關係如下:
上面的式子變化由上一篇博客的推導過程我們可以很容易得到。
與向量模式不同,旋轉模式的可以求解的兩個量是,z的初始條件是,終止條件是z經過多次旋轉之後變成0。然後我們從整體上看可以把次的旋轉看成1次旋轉,這次旋轉就是相當於對原來的座標旋轉了度,所以對應於數學關係如下:
所以只要我們的,那麼上式就變成了:
那麼我們可以看出經過座標旋轉的初始條件和旋轉條件的設置,我們最終可以求解到。這裏我們沒有對旋轉模式情況下的推導過程一步步的講解,而是結合向量模式下的推導過程,把旋轉模式下的n次旋轉看成1次旋轉一步得到n習次旋轉之後的表達式,然後設置初始條件左中可以獲得的值。
這裏需要特別注意旋轉模式與向量模式旋轉的角度不一致,旋轉模式我們是默認逆時針旋轉進行推導,向量模式我們默認是順時針旋轉進行推導。
MATLAB仿真
MATLAB代碼如下:
clc;
clear all;
Phase = 0:359;
Phase = [Phase,Phase,Phase];
rot = [2949120;1740992;919872;466944;234368;117312;58688;29312;14656;7360;3648;1856;896;448;256;128];
Pipeline = 16;
K = 39796; %K=0.607253*2^16,32'h09b74,
x = zeros(Pipeline+1,1);
y = zeros(Pipeline+1,1);
z = zeros(Pipeline+1,1);
cose = zeros(length(Phase),1);
sine = zeros(length(Phase),1);
zzz = zeros(length(Phase),1);
for i = 1:length(Phase)
x(1) = K;
y(1) = 0;
if(Phase(i) <= 90)
z(1) = Phase(i)*2^16;
elseif(Phase(i) > 90 && Phase(i) <= 180)
z(1) = (Phase(i)-90)*2^16;
elseif(Phase(i) > 180 && Phase(i) <= 270)
z(1) = (Phase(i)-180)*2^16;
else
z(1) = (Phase(i)-270)*2^16;
end
for j = 1:Pipeline
if(z(j)>0)
x(j+1) = x(j) - floor(y(j)*(2^-(j-1)));
y(j+1) = y(j) + floor(x(j)*(2^-(j-1)));
z(j+1) = z(j) - rot(j);
else
x(j+1) = x(j) + floor(y(j)*(2^-(j-1)));
y(j+1) = y(j) - floor(x(j)*(2^-(j-1)));
z(j+1) = z(j) + rot(j);
end
end
zzz(i) = z(17);
if(Phase(i) <= 90)
cose(i) = x(17);
sine(i) = y(17);
elseif(Phase(i) > 90 && Phase(i) <= 180)
cose(i) = -y(17);
sine(i) = x(17);
elseif(Phase(i) > 180 && Phase(i) <= 270)
cose(i) = -x(17);
sine(i) = -y(17);
else
cose(i) = y(17);
sine(i) = -x(17);
end
end
figure(1)
plot(cose,'r');
hold on
plot(sine,'g');
MATLAB仿真結果如下:
從上面結果可以看出我們實驗的正確性。我們利用了CORDIC算法通過計算累加的相位完成了正餘弦波形的計算。
FPGA代碼
我們將完全按照FPGA代碼的書寫進行Verilog代碼的編寫,並且在Modelsim中進行仿真驗證。
Cordic_Test模塊:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website : https://blog.csdn.net/zhangningning1996
// Module Name : Cordic_Test.v
// Create Time : 2020-06-15 16:06:58
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module Cordic_Test(
input sclk ,
input rst_n ,
input [31:0] phase ,
input phase_en ,
output reg [31:0] cose ,
output reg [31:0] sine ,
output wire data_en
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter PIPELINE = 16-1;
parameter K = 39796;
reg signed [31:0] rot[15:0] ;
reg signed [31:0] x[16:0] ;
reg signed [31:0] y[16:0] ;
reg signed [31:0] z[16:0] ;
reg [17:0] phase_en_delay ;
reg [ 1:0] quad[17:0] ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
initial begin
rot[0] <= 32'd2949120;
rot[1] <= 32'd1740992;
rot[2] <= 32'd919872;
rot[3] <= 32'd466944;
rot[4] <= 32'd234368;
rot[5] <= 32'd117312;
rot[6] <= 32'd58688;
rot[7] <= 32'd29312;
rot[8] <= 32'd14656;
rot[9] <= 32'd7360;
rot[10] <= 32'd3648;
rot[11] <= 32'd1856;
rot[12] <= 32'd896;
rot[13] <= 32'd448;
rot[14] <= 32'd256;
rot[15] <= 32'd128;
end
assign data_en = phase_en_delay[16];
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
z[0] <= 32'd0;
else if(phase <= 90 && phase_en == 1'b1)
z[0] <= phase << 16;
else if(phase > 90 && phase <= 180 && phase_en == 1'b1)
z[0] <= (phase - 90) << 16;
else if(phase > 180 && phase <= 270 && phase_en == 1'b1)
z[0] <= (phase - 180) << 16;
else if(phase_en == 1'b1)
z[0] <= (phase - 270) << 16;
else
z[0] <= z[0];
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
quad[0] <= 2'b00;
else if(phase <= 90 && phase_en == 1'b1)
quad[0] <= 2'b00;
else if(phase > 90 && phase <= 180 && phase_en == 1'b1)
quad[0] <= 2'b01;
else if(phase > 180 && phase <= 270 && phase_en == 1'b1)
quad[0] <= 2'b10;
else if(phase_en == 1'b1)
quad[0] <= 2'b11;
else
quad[0] <= quad[0];
genvar i;
generate
for (i=0; i < 17; i=i+1)
always @(posedge sclk or negedge rst_n)
quad[i+1] <= quad[i];
endgenerate
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)begin
x[0] <= K;
y[0] <= 0;
end else if(phase_en == 1'b1)begin
x[0] <= K;
y[0] <= 0;
end else begin
x[0] <= x[0];
y[0] <= y[0];
end
generate
for (i=0; i < 16; i=i+1)
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0) begin
x[i+1] <= 32'd0;
y[i+1] <= 32'd0;
z[i+1] <= 32'd0;
end else if(z[i] > 0)begin
x[i+1] <= x[i] - (y[i] >>> i);
y[i+1] <= y[i] + (x[i] >>> i);
z[i+1] <= z[i] - rot[i];
end else begin
x[i+1] <= x[i] + (y[i] >>> i);
y[i+1] <= y[i] - (x[i] >>> i);
z[i+1] <= z[i] + rot[i];
end
endgenerate
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0) begin
cose <= 32'd0;
sine <= 32'd0;
end else if(quad[16] == 2'b00) begin
cose <= x[16];
sine <= y[16];
end else if(quad[16] == 2'b01)begin
cose <= -y[16];
sine <= x[16];
end else if(quad[16] == 2'b10)begin
cose <= -x[16];
sine <= -y[16];
end else if(quad[16] == 2'b11) begin
cose <= y[16];
sine <= -x[16];
end else begin
cose <= cose;
sine <= sine;
end
always @(posedge sclk)
phase_en_delay <= {phase_en_delay[16:0],phase_en};
endmodule
測試模塊的代碼,
Cordic_Test_tb:
`timescale 1 ps/ 1 ps
module Cordic_Test_tb;
// Inputs
reg CLK_50M;
reg RST_N;
reg [15:0] cnt;
reg [15:0] cnt_n;
reg [31:0] Phase;
reg [31:0] Phase_n;
wire [31:0] Sin;
wire [31:0] Cos;
wire [31:0] Error;
wire data_en;
Cordic_Test Cordic_Test_inst(
.sclk (CLK_50M ),
.rst_n (RST_N ),
.phase (Phase ),
.phase_en (RST_N ),
.cose (Cos ),
.sine (Sin ),
.data_en (data_en )
);
initial
begin
#0 CLK_50M = 1'b0;
#10000 RST_N = 1'b0;
#10000 RST_N = 1'b1;
#1000000000 $stop;
end
always #10000
begin
CLK_50M = ~CLK_50M;
end
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
cnt <= 1'b0;
else
cnt <= cnt_n;
end
always @ (*)
begin
if(cnt == 16'd359)
cnt_n = 1'b0;
else
cnt_n = cnt + 1'b1;
end
//生成相位0-359度,Phase[17:16]爲相位的象限,Phase[15:10]爲相位的值
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
Phase <= 1'b0;
else
Phase <= cnt;
end
endmodule
仿真結果如下:
從上面MATLAB與Modelsim的聯合仿真驗證,從而證明了我們實驗的正確性。
小結
至此爲止,我們利用兩篇文章介紹了圓周系統的向量模式與旋轉模式,至於線性系統與雙曲線系統的兩種模式在這就不做過多的介紹,相信大家從這兩篇文章再結合參考文獻中的文章可以很輕鬆的寫出來這兩種系統的座標旋轉算法。
大家有沒有發現使用CORDIC產生正弦波比DDS要簡單的多。
總結
創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。或者對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣: