最近在學習基於FPGA的DDS設計,借此機會把學習過程記錄下來,當作自己的學習筆記也希望能夠幫助到學習DDS的小伙伴。
DDS(Direct Digital Synthesizer)直接數字合成器,這是直譯過來的名字。設計人員一般把它叫做信號發生器,用它來產生一些數字意義上的波形。它的意義還是挺大的,例如我們學習濾波器,就需要一個高低頻率疊加的波形,現時生活中到處都是,可以在設計中,怎么能做出這樣的波形呢?學習各種載波調制,需要將信息加載到載波上,而載波也一般都是一定頻率的正弦波。DDS就是能夠產生這種波形,對於學習數字信號處理以及信號調制解調等有很大的作用。
FPGA是數字電路,怎么產生模擬的波形呢?如果單純的使用FPGA是無論如何也產生不了連續不斷的波形,一般都是使用FPGA產生數字信號,再利用DAC(Digital-to-Analog Converter)轉化成為模擬的波形(如圖1)。DAC芯片是一堆模擬電路的東西了,如果感興趣的小伙伴可以在自己學習一下數字信號轉化為模擬信號的過程。
圖1
FPGA是數字信號,通過DAC轉化為模擬值,筆者在進行學習的時候一直有個疑問:既然FPGA是數字信號,那么也就只能輸出數字信號,輸出相鄰的兩個點中間一定是有一定距離的,輸出的模擬波形應該像樓梯一樣(有一定的幅值跳躍),而不是連續變化的,像這種情況下還是我們還可以用嗎?答案是肯定的,如果“樓梯”的高度跳躍很小,並且在一個周期中有很多小的跳躍,那么就是可以用的。其實微積分的概念和這個道理應該差不多就是用無限多的矩形來近似曲線(如圖2)。
圖2
所以在設計時,只要將波形的一個周期(周期波形)中分成N段輸出就可以了。
DDS的實現一般都是由頻率控制器、相位累加器和波形存儲器構成(如圖3)。
圖3
剛剛開始的時候接觸到這個信息,筆者也不太理解,經過一段的時間思考,大概明白了其中的設計原理。我們直接從最終的輸出開始分析,要輸出的一個波形(數字意義上),例如正弦波。那么怎么輸出呢,可以給出一個公式sin(2*pi*n/256),將n從0增長到255,就可以輸出一個波形。如果這么寫的話,就已經把一個周期分成了256份,也可以分成任意份,為了方便數字電路設計,一般都是2的整數次冪份。以下分析都當作一個周期分為256份。n等於一個數值就會輸出一個值,把n所對應的位置看作是相位。例如n等於64時,輸出的值正好對應於相位pi/2時。在FPGA中去計算sin,一般都是利用查表法,也就是說將一個周期分為N份,當輸入的值比較接近與某一個相位時,就把這個相位點的值輸出。那其實也就是把波形等分多份,存儲在存儲器中,而此時存儲器就叫做波形存儲器。存儲器的輸出是按照輸入地址來決定的,如果想要輸出一個完整的不斷的波形,就需要地址從最小到最大不變循環,而存儲器就會不斷的輸出波形。地址從最小到最大的累加,就被成為相位累加器。如果相位累加器1S從最小到最大循環了1000次,那么輸出的波形的頻率就為1KHz。故而相位累加器累加的速度決定輸出波形的頻率,而累加速度是由外部控制器來決定,所以此控制器被稱作頻率控制器。
原理就是上述的那樣,下面可以考慮如何來實現上述的過程。
在設計中,筆者采用INTEL FPGA來實現,故此采用Quartus Prime 18。首先制作波形存儲器,在FPGA中有很多存儲器資源可以來用,在此選擇ROM來當作存儲器。利用ROM當存儲需要制作初始化文件.mif或者.hex,這兩種都可以,在這里采用.mif文件。
.mif在Quartus 中顯示為一個一個小區域(如圖4),但是其實就是一種文件格式(如圖5)。
圖4
圖5
利用某些計算工具將數值計算出來,然后填入表格中,這種速度太慢,也太麻煩。我們一般采用下面所述的兩種方法:
利用mifmaker軟件生成(QQ群:173560979群文件中),此軟件用起來比較簡單。只需要簡單的設置“設定波形”即可。在設定成功后,點擊“文件->保存”即可生成對應的.mif文件(如圖6)。
圖6
另外一種方法就是利用matlab實現,此方法要求設計者要有一定的matlab基礎。源碼如下:
1 clear; 2 clc; 3 4 width = 8; 5 depth = 256; 6 7 file_handle = fopen('sin.mif','w+'); 8 fprintf(file_handle,'--Created by Author xxx\r\n'); 9 fprintf(file_handle,'WIDTH = %d;\r\n',width); 10 fprintf(file_handle,'DEPTH = %d;\r\n',depth); 11 fprintf(file_handle,'ADDRESS_RADIX = HEX;\r\n'); 12 fprintf(file_handle,'DATA_RADIX = HEX;\r\n'); 13 fprintf(file_handle,'CONTENT BEGIN\r\n'); 14 for i = 0 : depth-1 15 fprintf(file_handle,'%4x : %4x ; \r\n',i,floor((0.5+0.5*sin(2*pi*i/depth) ) *(2^width - 1))); 16 end 17 fprintf(file_handle,'END;\r\n'); 18 fclose(file_handle);
產生了.mif后,就可以加載到ROM中。在quartus工程中,采用50MHz的時鍾來進行驅動整個設計,讓rom的地址每個時鍾周期增加1。經過仿真可以得到正弦波(如圖7)。
圖7
產生了正弦波,在設置modelsim時,因為波形是按照無符號生成的數據,所以在設置成為模擬之前要先把進制改為無符號類型。即可產生圖7波形。經過使用modelsim工具測試,產生的波形的頻率為195.313KHz。我們自己也算以下:系統的驅動時鍾為50MHz,一個周期為20ns,256個周期輸出一個完整的波形。所以波形的周期為256x20ns=5120ns,經過計算頻率為195.3125KHz,與上述使用modelsim工具測試結果一直,只是modelsim測試保留了頻率的兩位小數而已。
相位累加器每次累加1,產生的波形的頻率為195.313KHz,那么只要改變每次累加的數字就可以得到其他頻率。如果每次增加的是整數比較好辦,那如果每次增加的是帶有小數呢?又該如何實現呢?
筆者水平有限,如有不妥之處,懇請大佬指出。
歡迎加好友探討QQ:746833924,QQ群:173560979。