【主題】:詳細解析基于FPGA(DDS)的正弦波發(fā)生器 【作者】:LinCoding 【時間】:2016.12.27 【聲明】:轉載,、引用,請注明出處 我們都知道FPGA是一個數(shù)字器件,,那么在通信領域,,很多時候,,要產(chǎn)生正弦波信號作為調制信號,。在FPGA中產(chǎn)生正弦波一般用的是:DDS,。 DDS(Direct Dignal Synthesizer):即直接數(shù)字式頻率合成器。 DDS的主要組成部分:相位累加器,、相位調制器,、波形數(shù)據(jù)表、DAC和低通濾波器組成,,如下圖所示,。 DDS原理: 首先ROM中要存放好要顯示的正弦波數(shù)據(jù)。然后由相位累加器(其實就是個計數(shù)器)一直累加,,根據(jù)這個累加器的值作為ROM的地址,,然后DAC根據(jù)ROM輸出的數(shù)據(jù)輸出相應的電壓值,但是由于數(shù)字的離散性,,DA輸出的也將是離散的電壓值,,也就構成了不平滑的正弦波,這時,,只需在后級加一個低通濾波器就可以輸出完美的正弦波,。 先看圖:正弦波 但是,DDS原理中最麻煩的是實現(xiàn)頻率可調的原理:下面筆者一一道來,。 首先我們要考慮以下兩個問題: 1,、相位累加器(計數(shù)器)的位寬是多少? 2,、ROM的數(shù)據(jù)位寬和深度(深度:2^地址位寬)是多少,? 第一個問題:相位累加器的位寬為24~32位,一般選32位,,至于為什么筆者也不清楚,,網(wǎng)上也沒找到答案,可能是經(jīng)驗吧,,這樣的話頻率可調的范圍可滿足大部分應用,。 第二個問題: (1)ROM的數(shù)據(jù)位寬選擇要看DAC模塊,比如我的DAC模塊的數(shù)據(jù)輸入數(shù)據(jù)范圍是0~1023,,那么我的ROM的數(shù)據(jù)位寬就要選擇為10位,; (2)ROM的深度也取決于你DAC模塊,因為ROM中只能存儲整數(shù),,這樣的話,,即使ROM每相鄰單元存儲的間隔是1(也就是1,2,3,4,5……),這樣的話由于最大只能到1023,,而這1024個數(shù)據(jù)僅僅為半個周期,,一個周期的話就是2048,所以標準ROM的深度是2^(DAC位寬)*2。但這是可變的,,我們可以每兩個點存儲相同的數(shù)字(比如1,1,2,2,3,3,4,4,5,5,……)這樣的話ROM深度也可以是4096,,當然我也可以間隔一個點存儲(比如1,3,5,7,9,……),,這樣我的ROM深度是1024,,所以這么說來ROM的深度是靈活的,但位寬一定是確定的,。 搞清楚這兩個問題以后,,就是如何實現(xiàn)頻率可調了? 好多人確實感覺這里不好理解,,但是其實這很簡單,,就是玩了個數(shù)字游戲,使用低位來改變高位的變化速度,。舉例如下: //----------------------------------- //phase adder reg [10:0] fre_cnt; always @ ( posedge clk or negedge rst_n ) begin if ( ! rst_n ) fre_cnt <= 11'd0; else if ( DDS_en ) fre_cnt <= fre_cnt + 1'b1; else fre_cnt <= 11'd0; end這就是所謂的相位累加器,,在DDS_en使能以后就一直計數(shù),直到計滿,,然后重新又開始計數(shù),,這里我們的clk是系統(tǒng)時鐘50Mhz,周期就是20ns,。 DDS_rom u_DDS_ddsrom ( .clock (clk), .address (fre_cnt), .q (DAC_data) );然后,,我們把計數(shù)的值作為ROM的地址送給ROM,ROM輸出相應的正弦波數(shù)據(jù),,這時,,會將2048個點全部輸出。而2048個點全部輸出需要2048*20ns=40960ns,,1/(40960ns)=24414.0625Hz,,這就是DDS的基本頻率,我們將其稱為基頻,。 好了,,下面開始改變頻率了。 (1)首先我想將頻率翻倍,,我們可以這樣: //----------------------------------- //phase adder reg [10:0] fre_cnt; always @ ( posedge clk or negedge rst_n ) //clk為50Mhz begin if ( ! rst_n ) fre_cnt <= 11'd0; else if ( DDS_en ) fre_cnt <= fre_cnt + 2'd2; else fre_cnt <= 11'd0; end DDS_rom u_DDS_ddsrom ( .clock (clk), .address (fre_cnt), .q (DAC_data) );這樣的話,,由于clk仍為50Mhz,計數(shù)器周期還是20ns,,但是我們相當于將ROM中數(shù)據(jù)隔點輸出,一共只輸出了1024個點,,這樣的話輸出波形的周期是1024*20ns=20480ns,,頻率是1/(20480ns)=48848.125Hz,輕松實現(xiàn)了頻率翻倍。當然我這里為了大家理解選擇了整數(shù)倍,,當然1.3倍,,1,6倍是同樣的道理,也就是改變計數(shù)器的計數(shù)間隔,。 (2)下面我們將頻率減半,,頻率減半的原理就是每兩個20ns(每40ns)輸出相同的數(shù)據(jù),但由于此時我們無法再減小計數(shù)器的計數(shù)間隔了(已經(jīng)是1了),,因此迫不得已必須改變計數(shù)的時鐘,,我們我可以這樣: 代碼和第一個代碼一樣,但是clk我使用的是經(jīng)過PLL的25Mhz的clk_ref,,這樣的話周期就是40ns,,在40ns內將2048個點輸出,這樣的話正弦波周期為2048*40ns=81920ns,,頻率為1/(81920ns)=12207.0315Hz,,任務完成。 如果這樣一來,,在基頻的基礎上,,頻率增大和較小的代碼不一樣,而且需要改變計數(shù)器的clk,,這是我們無法容忍的,。因此改良代碼如下: 首先,這時,,clk為固定50Mhz,,fre_value我們稱為頻率控制字,如果fre_value是1的話,,每次要計數(shù)滿20'h1_00000之后,,rom_addr才會增加1,也就是說每20'h1_00000*20ns,,ROM的輸出值才會變化,,這樣一來,周期為20'h1_00000*20ns*2048=42.94967296s,,頻率為1/43s≈0.023283Hz,,這也就是DDS可以達到的最小頻率,并且DDS可達到的所有頻率也均為這個最小頻率的整數(shù)倍,。 如果fre_value等于20'h1_00000的話,,這樣每20ns,ROM可改變一次輸出值,,達到的就是我們的基頻,,這里就不再計算了。 那么DDS最大的頻率是多少呢?我們可以讓fre_value等于32'h8_000_0000,,這樣的話ROM只會輸出第一個值,,最中間的值和最后一個值,頻率為1/40ns=25Mhz,,但是這三個點的ROM數(shù)據(jù)都為0,,因此波形已經(jīng)是一條直線了。 最后,,為了完善DDS,,我們可以給他增加一個調節(jié)相位的功能。 其實很簡單,,就是加了個pha_value相位控制字,。它的位寬需與DAC模塊位寬相同。 總結: 1,、相位累加器的位寬為24~32位,,一般選32位; 2,、頻率控制字位寬與相位累加器位寬相同,; 3、ROM的數(shù)據(jù)位寬選擇取決于DAC模塊,; 4,、ROM的深度(2^地址位寬)有標準深度,但可任意,; 5,、相位控制字位寬選擇取決于DAC模塊。
|
|