FPGA實戰--2FSK調製

首先了解一下2FSK的百度百科:(2ASK請直接看結尾)

FSK是信息傳輸中使用得較早的一種調製方式,它的主要優點是: 實現起來較容易,抗噪聲與抗衰減的性能較好。在中低速數據傳輸中得到了廣泛的應用。所謂FSK就是用數字信號去調製載波的頻率。如果是採用二進制調製信號,則稱爲2FSK;採用多進制調製信號,則稱爲MFSK。
l 調製方法:2FSK可看作是兩個不同載波頻率的ASK已調信號之和。
l 解調方法:相干法和非相干法。
l 類型:二進制移頻鍵控(2FSK),多進制移頻鍵控(MFSK)。
在上述三種基本的調製方法之外,隨着大容量和遠距離數字通信技術的發展,出現了一些新的問題,主要是信道的帶寬限制和非線性對傳輸信號的影響。在這種情況下,傳統的數字調製方式已不能滿足應用的需求,需要採用新的數字調製方式以減小信道對所傳信號的影響,以便在有限的帶寬資源條件下獲得更高的傳輸速率。這些技術的研究,主要是圍繞充分節省頻譜和高效率的利用頻帶展開的。多進制調製,是提高頻譜利用率的有效方法,恆包絡技術能適應信道的非線性,並且保持較小的頻譜佔用率。
從傳統數字調製技術擴展的技術有最小移頻鍵控MSK)、高斯濾波最小移頻鍵控GMSK)、正交幅度調製QAM)、正交頻分複用調製OFDM)等等。

我們需要怎麼做

本次實戰中,我們選用二進制頻移鍵控,原理和方法比較簡單粗暴,我們用一個僞隨機序列(M序列)來假裝按鍵,然後生成2個不同頻率正弦波,通過一個選通開關並口輸出,在使用並轉串芯片轉換實現2FSK的簡單實踐,下面我們來記錄實踐流程。

        首先是頂層文件(實踐中就是原理草圖,大概的實現原理)

從左到右分別是時鐘接口->分頻器->正弦波發生器/M序列發生器->開關選通(實驗中時鐘爲20M),下面是各個模塊代碼:

分頻器:(N代表分頻數,爲了讓結果清晰,所以M序列的分頻數很高,因爲要讓一個上升沿有好幾個週期才行)

module fenpin(clk_out,clk_in);
output clk_out;
input clk_in;
reg[13:0] cnt;
reg clk_out;
parameter N=1024;
always@(posedge clk_in)
begin
  begin
    if(cnt==N/2-1)
    begin clk_out<=!clk_out;
    cnt<=0;
    end else
    cnt<=cnt+1;
  end
end
endmodule

仿真結果:


M序列發生器:

module MXL(clk ,out);
input clk;
output out;
reg[3:0] tmp=4'b0;
reg out;
always @(posedge clk )
begin
if(tmp > 4'd15)
tmp=4'd0;
else tmp=tmp+1'b1;
case(tmp)
4'd0:out<=0;
4'd1:out<=1;
4'd2:out<=0;
4'd3:out<=0;
4'd4:out<=1;
4'd5:out<=1;
4'd6:out<=0;
4'd7:out<=1;
4'd8:out<=1;
4'd9:out<=0;
4'd10:out<=1;
4'd11:out<=0;
4'd12:out<=0;
4'd13:out<=0;
4'd14:out<=0;
4'd15:out<=0;
endcase
end
endmodule

仿真結果:



重點,正弦波發生器:(這是這個實驗難點,需要使用IP,所謂正弦波發生器,就是計數器+ram核,將正弦波抽樣128個點,然後隨着計數器計數逐個輸出,ps,並口),調用IP核流程和mif文件的參數設置參考TOP文件,就是頂層文件圖。mif文件導入在ram核的創建中。下面也帶上C語言產生mif文件(也就是正弦波的序列)

內部結構圖:


C語言mif文件代碼(用VC或者devc++運行即可,摘自:點擊打開鏈接)這個代碼淺顯易懂,讀懂爲好。

#include <stdio.h>
#include <math.h>

#define PI 3.141592
#define DEPTH 128     /*數據深度,即存儲單元的個數*/
#define WIDTH 8       /*存儲單元的寬度*/

int main(void)
{
    int i,temp;
    float s;

    FILE *fp;
    fp = fopen("TestMif.mif","w");   /*文件名隨意,但擴展名必須爲.mif*/
    if(NULL==fp)
        printf("Can not creat file!\r\n");
    else
    {
        printf("File created successfully!\n");
        /*
        *    生成文件頭:注意不要忘了“;”
        */
        fprintf(fp,"DEPTH = %d;\n",DEPTH);
        fprintf(fp,"WIDTH = %d;\n",WIDTH);
        fprintf(fp,"ADDRESS_RADIX = HEX;\n");
        fprintf(fp,"DATA_RADIX = HEX;\n");
        fprintf(fp,"CONTENT\n");
        fprintf(fp,"BEGIN\n");

        /*
        * 以十六進制輸出地址和數據
        */
        for(i=0;i<DEPTH;i++)
        {
             /*週期爲128個點的正弦波*/ 
            s = sin(PI*i/64);   
            /*將-1~1之間的正弦波的值擴展到0-255之間*/ 
            temp = (int)((s+1)*255/2);
            /*以十六進制輸出地址和數據*/
            fprintf(fp,"%x\t:\t%x;\n",i,temp);
        }//end for
        
        fprintf(fp,"END;\n");
        fclose(fp);
    }
}

仿真結果:

選通開關代碼:

module KAIGUAN(din0,dout,din1,sel);
parameter N=12;
input[N-1:0] din0;
output[N-1:0] dout;
input[N-1:0] din1;
input sel;
wire[N-1:0] MW_din0l;
wire[N-1:0] MW_din1l;
reg[N-1:0] MW_dtempl;
always@(MW_din0l or MW_din1l or sel)
begin
  case(sel)
  1'd0:MW_dtempl=MW_din0l;
  default:MW_dtempl=MW_din1l;
  endcase
  end
assign dout=MW_dtempl;
assign MW_din0l=din0;
assign MW_din1l=din1;
endmodule

整體系統的仿真結果:

仿真成功!

下載到FPGA中接上示波器:(FFT中有兩個高峯,實驗成功,具體速率大家可以自己算哦)


2ASK比較簡單,至於要信號發生器的分頻器分頻數目一致,然後改任意一個波形發生器的mif文件(中心範圍縮小,可改代碼得,記得有個直流偏置),其他不用變。

過程寫的比較簡單粗暴,有問題可留言或者私信,我都會看的!





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章