DDS原理及FPGA實現

DDS原理及FPGA實現

一個按一定速度沿x軸行進,同時半徑按一定頻率在圓周上滑動的圓,最後留下的痕跡就是一個正餘弦波。

DDS全稱直接數字頻率合成(Direct Digital Synthesis),簡單來講,分以下幾步:

1.抽樣

既然是數字頻率合成,那麼從模擬信號變成數字信號的過程必不可少。這個過程就是抽樣的過程。根據奈奎斯特採樣定律,我們在採樣過程要保留源信號的信息,那麼採樣率至少爲源信號頻率的兩倍。換句話說,我們想要在數字合成出來的波形還能還原原始信號的信息的話,我們一個週期中至少要有兩個以上的“點”。

但一般來講,爲了波形的完整,我們一個週期中最少保留的點還會多一些。如果假設一個週期最小4個點,採樣頻率爲爲100MSPS,那我們可以還原的源信號的頻率最大爲25M

我們通常對一個週期採樣的點數爲2^N個,在這裏,我採樣爲2的8次方,即256個。

採樣的過程可以通過matlab進行模擬,設置好採樣的位寬和深度便可以生成採樣數據。

  width=10;   %rom的位寬
  depth=1024; %rom的深度
  x=linspace(0,2*pi,depth);  %在一個週期內產生1024個採樣點
  y_sin=sin(x);   %生成正弦數據
  y_sin=round(y_sin*(2^(width-1)-1))+2^(width-1)-1;  %將餘弦數據全部轉換爲整數
  
  fid=fopen('C:\Users\Leixx\Desktop\sin_txt.txt','w');  %創建.txt文件
  fprintf(fid,'%d;\n',y_sin);  %向.txt文件中寫入數據
  fclose(fid);  %關閉.txt文件

得到的部分採樣數據如下

511;
514;
517;
520;
524;
527;
530;
533;
536;
539;
542;
545;
549;
552;
555;
558;
561;
564;
567;
570;
574;
577;
580;
583;
586;
589;
592;
595;
598;
602;
605;
608;
611;
614;
617;
620;
623;
626;
629;
632;
635;
638;
641;
644;
647;
650;
653;
656;

2.合成

DDS技術的核心,簡單來說就是將我們的抽樣數據還原成模擬信號。還原的方式和文章講到的一樣:以一定的頻率將抽樣數據依次輸出,就可以還原波形。

假設,以100M的頻率輸出我們的1024個抽樣數據,則將會得到一個頻率爲
fout=100M/1024=97KHZ fout=100M/1024=97KHZ
的正弦波。這就達到了最初的信號輸出。

那如何調頻呢?

調頻的方案有兩種:一種是改變我們的時鐘頻率,將我們讀取抽樣數據的速度變快或者變慢,這樣就可以改變頻率。這種方法對於當下很多開發板固定的晶振頻率來說比較難以實現。

另一種方案就是減少我們輸出的抽樣數據,輸出的抽樣數據越少,按照上面的公式,頻率便會越高。

比如說,我們最開始查數據是按照依次加一的方式,那我們改成依次加二,顯然,這樣做之後,輸出頻率便會提高。但也會帶來一個問題,我們輸出的點數少了,那麼點與點之間不再平滑,輸出的波形會變得階梯化

顯然加一會得到一個頻率,加二會得到另一個頻率,但這兩個頻率都不是我想要的怎麼辦?

如何精準調頻?

假設我們需要得到一個頻率很低的信號,1KHZ,而我們的時鐘頻率爲100M,我們在一個週期內輸出1024個點也達不到這樣的頻率。因此我們就需要在輸出的每個數據之間進行等待,可以通過設置計數器來解決這個問題。爲了使輸出的信號儘可能的低,我們設置一個32位的累加器。將高10位作爲查表的地址。對於1KHZ,有
foutfword=fclk232 \frac{fout}{fword}=\frac{fclk}{2^{32}}
fword=232foutfclk fword=\frac{2^{32}*fout}{fclk}
所以,累加值fwordfword爲4295。

其餘頻率對應的累加值均可以按此公式計算。

如何解決階梯化?

從數字上來看,波形變得階梯化是因爲我們輸出的抽樣數據減少,點與點之間不再平滑。但是從另一個角度理解,波形變得階梯化的原因是因爲疊加了其他雜波

我們簡單地波形變得階梯化理解爲趨近於方波。下圖是方波的合成。
在這裏插入圖片描述
由方波的傅里葉級展開式
4AMAXπi=1sin((2n1)ωt)2n1n=1,2,3... \frac{4A_{MAX}}{\pi}\sum_{i=1}^\infty\frac{sin((2n-1)\omega t)}{2n-1} \qquad n=1,2,3...
可以得出,方波是由無數個奇次諧波疊加起來的,頻率爲2n-1倍,幅度爲4AMAX(2n1)π\frac{4A_{MAX}}{(2n-1)\pi}

因此,若我們的波形也是疊加了高頻的諧波導致波形階梯化,那麼就通過低通濾波器來濾除高頻諧波,得到平滑的波形。

DDS的原理圖如下:
在這裏插入圖片描述

3.實現

基於FPGA的DDS,就是按照上面的原理來實現的。

(1)儲存波形
reg [9:0] wave_sin_buf;
always @(*) begin
	case (addr)
		8'd0 : begin wave_sin_buf<=511; end
		8'd1 : begin wave_sin_buf<=514; end
		8'd2 : begin wave_sin_buf<=517; end
		8'd3 : begin wave_sin_buf<=520; end
		8'd4 : begin wave_sin_buf<=524; end
		8'd5 : begin wave_sin_buf<=527; end
		8'd6 : begin wave_sin_buf<=530; end
		8'd7 : begin wave_sin_buf<=533; end
		8'd8 : begin wave_sin_buf<=536; end
		8'd9 : begin wave_sin_buf<=539; end
		8'd10 : begin wave_sin_buf<=542; end
		8'd11 : begin wave_sin_buf<=545; end
		8'd12 : begin wave_sin_buf<=549; end
		8'd13 : begin wave_sin_buf<=552; end
		8'd14 : begin wave_sin_buf<=555; end
		8'd15 : begin wave_sin_buf<=558; end
		8'd16 : begin wave_sin_buf<=561; end
		8'd17 : begin wave_sin_buf<=564; end

我這裏只儲存了256個數據,至於原因,後面會講到。

(2)累加

設置一個32位相位控制字和頻率控制字,進行累加。

always @(posedge clk_165m or negedge rst_n) begin
    if (!rst_n) begin
        addr_r0 <= 0;
        addr_r1 <= 0;     
    end
    else begin
        addr_r0 <= addr_r0 + fre_word;  //N位累加器
        addr_r1 <= addr_r0 + pha_word;  //N位寄存器,帶相位偏移    
    end
end
(3)查表
/////查表,按照不同的相位////////
always @(*) begin
    case (addr_cache[9:8])
        2'b00:begin addr_r<=addr_cache[7:0]; end
        2'b01:begin addr_r<=addr_cache[7:0]^8'b1111_1111; end
        //異或可以求得原值的8位補值(原值與現值相加得到256)
        2'b10:begin addr_r<=addr_cache[7:0]; end
        2'b11:begin addr_r<=addr_cache[7:0]^8'b1111_1111; end 
        default: begin addr_r <= 8'd0; end
    endcase
end

這裏我只儲存了2^8個波形數據,是爲了節省寄存器資源。因爲一個週期的正弦波的四個相位實際上數據是有關聯的,知道第一相位的數據,便可推導出另外三個相位的數據

代碼中,00表示第一相位,此時按照正常的查表順序即可。

01表示第二相位,此時,查表的順序應當是2^8-地址值。但實際上這個減法的操作就是異或的操作。

相減後,地址值8位中原本的“1”變爲0,原本的“0”變爲1,正好和異或的原理相同。這裏爲了方便,就直接寫了異或。實際上寫256-addr_cache[7:0]也是一個效果。

其餘兩個相位,查表的方式類似。

(4)轉換

因爲我這裏的256個數據是第一相位的,而第三第四相位的數據是等於2^10減去第一相位的值,因此這裏需要將輸出的數據轉換一下。

reg [9:0]dac_data_r;
always @(*) begin
	case (addr_cache[9]) 
	    1'b0    :   begin dac_data_r <= wave_sin_buf; end
	    1'b1    :   begin dac_data_r <= wave_sin_buf^10'b11_1111_1111;  end
	    default :   begin dac_data_r <= 10'd0; end
	endcase
end
(5)測試

通過串口分別發送01999b60和031a5f60,由上面公式
foutfword=fclk232 \frac{fout}{fword}=\frac{fclk}{2^{32}}
可以算出分別是1M和2M的頻率控制字在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述
以上便是DDS的FPGA實現。

發佈了15 篇原創文章 · 獲贊 12 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章