2ASK调制解调
? ? ? ? ASK調制解調中,調制信號為二進制數字信號(2ASK),載波幅度僅有兩種狀態變化,發送的信號上沒有載波時表示發送的碼元0,信號上有載波時發送的碼元1,可看作一個單極性的脈沖序列和一個載波相乘。
2ASK信號調制模型:
2ASK信號解調模型:
?由整流電路對輸入信號取整,將交流信號轉換成直流信號,低通濾波器濾出基帶信號的包絡,經判決輸出,完成解調。
FPGA 端的實驗框圖:
????????發送端:由ARM將數據傳入DDR,通過DMA進行數據讀取并進行并串轉換,再由tx_ask進行調制,將調制后的信號送入AD9361經PA后發送出去;
? ? ? ? 接收端:AD9361接收到的數據送入rx_fir進行整流以及濾波,再由mean模型進行均值平滑濾波器以消除噪聲干擾,bitsync模塊進行數據同步,判決輸出,將接收到的模擬信號轉為數字信號,由串并轉換將數據恢復成8位有效數據,通過DMA寫回DDR,ARM端用串口將數據返回至上位機,由上位機進行解調正確性的判斷。
????????實驗采用AD9361+zynq 框架實現,首先需要搭建基于AD9361 的收發器框架。
1、AD9361 PL側框架搭建
????????AD9361框架圖:
?1T1R和2T2R讀寫時序圖:
?????????1T1R模式需要兩個時鐘才能完整的接收完一個 12 位的數據,根據data_clk 和 rx_frame 信號先接收 I Q 路數據的高 6 位,再接收低 6 位;
? ? ? ? 2T2R模型需要四個時鐘才能完整接收完一個12位數據,在rx_frame 信號為高時,接收1個通道數據,為低時接收另一個通道數據;需要注意的是,rx_frame為高時,接收的是兩個通道的高6位,反之接收低6位數據;
? ? ? ? AD9361接口模塊設計框圖:
RX 鏈路:IBUFDS -> IDELAY -> IDDR ->RX_CHANNEL_IQ
TX 鏈路:TX_CHANNEL_IQ -> ODDR -> OBUFDS
IBUFDS和OBUFDS進行單端信號與差分信號的相互轉換,因為FPGA無法處理差分信號;
IDDR和ODDR進行單沿與雙沿采樣數據的轉換;
IDELAY用于動態調制接收數據與時鐘的延遲;
RX_CHANNEL_IQ 和 TX_CHANNEL_IQ 是對RX 和 TX數據的解析,提取1T1R和2T2R模式下的? I /Q 路數據;
FPGA系統搭建:
2、ASK信號的調制
? ? ? ? ?調制原理:發送的數據為0,則輸出0;發送的數據為1,則輸出載波信號,即正余弦信號。
????????參數:采樣時鐘 40MHZ,數據頻率100Kbps,載波頻率1.25MHZ,每個載波周期內采樣點數 40/1.25=32個,每個數據周期內有 40/0.1=400個采樣點
????????模塊設計思路:調制模塊內部需要先聲明兩個數組存放sin和cos對應的數據;通過計數器,在采樣時鐘作用下,從0~32進行循環計數,模塊每輸入一個數進行一次判斷;當輸入數據為0,輸出0;輸入數據為1,輸出sin 和cos數組內與當前計數器對應的值。
使用MATLBA生成 sin 和 cos 數組:
t = 1:1/32:1; y1 = 255 * sin(2*pi*t); y2 = 255 * cos(2*pi*t); y1 = round(y1); y2 = round(y2); file = fopen('data.txt','w'); fprintf(file,'%d, ',y1); fprintf(file,'\n'); fprintf(file,'%d, ',y2); fclose(file);HLS實現tx_ask模塊:
void tx_ask(ap_uint<1> data_in, ap_int<12> *sin, ap_int<12> *cos){ap_int<12> cos_table[32] ={255 ,250 ,236 ,212 ,180 ,142 ,98 ,50 ,0 ,- 50 ,-98 ,-142 ,-180 ,-212 ,-236 ,-250 ,-255 ,-250 ,-236 ,-212 ,-180 ,-142 ,-98 ,-50 ,0 ,50 ,98 ,142 ,180 ,212 ,236 ,250};ap_int<12> sin_table[32] ={0 ,50 ,98 ,142 ,180 ,212 ,236 ,250 ,255 ,250 ,236 ,212 ,180 ,142 ,98 ,50 ,0 ,-50 ,-98 ,-142 ,-180 ,-212 ,-236 ,-250 ,-255 ,-250 ,-236 ,-212 ,-180 ,-142 ,-98 ,-50};if(data_in == 1){*sin = sin_table[count.range(4, 0)];*cos = cos_table[count.range(4, 0)]; } else {*sin=0;*cos=0; }count ++;if(count == 32) {count =0; } } }3、接收鏈路rx_fir 模塊實現
????????先進行abs()函數取絕對值進行整流,再由FIR低通濾波,濾除高頻載波信號。
? ? ? ? fir參數設置:采樣率40MHZ,54階低通濾波器,Hamming窗,通帶頻率100K;
?
?
void rx_ask (ap_int<20> *y,ap_int<12> x) {const ap_int<8> c[54] = {1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18, 18, 17, 17, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 7, 6, 5, 4, 3, 3, 2, 2, 2, 1, 1 };static ap_int<12> shift_reg[54];ap_int<26> acc;ap_int<12> x_t;int i;acc=0;x_t = abs(x);Shift_Accum_Loop: for (i=54-1;i>=0;i--) {if (i==0) {acc+=x_t*c[0];shift_reg[0]=x_t; } else {shift_reg[i]=shift_reg[i-1];acc+=shift_reg[i]*c[i]; } }*y = acc.range(25,6); }?4、均值濾波
? ? ? ? 將連續輸入的相鄰的數進行累加求平均值,以濾除噪聲產生的毛刺,再送入同步模塊,使得其減少誤判。
void mean(ap_int<20> dina,ap_int<20> *dout){static ap_int<20> shift_reg[16];ap_int<24> acc;acc =0;int i;Shift_Accum_Loop:for(i=16-1;i>=0;i--){if(i==0) {shift_reg[0] = dina;acc += dina;}else{shift_reg[i]=shift_reg[i-1];acc+=shift_reg[i];}}*dout=acc.range(23, 4); //div 16dout =0; }5、判決輸出
????????包絡檢波輸出基帶波形后,需要將其進行判決轉換為二進制,因此要考慮判決門限的大小和符號采樣問題,保證門限判決的正確性和只對每一位符號判決后的二進制值采樣一次。
? ? ? ? 數據幀結構:
????????工作流程:
? ? ? ? ?當輸入值增大,則認為有數據輸入,但也需要排除噪聲干擾的情況,所以對輸入值求均值,當均值大于門限值,可判定有數據輸入,可進行符號判決;利用FIFO進行數據延拍,以便在最佳采樣點采集到穩定數據。
? ? ? ? ?判決門限:
? ? ? ? 輸入數據大于門限值,判定數據為1;輸入數據小于門限值,判定數據為0;
? ? ? ? 符號判決:
? ? ? ? 保證一個符號周期內,只對符號采樣一次,且在判決后的二進制數據的正中間時刻采樣;
? ? ? ? 判斷幀頭:
? ? ? ? 幀頭由巴克碼和定界符組成,利用序列檢測器即可實現。
? ? ? ? 檢測到幀頭后,可提取LEN信息,得到數據的長度,以便得到裸數據,寫入DDR。
6、DMA實現
????????ARM端通過串口接收數據并寫入DDR,FPGA通過DMA將數據讀出送入調制部分;而解調部分則將數據通過DMA寫回DDR,由ARM返回給上位機。
?DMA IP:
?
?S_AXI_LITE:配置通道,axi_dma IP去DDR里面哪個地址空間,讀多少數據,由此接口配置讀取的地址及讀取數據的長度;S_AXI_LITE配置后之后啟動讀,就能夠從IP輸出端驅動 HP口讀取數據,中間需要經過協議轉換IP(interconnected);
M_AXI_MM2S輸出的是從DDR存儲器中讀出要發送的數據,該數據需要通過自定義緩存模塊(s_axis_rd)進行數據位寬轉換(64bit->8bit)和跨時鐘域處理,每次緩存一幀突發數據;
M_AXI_S2MM輸出的數據同樣需要通過自定義緩存模塊(m_axis_wr)進行數據位寬轉換(8bit->64bit)和跨時鐘域處理,緩存完一幀突發長度時進行寫操作,將解調數據寫入DDR;
? ? ? ? 解決輸入數據長度不為 8字節整數倍的問題:
? ? ? ? 因為總數據長度不可知,當不為8字節整數倍時需要插入無效字節,使得FIFO讀的時候可以整體8字節讀出,便于FIFO讀空內部的數據。如果是8字節的整數倍的數據長度,其低三位為000;
如果不是8字節的整數倍,可以將數據長度的低三位取反再加1得到的值作為無效數據填充進FIFO內部。舉例:數據長度低三位為3'b011,余數為3,需要寫入5字節湊齊8字節,則將3'b011取反再加1,即得到3'b101,為十進制5。
總結
- 上一篇: MySQL的IFNULL() 函数使用
- 下一篇: 【一步一步学习spring】spring