matlab与quartus的联合数据交换(NCO与文件数据的混频处理)
文章目錄
- 背景
- 再次認(rèn)識(shí)關(guān)于DDS的來(lái)源
- 實(shí)際案例
- 官方資料閱讀(NCO IP core)
- 參數(shù)原理
- 通常的步驟
- 工程實(shí)例
- MATLAB生成波形txt文件
- IP配置
- 文件命令語(yǔ)法(官方提示)
- modelsim仿真
- 工程福利連接
背景
由于modelsm只能觀(guān)察時(shí)域波形,無(wú)法顯示數(shù)據(jù)的頻譜特性,并且對(duì)數(shù)據(jù)進(jìn)行分析、處理不夠方便,特別是在FPGA中設(shè)計(jì)數(shù)字濾波器時(shí),無(wú)法直接觀(guān)察濾波器的頻域響應(yīng)。另外書(shū)寫(xiě)激勵(lì)文件的時(shí)候,很難產(chǎn)生用戶(hù)所需要的具有任意信噪比的輸入信號(hào)。特別聲明,不要轉(zhuǎn)載本博主的所有blog,侵權(quán)必究,否則博主將關(guān)閉自己的所有blog。
再次認(rèn)識(shí)關(guān)于DDS的來(lái)源
實(shí)際案例
官方資料閱讀(NCO IP core)
參數(shù)原理
通常你可以使用IP工具接口來(lái)實(shí)施NCO的架構(gòu),包括基于ROM,CORDIC算法、和乘法器。另外IP工具會(huì)在你設(shè)置參數(shù)的時(shí)候提供可視化的時(shí)域和頻域圖像。設(shè)計(jì)者通常可以用NCO在通信領(lǐng)域,產(chǎn)生正交的IQ生成器。
輸出的兩個(gè)信號(hào),用補(bǔ)碼的形式給出。
正如上圖所示,上圖是官方給出的NCO的架構(gòu),其實(shí)可以看到,是不用于我們所認(rèn)知的DDS的,所以有很多人通常用DDS來(lái)認(rèn)知NCO,這個(gè)是不對(duì)的,對(duì)于IP核,我們只有從官方手冊(cè)中學(xué)習(xí),才能正確認(rèn)識(shí)到官方想表達(dá)的意思。
另外,我們需要注意的是實(shí)線(xiàn)部分是必須的,而虛線(xiàn)部分是可選的輸入?yún)?shù)。NCO的IP核函數(shù)允許你生成一種NCO架構(gòu),你可以創(chuàng)建你自定義的NCO,實(shí)施的效果你可以在NCO的圖形界面中看到。
正如上圖公式所示,你可以看到這個(gè)波形生成是由上述公式生成的,其中我們要注意的正是這些參數(shù)。
從生成的黑盒子模塊,我們可以看到,輸入接口phi_inc_i正是公式中的fO,也就是NCO架構(gòu)中左邊的第一個(gè)必須輸入的參數(shù)。
而例化中的 [15:0] freq_mod_i ,這個(gè)指的正是上圖中的Frequency Modulation中,這個(gè)是個(gè)可選項(xiàng)。
所以輸出波形的頻率正由[15:0] phi_inc_i;和[15:0] freq_mod_i一起累加構(gòu)成頻率。
上圖中的兩個(gè)公式,雖然官方介紹的是f0(phi_inc)是相位增量,而fFM是頻率,其實(shí)根據(jù)公式,我們可以看出,沒(méi)啥區(qū)別,都是作為頻率,既然官方這么叫,那也行吧。另外還有一個(gè)精度是角度精度,這個(gè)沒(méi)啥用,和相位精度保持一致即可,這里官方解釋的是:角度精度是將坐標(biāo)轉(zhuǎn)換為笛卡爾的極化坐標(biāo)轉(zhuǎn)換前的角度精度,那么我們就把它與相位精度保持一致即可。
正如上圖所示,我們還可以看到相位調(diào)制器參數(shù),這個(gè)也是個(gè)可選項(xiàng),它影響我們的初始相位,所以在黑盒子,我們可以看到
input [15:0] phase_mod_i;
正是代表的這個(gè)參數(shù)。
此外還有一個(gè)參數(shù)就是抖動(dòng),啥叫相位抖動(dòng),也就是說(shuō)會(huì)有某個(gè)相位這個(gè)參數(shù)的值是不確定的,會(huì)有左右漂移,從而導(dǎo)致幅度的不確定性。
在IP核的這里面可以設(shè)置,也就是說(shuō)我們可以設(shè)置相位噪聲。
從上面兩張圖中,我僅僅改變了抖動(dòng)大小,可以看到抖動(dòng)越大,信噪比越低,這一點(diǎn)特別是在輸出頻率比較高的情況下尤其明顯。注意,參數(shù)只是樣圖,請(qǐng)不要按照上面的參數(shù)設(shè)置。
至此,我已經(jīng)對(duì)主要的輸入?yún)?shù)進(jìn)行了徹底的講解了。
通常的步驟
首先配置參數(shù)
然后建立仿真,勾選仿真模型,并設(shè)置仿真用的語(yǔ)言,verilog。注意,如果不勾選仿真,那么在后續(xù)的仿真中,仿真是無(wú)法運(yùn)行的。
最后是生成IP
如上圖,會(huì)生成如上圖所示的這些文件。從上面,我們可以知道.v文件需要Quartus II綜合,它會(huì)添加到你的Quartus II工程中。另外qiq文件,也是需要添加入工程中的。另外_bb.v文件,是IP的黑盒子,當(dāng)使用第三方仿真工具的時(shí)候可以使用這個(gè)文件,來(lái)例化。cos_c.hex和cos_f.hex文件sin_c.hex和sin_f.hex文件,這四個(gè)文件是存儲(chǔ)初始化數(shù)據(jù)文件,以十六進(jìn)制。
- setting parameters
首先,對(duì)于算法的具體實(shí)現(xiàn)細(xì)節(jié),我就不展開(kāi)講了,因?yàn)楹芏嗾撐亩加袑?xiě)過(guò)(抄過(guò))。
好的,至此理論部分,我們已經(jīng)講解完畢,至于具體算法實(shí)現(xiàn)的細(xì)節(jié),比如CORDIC算法的原理,這些我就不講解了,很多論文已經(jīng)反反復(fù)復(fù)的抄過(guò)。
工程實(shí)例
MATLAB生成波形txt文件
%采用matlab進(jìn)行電路仿真,用于驗(yàn)證整個(gè)FPGA電路的工作過(guò)程及輸出結(jié)果是否滿(mǎn)足要求 %同時(shí)產(chǎn)生FPGA程序中需要使用到的正弦波采樣數(shù)據(jù),50M采樣率產(chǎn)生625KHZ的隨機(jī)相位的正弦信號(hào)。也就是說(shuō)一個(gè)周期可以采樣80個(gè)點(diǎn),已經(jīng)能夠非常好的顯示出正弦波形了。 %采用matlab進(jìn)行電路仿真,用于驗(yàn)證整個(gè)FPGA電路的工作過(guò)程及輸出結(jié)果是否滿(mǎn)足要求 %同時(shí)產(chǎn)生FPGA程序中需要使用到的正弦波采樣數(shù)據(jù) clc; clear; fi=625000; %輸入信號(hào)的頻率 fc=625000; %本振信號(hào)的頻率Fs=50000000; %采樣頻率 L=1024; %數(shù)據(jù)長(zhǎng)度 N=10; %量化位數(shù)% 產(chǎn)生輸入信號(hào) t=0:1/Fs:(1/Fs)*(L-1); %產(chǎn)生采樣頻率的時(shí)間序列 theta=rand()*2*pi; %產(chǎn)生一個(gè)隨機(jī)相位角度 si=sin(2*pi*fi*t+theta); %生成具隨機(jī)起始相位的正弦波輸入信號(hào)si=round(si*(2^(N-1)-1)); %10bit量化%產(chǎn)生本振信號(hào) sc=sin(2*pi*fc*t); %生成本振信號(hào) sc=round(sc*(2^(N-1)-1)); %10bit量化%仿真混頻輸出并畫(huà)圖 so=si.*sc; %混頻器輸出 sof=so-mean(so); %混頻器濾出直流分量后輸出 fso=abs(fft(so,L)); %求FFT變換的幅度值 %歸一化處理 sc=sc/max(abs(sc)); %本振信號(hào)的歸一化處理 si=si/max(abs(si)); %輸入信號(hào)的歸一化處理 so=so/max(abs(so)); %輸出信號(hào)的歸一化處理 sof=sof/max(abs(sof)); %混頻器輸出信號(hào)濾出直流分量后歸一化處理 fso=fso/max(fso); %FFT的幅度值歸一化處理 %轉(zhuǎn)換成相對(duì)于原點(diǎn)對(duì)稱(chēng)的信號(hào) fso=[fso(L/2+1:L),fso(1:L/2)]; %畫(huà)圖 m=[-L/2:1:(L/2-1)]*Fs/L*(10^(-6)); %生成頻率坐標(biāo)軸,單位為MHz t=t*(10^6) ; %生成時(shí)間坐標(biāo)軸,單位為us subplot(221);plot(t(1:L),si(1:L)); title('10bit量化后的輸入信號(hào)si','fontsize',8); subplot(222);plot(t(1:L),so(1:L)); title('20bit量化后的混頻輸出信號(hào)so','fontsize',8); subplot(223);plot(t(1:L),sof(1:L)); title('20bit濾出直流分量后的混頻輸出sof','fontsize',8); subplot(224);plot(m,fso); title('混頻輸出信號(hào)的幅頻響應(yīng)','fontsize',8);%將生成的輸入正弦信號(hào)的數(shù)據(jù),寫(xiě)入外部文本文件(sinin.txt)中 f_s=si/max(abs(si)); %歸一化處理 Q_s=round(f_s*(2^(N-1)-1)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %新建文本文件前,必須建好文件存放的目錄文件夾,否則出現(xiàn)提示信息: %??? 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);
關(guān)于以上部分代碼的解釋:
B_s=dec2bin(Q_s(k)+(Q_s(k)<0)*2^N,N); %Q_s小于0就為1,大于0就為0
由于dec2bin只能夠?qū)⒄麛?shù)轉(zhuǎn)換成二進(jìn)制,所以必須要判斷一下是否有負(fù)數(shù),如果有負(fù)數(shù),(Q_s(k)<0)的返回值就是1,如果是正數(shù),返回值就是0,也就是說(shuō),如果是負(fù)數(shù),那么就將原來(lái)的值加2^N ,就是其負(fù)數(shù)的補(bǔ)碼的二進(jìn)制。這一點(diǎn),我之前已經(jīng)寫(xiě)過(guò)。https://blog.csdn.net/ciscomonkey/article/details/87104636
頂層文件設(shè)計(jì)
module mix_top (rst,clk,din,s_oc,dout) ; input rst; //復(fù)位信號(hào),高電平有效 input clk; //數(shù)據(jù)采樣時(shí)鐘/FPGA系統(tǒng)時(shí)鐘,頻率為5MHz input [9:0] din; //輸入的625KHz單頻信號(hào) output [9:0] s_oc; //本地OC輸出的625KHz單頻信號(hào) output [19:0] dout; //輸出混頻濾波后的的1.25MHz單頻信號(hào)//實(shí)例化NCO IP核 wire reset_n,out_valid,clken; wire [15:0] phi_inc_i; //本地信號(hào)的相位 wire [15:0] phase_mod_i; wire [15:0] freq_mod_i; wire [9:0] oc_sin; //本地信號(hào)的輸出,默認(rèn)無(wú)符號(hào)assign reset_n = rst; //NCO的復(fù)位信號(hào)低電平有效assign phi_inc_i = 16'd0; //設(shè)置相位為0 assign phase_mod_i=16'd0; //設(shè)置相位為0 assign freq_mod_i=16'd819; //大約為624KHZ,當(dāng)然,有小數(shù)的話(huà)也只能舍棄。值本來(lái)應(yīng)該是819.2,其實(shí)我們可以從IP核里面的提示看出,叫我們相位增量設(shè)置為819,這里,我把頻率增量設(shè)置為819,相位增量設(shè)置為0,也一樣。assign clken = 1'b1; //設(shè)置時(shí)鐘允許信號(hào)始終有效assign s_oc = oc_sin; //將本振輸出信號(hào)送至模塊輸出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)); //乘法運(yùn)算實(shí)現(xiàn)混頻輸出 reg signed [19:0] mult=0; //有符號(hào)的混頻運(yùn)算結(jié)果 wire signed [9:0] s_din; //有符號(hào)的輸入數(shù)字信號(hào) wire signed [9:0] s_oc_sin; //有符號(hào)的本地輸出625KHzassign s_din = din; //將乘數(shù)轉(zhuǎn)換成有符號(hào)數(shù)運(yùn)算 assign s_oc_sin = oc_sin; //將乘數(shù)轉(zhuǎn)換成有符號(hào)數(shù)運(yùn)算always @(posedge clk or negedge rst)if (!rst)mult <= 20'd0;elsemult <= s_din * s_oc_sin; //轉(zhuǎn)換為有符號(hào)后,進(jìn)行乘法運(yùn)算//求均值 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個(gè)有符號(hào)數(shù)據(jù)加起來(lái),其實(shí)這里我要補(bǔ)充一點(diǎn)了,原書(shū)上寫(xiě)的是給輸入時(shí)鐘是5M,輸出625KHZ,所以剛好是8倍關(guān)系,那么也就是一個(gè)周期8個(gè)點(diǎn)。但是,這里我們的時(shí)鐘是50MHz,我們本來(lái)應(yīng)該是去平均值80個(gè)點(diǎn),寄存80個(gè),才能求出平均值。這里我就不管那么多啦,大家明白即可。畢竟要寫(xiě)80個(gè)點(diǎn)平均值,有點(diǎn)懶得寫(xiě)。 assign mean = madd[22:3]; //代表將8加起來(lái)的數(shù)據(jù)左移3位,相當(dāng)于除以8//濾出直流分量(均值) assign mt = mult -mean; //濾出去直流分量 assign dout = mt; endmodule這里為什么要減去直流分量呢,當(dāng)然是因?yàn)榛祛l后626KHZ-625KHZ=0KHZ,那么就會(huì)產(chǎn)生直流分量,所以必須要減去直流分量。此外,還要注意的是,你試圖計(jì)算一下頻率增量,如果要在16位,50M時(shí)鐘的情況下產(chǎn)生NCO,那么根本沒(méi)法算出一個(gè)625KHZ的正弦,算出來(lái),頻率增量,我們應(yīng)該取819.4,這里我就取819吧,這樣產(chǎn)生的就是一個(gè)624點(diǎn)幾KHZ的正弦。也差不多吧,本來(lái)也有噪聲的,也會(huì)導(dǎo)致難免差一點(diǎn)點(diǎn)。這些東西差一點(diǎn)點(diǎn),也影響不大。
仿真文件:
// 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; //仿真數(shù)據(jù)長(zhǎng)度 parameter time_sim=data_num*clk_period; //仿真時(shí)間// assign statements (if any) mix_top i1 ( // port map - connection between master ports and signals/registers .clk(clk), //時(shí)鐘.din(din), //從文件讀取輸入的625KHz單頻信號(hào).dout(dout), // 輸出混頻濾波后的的1.25MHz單頻信號(hào) .rst(rst), //復(fù)位.s_oc(s_oc) //本地NCO產(chǎn)生輸出的625KHz單頻信號(hào) ); initial begin clk=0; rst=0; din=10'd10;//設(shè)置從文本中讀取輸入的625KHz單頻信號(hào)的初值 #50 rst=1;//設(shè)置仿真時(shí)間 #time_sim $stop;end //產(chǎn)生時(shí)鐘信號(hào) always #(clk_period/2) clk=~clk; //從外部TXT文件中讀入數(shù)據(jù)作為測(cè)試激勵(lì) reg [9:0] stimulus[1:data_num]; //用于存儲(chǔ)從文本中讀取的數(shù)據(jù),全部存放于數(shù)組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單頻信號(hào)dout寫(xiě)入外部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; //將混頻后的數(shù)據(jù),轉(zhuǎn)換為有符號(hào)數(shù) assign dout_s=dout; assign clk_write=clk&(rst); //產(chǎn)生寫(xiě)入的時(shí)鐘信號(hào),復(fù)位狀態(tài)時(shí)候不寫(xiě)入數(shù)據(jù)always @ (posedge clk_write)$fdisplay(file_out,"%d",dout_s); //將混頻后輸出的有符號(hào)的數(shù)據(jù),寫(xiě)入file_out代表的out.txt文件中//將NCO產(chǎn)生的數(shù)據(jù)寫(xiě)入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產(chǎn)生的數(shù)據(jù)轉(zhuǎn)變?yōu)橛蟹?hào)數(shù)據(jù) always @(posedge clk_write)$fdisplay(file_nco,"%d",nco_s); endmoduleIP配置
調(diào)用NCO的IP核
然后點(diǎn)擊geinirate即可
最后生成成功。
最后,方可得出NCO成功生成并添加其IP。
仿真的過(guò)程主要包括了行為仿真和時(shí)序仿真,無(wú)論何種仿真均需要設(shè)計(jì)測(cè)試激勵(lì)文件,采用HDL代碼文件書(shū)寫(xiě)激勵(lì),且需要在激勵(lì)文件中將部分仿真結(jié)果數(shù)據(jù)寫(xiě)入外部的文本中,以方便matlab讀取數(shù)據(jù)做進(jìn)一步的仿真。
testbench中導(dǎo)入文本數(shù)據(jù)文件
文件命令語(yǔ)法(官方提示)
modelsim仿真
如上圖所示,可以看到混頻后輸出的波形差不多是1.24MHz的樣子,大差不差,存在誤差也正常,畢竟我們的NCO本來(lái)就是產(chǎn)生的近似625KHZ的信號(hào)。
下面,我們來(lái)仔細(xì)看看從modelsim中,我們還能獲取哪些知識(shí)。
首先,我們可以看到din,導(dǎo)入的數(shù)據(jù)是與文件中的數(shù)據(jù)完全一致的,
此外,我們可以看到,NCO產(chǎn)生的數(shù)據(jù),剛開(kāi)始需要一定的時(shí)鐘后,然后才能產(chǎn)生穩(wěn)定的波形。
此外,我們可以看到,寫(xiě)入數(shù)據(jù)文本與波形中的數(shù)據(jù)完全一致
我們看到noc_s的波形數(shù)據(jù)與文本上面的一致。
mult <= s_din * s_oc_sin; //轉(zhuǎn)換為有符號(hào)后,進(jìn)行乘法運(yùn)算
下面,我們?cè)賮?lái)看一下轉(zhuǎn)換為有符號(hào)后,進(jìn)行乘法運(yùn)算,乘法運(yùn)算所消耗的時(shí)鐘。
可以看到一個(gè)時(shí)鐘就可以完成乘法運(yùn)算。
另外采用8級(jí)流水線(xiàn),求平均值,然后減去平均值
可以看到移位操作在本時(shí)鐘周期以?xún)?nèi)就可以完成,所以,這就是說(shuō)移位操作符是非常的強(qiáng)大。
另外,我們?cè)賮?lái)看看減法操作,減法操作也是在本時(shí)鐘周期以?xún)?nèi)就可以完成。
工程福利連接
聯(lián)系QQ:1183699227 并附帶加友目的。
總結(jié)
以上是生活随笔為你收集整理的matlab与quartus的联合数据交换(NCO与文件数据的混频处理)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 虚拟机屏幕界面自适应调整
- 下一篇: matlab从图表中提取数据