目錄
FPGA産生2FSK信号(1)
一、2FSK介紹
1、相幹解調:
2、非相幹解調
二、FPGA生成2FSK方法
1、正弦ROM表産生
(1)生成mif檔案
(2)生成rom IP核并導入mif檔案
(3)生成計數器
(4)計數器和rom整合
2、數字基帶控制正弦ROM表
3、Modelsim仿真驗證
開發環境:
FPGA: cyclone iii
軟體:quartus ii13.1+modelsim,matlab2016b
語言:Verilog HDL
一、2FSK介紹
FSK是資訊傳輸中使用得較早的一種調制方式,它的主要優點是:實作起來較容易,抗噪聲與抗衰減的性能較好。國際電信聯盟(ITU)建議在傳輸速率低于1200b/s時采用2FSK體制,其在中低速資料傳輸中得到了廣泛的應用。所謂FSK就是用數字信号去調制載波的頻率。
調制方法:2FSK可看作是兩個不同載波頻率的ASK已調信号之和。
解調方法:相幹法和非相幹法。
2FSK示意圖
1、相幹解調:
相幹解調
2、非相幹解調
過零檢測
包絡檢波
二、FPGA生成2FSK方法
如圖所示,2FSK産生的方案,利用基帶信号控制DA的ROM表,進而實作FSK調試。
FPGA生成2FSK方案框圖
1、正弦ROM表産生
下面詳細講解下如何生成ROM表。
正弦ROM表應該有這樣的功能:輸入時鐘信号,輸出幅度值(數字)。然後輸出的幅度送給DA讓其輸出實際對應的模拟電壓信号。
正弦rom表功能圖
想要有這樣的功能,首先正弦rom表中要存儲正弦數值,以mif的形式導入到建立的rom IP核中;然後建立計數器使其根據時鐘信号生成位址,對應為rom表中資料的存儲位置。
正弦rom表内部結構
要想生成正弦rom表,首先要明确正弦的表達為:
,其三要素為幅度A,頻率w和相位
。幅度A在二進制中和位寬n有關
,頻率和一個周期的點數有關,相位這裡先不考慮。
正弦ROM表裡面存儲的點數,是根據DA輸出一點需要的頻率和要輸出的正弦頻率來确定。
正弦波示意圖
圖中一個點的頻率為f1,正弦波的頻率為f2,正弦波一共有16個點,那麼三個數之間的關系為f2=f1/16。這裡f1也叫做采樣率,也就是采樣率/(一個周期的點數)=這個周期對應的頻率。
這裡我的DA輸出頻率為2M,我想輸出的正弦波頻率為4k和12.5k,那麼需要rom表的點數為2000/4=300,和2000/12.5=160。
(1)生成mif檔案
利用matlab生成mif檔案,DA的位數為16位,單極性器件,是以這裡的mif檔案裡面正弦波的資料位寬要為16位,無符号型。
這裡需要注意的是信号的位寬為16位無符号數,那麼可以表示的信号範圍為0~2^16-1=65535,在設定信号的幅度A和直流分量的時候要保證不能溢出,比如當A=2^15,ADC=2^15的時候最大值為2^16會溢出。
F1=1; %信号的頻率
P1=0;%信号初始相位
Fs=300;%采樣頻率
N=300;%采樣點數為N
t=[0:1/Fs:(N-1)/Fs];%采樣時刻
ADC=2^15-1 ;%直流分量
A=2^15-1;%信号幅度
s=A*sin(2*pi*F1*t + pi*P1/180)+ADC;%生成信号
plot(s);%繪制圖形
fild = fopen('d:/DA_4k.mif','wt');%建立mif檔案
%寫入mif檔案檔案頭
fprintf(fild, '%s\n','WIDTH=16;');%位寬
fprintf(fild, '%s\n\n','DEPTH=300;');%深度
fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;');%位址格式
fprintf(fild, '%s\n\n','DATA_RADIX=UNS;');%資料格式
fprintf(fild, '%s\t','CONTENT');%位址
fprintf(fild, '%s\n','BEGIN');%
for i = 1:N
s2(i) = round(s(i)); %對小數四舍五入以取整
if s2(i)<0 %強制将負1置0,
s2(i) = 0;
end
fprintf(fild, '\t%g\t',i-1);%位址,從0開始編碼
fprintf(fild, '%s\t',':');
fprintf(fild, '%d',s2(i));
fprintf(fild, '%s\n',';');
end
fprintf(fild, '%s\n','END;');%位址
(2)生成rom IP核并導入mif檔案
打開工具欄的IP核生成助手
建立一個新的自定義的宏檔案
選擇memory裡面的ROM,然後檔案輸出位置要在project檔案下,直接在後面命名就可以。
寬度wide指的是mif中的位寬,這裡用的是16位,數量我們用的是300個,不能少于這個數量,是以這裡選擇用512個。
保持預設Next
選擇 mif檔案,要注意mif檔案也要拷貝放到工程目錄下,不然會造成在後面modelsim仿真的時候出現沒有波形的奇怪錯誤(這個bug,調了半天)。
保持預設Next
勾選inst初始化調用模闆。最後點選finish。
在project下打開inst檔案,複制到工程中就可以調用rom IP核。
sin_rom sin_rom_inst (
.address ( address_sig ),
.clock ( clock_sig ),
.q ( q_sig )
);
(3)生成計數器
計數器應該有這樣的功能:
1、向上計數和向下計數(updown);
2、計數開始資料(基數)輸入(data);
3、計數結果輸出(q);
4、進位輸入(carry in);
5、進位輸出(carry out);
6、載入基數(load);
7、時鐘輸入(clk);
計數器模型
我們想實作300個位址的尋址計數,那需要設定:計數開始值為300,向下計數,當300個初始值計完,産生進位cout這個信号給laod,讓其再次載入初始值300,進入下一輪的計數。
下面是具體的操作過程:
選擇數學運算中的參量化模拟庫(Library of parameterized modules)LPM_COUNTER,然後命名
資料位寬選擇9位的,因為是300個數,至少需要9位(2^9-1=511)來表示。選擇向下計數模式。
選擇進入輸出。和load配合保證下一輪的計數。
選擇同步load
保持預設,Next下一步。
選中conter_inst。
(4)計數器和rom整合
module DAROM_4k(
clk,
sinromout_A,
);
input clk;
output sinromout_A;
wire [15:0] sinromout_A;
wire cout_sig;
wire [8:0]addr_A;
conter conter_inst (
.clock ( clk ),
.data ( 9'd499),
.sload ( cout_sig ),
.cout (cout_sig),
.q ( addr_A)
);
sin_rom sin_rom_inst
(
.clock(clk),
.address(addr_A),
.q(sinromout_A)
);
endmodule
2、數字基帶控制正弦ROM表
基帶信号作為判斷的依據來控制正弦rom1和rom2的輸出,這裡使用assign語句來實作。
assign DA_SINROM=(baseband_data==1)?DAROM_12k5:DAROM_4k;
3、Modelsim仿真驗證
點選processing-start-start Test Bench Template Writer自動建立test Bench檔案
生成的檔案為project/simulation/modelsim下的.vt檔案,打開檔案把該檔案名修改成和頂層檔案相同的名字。
根據硬體實際情況,添加需要的時鐘和基帶信号。
點選Assignments-Settings,進入仿真設定界面,配置modelsim相關檔案。
進入simulation界面,更改配置入圖中所示,然後點選Test Benches。
選擇建立,然後點選圖中file name,在project/simulation/modelsim下選擇生成的vt檔案。
然後把檔案名字複制一下,粘貼到Test bench name,再點選Add。
點選OK
點選OK
點選RTL仿真。
生成了仿真波形圖,波形會頻率會随着基帶信号發生變化,實作調相功能。--成功
想生成上圖的正弦波形,右擊波形的左側,選擇Format-Analog(custom),根據自己的資料大小修改下最大值和最小值。