matlab与quartus的联合数据交换(NCO与文件数据的混频处理)
文章目錄
- 背景
- 再次認識關于DDS的來源
- 實際案例
- 官方資料閱讀(NCO IP core)
- 參數原理
- 通常的步驟
- 工程實例
- MATLAB生成波形txt文件
- IP配置
- 文件命令語法(官方提示)
- modelsim仿真
- 工程福利連接
背景
由于modelsm只能觀察時域波形,無法顯示數據的頻譜特性,并且對數據進行分析、處理不夠方便,特別是在FPGA中設計數字濾波器時,無法直接觀察濾波器的頻域響應。另外書寫激勵文件的時候,很難產生用戶所需要的具有任意信噪比的輸入信號。特別聲明,不要轉載本博主的所有blog,侵權必究,否則博主將關閉自己的所有blog。
再次認識關于DDS的來源
實際案例
官方資料閱讀(NCO IP core)
參數原理
通常你可以使用IP工具接口來實施NCO的架構,包括基于ROM,CORDIC算法、和乘法器。另外IP工具會在你設置參數的時候提供可視化的時域和頻域圖像。設計者通常可以用NCO在通信領域,產生正交的IQ生成器。
輸出的兩個信號,用補碼的形式給出。
正如上圖所示,上圖是官方給出的NCO的架構,其實可以看到,是不用于我們所認知的DDS的,所以有很多人通常用DDS來認知NCO,這個是不對的,對于IP核,我們只有從官方手冊中學習,才能正確認識到官方想表達的意思。
另外,我們需要注意的是實線部分是必須的,而虛線部分是可選的輸入參數。NCO的IP核函數允許你生成一種NCO架構,你可以創建你自定義的NCO,實施的效果你可以在NCO的圖形界面中看到。
正如上圖公式所示,你可以看到這個波形生成是由上述公式生成的,其中我們要注意的正是這些參數。
從生成的黑盒子模塊,我們可以看到,輸入接口phi_inc_i正是公式中的fO,也就是NCO架構中左邊的第一個必須輸入的參數。
而例化中的 [15:0] freq_mod_i ,這個指的正是上圖中的Frequency Modulation中,這個是個可選項。
所以輸出波形的頻率正由[15:0] phi_inc_i;和[15:0] freq_mod_i一起累加構成頻率。
上圖中的兩個公式,雖然官方介紹的是f0(phi_inc)是相位增量,而fFM是頻率,其實根據公式,我們可以看出,沒啥區別,都是作為頻率,既然官方這么叫,那也行吧。另外還有一個精度是角度精度,這個沒啥用,和相位精度保持一致即可,這里官方解釋的是:角度精度是將坐標轉換為笛卡爾的極化坐標轉換前的角度精度,那么我們就把它與相位精度保持一致即可。
正如上圖所示,我們還可以看到相位調制器參數,這個也是個可選項,它影響我們的初始相位,所以在黑盒子,我們可以看到
input [15:0] phase_mod_i;
正是代表的這個參數。
此外還有一個參數就是抖動,啥叫相位抖動,也就是說會有某個相位這個參數的值是不確定的,會有左右漂移,從而導致幅度的不確定性。
在IP核的這里面可以設置,也就是說我們可以設置相位噪聲。
從上面兩張圖中,我僅僅改變了抖動大小,可以看到抖動越大,信噪比越低,這一點特別是在輸出頻率比較高的情況下尤其明顯。注意,參數只是樣圖,請不要按照上面的參數設置。
至此,我已經對主要的輸入參數進行了徹底的講解了。
通常的步驟
首先配置參數
然后建立仿真,勾選仿真模型,并設置仿真用的語言,verilog。注意,如果不勾選仿真,那么在后續的仿真中,仿真是無法運行的。
最后是生成IP
如上圖,會生成如上圖所示的這些文件。從上面,我們可以知道.v文件需要Quartus II綜合,它會添加到你的Quartus II工程中。另外qiq文件,也是需要添加入工程中的。另外_bb.v文件,是IP的黑盒子,當使用第三方仿真工具的時候可以使用這個文件,來例化。cos_c.hex和cos_f.hex文件sin_c.hex和sin_f.hex文件,這四個文件是存儲初始化數據文件,以十六進制。
- setting parameters
首先,對于算法的具體實現細節,我就不展開講了,因為很多論文都有寫過(抄過)。
好的,至此理論部分,我們已經講解完畢,至于具體算法實現的細節,比如CORDIC算法的原理,這些我就不講解了,很多論文已經反反復復的抄過。
工程實例
MATLAB生成波形txt文件
%采用matlab進行電路仿真,用于驗證整個FPGA電路的工作過程及輸出結果是否滿足要求 %同時產生FPGA程序中需要使用到的正弦波采樣數據,50M采樣率產生625KHZ的隨機相位的正弦信號。也就是說一個周期可以采樣80個點,已經能夠非常好的顯示出正弦波形了。 %采用matlab進行電路仿真,用于驗證整個FPGA電路的工作過程及輸出結果是否滿足要求 %同時產生FPGA程序中需要使用到的正弦波采樣數據 clc; clear; fi=625000; %輸入信號的頻率 fc=625000; %本振信號的頻率Fs=50000000; %采樣頻率 L=1024; %數據長度 N=10; %量化位數% 產生輸入信號 t=0:1/Fs:(1/Fs)*(L-1); %產生采樣頻率的時間序列 theta=rand()*2*pi; %產生一個隨機相位角度 si=sin(2*pi*fi*t+theta); %生成具隨機起始相位的正弦波輸入信號si=round(si*(2^(N-1)-1)); %10bit量化%產生本振信號 sc=sin(2*pi*fc*t); %生成本振信號 sc=round(sc*(2^(N-1)-1)); %10bit量化%仿真混頻輸出并畫圖 so=si.*sc; %混頻器輸出 sof=so-mean(so); %混頻器濾出直流分量后輸出 fso=abs(fft(so,L)); %求FFT變換的幅度值 %歸一化處理 sc=sc/max(abs(sc)); %本振信號的歸一化處理 si=si/max(abs(si)); %輸入信號的歸一化處理 so=so/max(abs(so)); %輸出信號的歸一化處理 sof=sof/max(abs(sof)); %混頻器輸出信號濾出直流分量后歸一化處理 fso=fso/max(fso); %FFT的幅度值歸一化處理 %轉換成相對于原點對稱的信號 fso=[fso(L/2+1:L),fso(1:L/2)]; %畫圖 m=[-L/2:1:(L/2-1)]*Fs/L*(10^(-6)); %生成頻率坐標軸,單位為MHz t=t*(10^6) ; %生成時間坐標軸,單位為us subplot(221);plot(t(1:L),si(1:L)); title('10bit量化后的輸入信號si','fontsize',8); subplot(222);plot(t(1:L),so(1:L)); title('20bit量化后的混頻輸出信號so','fontsize',8); subplot(223);plot(t(1:L),sof(1:L)); title('20bit濾出直流分量后的混頻輸出sof','fontsize',8); subplot(224);plot(m,fso); title('混頻輸出信號的幅頻響應','fontsize',8);%將生成的輸入正弦信號的數據,寫入外部文本文件(sinin.txt)中 f_s=si/max(abs(si)); %歸一化處理 Q_s=round(f_s*(2^(N-1)-1)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %新建文本文件前,必須建好文件存放的目錄文件夾,否則出現提示信息: %??? Error using ==> fprintf %Invalid file identifier fid=fopen('D:\quartus_Project\Liruifeng_tem\DO_Pro\CP2\CP_2_4_matlab_alt_mixNCO\sin.txt','w'); for k=1:length(Q_s)B_s=dec2bin(Q_s(k)+(Q_s(k)<0)*2^N,N); %Q_s小于0就為1,大于0就為0%k;for j=1:Nif B_s(j)=='1'tb=1;elsetb=0;endfprintf(fid,'%d',tb); endfprintf(fid,'\r\n'); end fprintf(fid,';'); fclose(fid);
關于以上部分代碼的解釋:
B_s=dec2bin(Q_s(k)+(Q_s(k)<0)*2^N,N); %Q_s小于0就為1,大于0就為0
由于dec2bin只能夠將整數轉換成二進制,所以必須要判斷一下是否有負數,如果有負數,(Q_s(k)<0)的返回值就是1,如果是正數,返回值就是0,也就是說,如果是負數,那么就將原來的值加2^N ,就是其負數的補碼的二進制。這一點,我之前已經寫過。https://blog.csdn.net/ciscomonkey/article/details/87104636
頂層文件設計
module mix_top (rst,clk,din,s_oc,dout) ; input rst; //復位信號,高電平有效 input clk; //數據采樣時鐘/FPGA系統時鐘,頻率為5MHz input [9:0] din; //輸入的625KHz單頻信號 output [9:0] s_oc; //本地OC輸出的625KHz單頻信號 output [19:0] dout; //輸出混頻濾波后的的1.25MHz單頻信號//實例化NCO IP核 wire reset_n,out_valid,clken; wire [15:0] phi_inc_i; //本地信號的相位 wire [15:0] phase_mod_i; wire [15:0] freq_mod_i; wire [9:0] oc_sin; //本地信號的輸出,默認無符號assign reset_n = rst; //NCO的復位信號低電平有效assign phi_inc_i = 16'd0; //設置相位為0 assign phase_mod_i=16'd0; //設置相位為0 assign freq_mod_i=16'd819; //大約為624KHZ,當然,有小數的話也只能舍棄。值本來應該是819.2,其實我們可以從IP核里面的提示看出,叫我們相位增量設置為819,這里,我把頻率增量設置為819,相位增量設置為0,也一樣。assign clken = 1'b1; //設置時鐘允許信號始終有效assign s_oc = oc_sin; //將本振輸出信號送至模塊輸出nco nco_inst(.phi_inc_i(phi_inc_i),.freq_mod_i(freq_mod_i),.phase_mod_i(phase_mod_i),.clk(clk),.reset_n(reset_n),.clken(clken),.fsin_o(oc_sin),.out_valid(out_valid)); //乘法運算實現混頻輸出 reg signed [19:0] mult=0; //有符號的混頻運算結果 wire signed [9:0] s_din; //有符號的輸入數字信號 wire signed [9:0] s_oc_sin; //有符號的本地輸出625KHzassign s_din = din; //將乘數轉換成有符號數運算 assign s_oc_sin = oc_sin; //將乘數轉換成有符號數運算always @(posedge clk or negedge rst)if (!rst)mult <= 20'd0;elsemult <= s_din * s_oc_sin; //轉換為有符號后,進行乘法運算//求均值 reg signed [19:0] m1,m2,m3,m4,m5,m6,m7; always @(posedge clk or negedge rst)if (!rst)beginm1 <= 20'd0;m2 <= 20'd0;m3 <= 20'd0;m4 <= 20'd0;m5 <= 20'd0;m6 <= 20'd0;m7 <= 20'd0;endelsebeginm1 <= mult;m2 <= m1;m3 <= m2;m4 <= m3;m5 <= m4;m6 <= m5; m7 <= m6;end wire signed [22:0] madd; wire signed [19:0] mean,mt; assign madd = mult+m1+m2+m3+m4+m5+m6+m7; //代表將8個有符號數據加起來,其實這里我要補充一點了,原書上寫的是給輸入時鐘是5M,輸出625KHZ,所以剛好是8倍關系,那么也就是一個周期8個點。但是,這里我們的時鐘是50MHz,我們本來應該是去平均值80個點,寄存80個,才能求出平均值。這里我就不管那么多啦,大家明白即可。畢竟要寫80個點平均值,有點懶得寫。 assign mean = madd[22:3]; //代表將8加起來的數據左移3位,相當于除以8//濾出直流分量(均值) assign mt = mult -mean; //濾出去直流分量 assign dout = mt; endmodule這里為什么要減去直流分量呢,當然是因為混頻后626KHZ-625KHZ=0KHZ,那么就會產生直流分量,所以必須要減去直流分量。此外,還要注意的是,你試圖計算一下頻率增量,如果要在16位,50M時鐘的情況下產生NCO,那么根本沒法算出一個625KHZ的正弦,算出來,頻率增量,我們應該取819.4,這里我就取819吧,這樣產生的就是一個624點幾KHZ的正弦。也差不多吧,本來也有噪聲的,也會導致難免差一點點。這些東西差一點點,也影響不大。
仿真文件:
// Copyright (C) 1991-2013 Altera Corporation // Your use of Altera Corporation's design tools, logic functions // and other software and tools, and its AMPP partner logic // functions, and any output files from any of the foregoing // (including device programming or simulation files), and any // associated documentation or information are expressly subject // to the terms and conditions of the Altera Program License // Subscription Agreement, Altera MegaCore Function License // Agreement, or other applicable license agreement, including, // without limitation, that your use is for the sole purpose of // programming logic devices manufactured by Altera and sold by // Altera or its authorized distributors. Please refer to the // applicable agreement for further details.// ***************************************************************************** // This file contains a Verilog test bench template that is freely editable to // suit user's needs .Comments are provided in each section to help the user // fill out necessary details. // ***************************************************************************** // Generated on "05/30/2019 16:24:44"// Verilog Test Bench template for design : mix_top // // Simulation tool : ModelSim (Verilog) // `timescale 1 ns/ 1 ns module mix_top_vlg_tst(); reg clk; reg [9:0] din; reg rst; // wires wire [19:0] dout; wire [9:0] s_oc;parameter clk_period=20; //20ns parameter data_num=800; //仿真數據長度 parameter time_sim=data_num*clk_period; //仿真時間// assign statements (if any) mix_top i1 ( // port map - connection between master ports and signals/registers .clk(clk), //時鐘.din(din), //從文件讀取輸入的625KHz單頻信號.dout(dout), // 輸出混頻濾波后的的1.25MHz單頻信號 .rst(rst), //復位.s_oc(s_oc) //本地NCO產生輸出的625KHz單頻信號 ); initial begin clk=0; rst=0; din=10'd10;//設置從文本中讀取輸入的625KHz單頻信號的初值 #50 rst=1;//設置仿真時間 #time_sim $stop;end //產生時鐘信號 always #(clk_period/2) clk=~clk; //從外部TXT文件中讀入數據作為測試激勵 reg [9:0] stimulus[1:data_num]; //用于存儲從文本中讀取的數據,全部存放于數組stimulus中 integer address=0; initial begin $readmemb("sin.txt",stimulus);//文件必須放到simulation\modelsim的文件夾中repeat(data_num) beginaddress=address+1;din=stimulus[address];#clk_period;end end //將混頻濾波后的的1.25MHz單頻信號dout寫入外部TXT文件中(out.txt)integer file_out; initial begin file_out=$fopen("out.txt");//文件必須放到simulation\modelsim的文件夾中if(!file_out)begin$display("could not open file!");$finish;end endwire clk_write; wire signed[19:0] dout_s; //將混頻后的數據,轉換為有符號數 assign dout_s=dout; assign clk_write=clk&(rst); //產生寫入的時鐘信號,復位狀態時候不寫入數據always @ (posedge clk_write)$fdisplay(file_out,"%d",dout_s); //將混頻后輸出的有符號的數據,寫入file_out代表的out.txt文件中//將NCO產生的數據寫入NCO.txt文件中 integer file_nco; initial begin//文件必須放到simulation\modelsim的文件夾中 file_nco = $fopen("nco.txt");if(!file_nco)begin$display("could not open file!");$finish;end end wire signed [9:0] nco_s; assign nco_s = s_oc;//將NCO產生的數據轉變為有符號數據 always @(posedge clk_write)$fdisplay(file_nco,"%d",nco_s); endmoduleIP配置
調用NCO的IP核
然后點擊geinirate即可
最后生成成功。
最后,方可得出NCO成功生成并添加其IP。
仿真的過程主要包括了行為仿真和時序仿真,無論何種仿真均需要設計測試激勵文件,采用HDL代碼文件書寫激勵,且需要在激勵文件中將部分仿真結果數據寫入外部的文本中,以方便matlab讀取數據做進一步的仿真。
testbench中導入文本數據文件
文件命令語法(官方提示)
modelsim仿真
如上圖所示,可以看到混頻后輸出的波形差不多是1.24MHz的樣子,大差不差,存在誤差也正常,畢竟我們的NCO本來就是產生的近似625KHZ的信號。
下面,我們來仔細看看從modelsim中,我們還能獲取哪些知識。
首先,我們可以看到din,導入的數據是與文件中的數據完全一致的,
此外,我們可以看到,NCO產生的數據,剛開始需要一定的時鐘后,然后才能產生穩定的波形。
此外,我們可以看到,寫入數據文本與波形中的數據完全一致
我們看到noc_s的波形數據與文本上面的一致。
mult <= s_din * s_oc_sin; //轉換為有符號后,進行乘法運算
下面,我們再來看一下轉換為有符號后,進行乘法運算,乘法運算所消耗的時鐘。
可以看到一個時鐘就可以完成乘法運算。
另外采用8級流水線,求平均值,然后減去平均值
可以看到移位操作在本時鐘周期以內就可以完成,所以,這就是說移位操作符是非常的強大。
另外,我們再來看看減法操作,減法操作也是在本時鐘周期以內就可以完成。
工程福利連接
聯系QQ:1183699227 并附帶加友目的。
總結
以上是生活随笔為你收集整理的matlab与quartus的联合数据交换(NCO与文件数据的混频处理)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 虚拟机屏幕界面自适应调整
- 下一篇: ubuntu18.04安装VCS+ver