?
實(shí)際上說道上一講,老衲就可以體面撤退了。該說的都說了,細(xì)枝末節(jié)嘛,也不適合講座這種短篇幅的東西來表現(xiàn)??墒抢仙岵坏么蠹野。▽?shí)際上是舍不得出場費(fèi)),所以湊個整兩個九講。話說回來,“九”這個數(shù)字一向與武林有關(guān):《九陰真經(jīng)》、《九陽真經(jīng)》還有降龍 2×9 掌……
這一講呢,將會綜合應(yīng)用前面的全部知識,來完成一個相對較大的系統(tǒng)。希望施主們打起七十二分的精神,如果哪些知識點(diǎn)忘掉了,也需要往回翻一翻、看一看。
再嘮叨一句:講座篇幅短短幾十頁,不可能包含 Verilog 語言全部的內(nèi)容,就是與電路有關(guān)的也不全。想想看,IEEE 標(biāo)準(zhǔn) 200 多頁,除了 DPI 也有 150 頁的樣子,這個講座才幾頁啊。喜歡老衲啰嗦的老少爺們也不要失望,老和尚“慈悲為懷,善念為本”早就寫得了《Verilog 傳奇》的手抄本小冊子。您老聽著高興,可以到茶房那里購買,“走過,路過,可別錯過啊”。
好了,閑言少敘,書歸正傳?,F(xiàn)在老僧開始給大伙兒講講 DDS。
1. 概念算法,兩不耽誤
按照一般論文緒論里面吹牛的定義:直接數(shù)字合成是一種數(shù)字電子方式,它從一個單一(或混合)的時鐘源中產(chǎn)生任意波形和頻率。與傳統(tǒng)的頻率合成器相比,DDS 具有低成本、低功耗、高分辨率和快速轉(zhuǎn)換時間等優(yōu)點(diǎn),廣泛使用在電信與電子儀器領(lǐng)域,是實(shí)現(xiàn)設(shè)備全數(shù)字化的一個關(guān)鍵技術(shù)。
DDS 的一般結(jié)構(gòu)如圖 1 所示,其數(shù)字邏輯部分包括控制模塊、累加器和正弦函數(shù)發(fā)生器三個部分??刂颇K可以串行或并行的方式裝載并寄存用戶輸入的頻率控制碼;而累加器根據(jù)頻率控制碼在每個時鐘周期內(nèi)進(jìn)行相位累加,得到一個相位值;正弦函數(shù)發(fā)生器則對該相位值計(jì)算數(shù)字化正弦波幅度。DDS 芯片輸出的一般是數(shù)字化的正弦波,因此還需經(jīng)過高速 D/A 轉(zhuǎn)換器和低通濾波器才能得到一個可用的模擬頻率信號。
圖 1 DDS 系統(tǒng)整體結(jié)構(gòu)
要使 DDS 系統(tǒng)工作需要兩個操作階段:我們稱之為編程和運(yùn)行。
在編程這一階段里,電子控制器把數(shù)據(jù)載入至存儲器中。數(shù)據(jù)的每一個單元是一個用來表示當(dāng)前時刻信號幅度的二進(jìn)制數(shù)。存儲器中這些數(shù)據(jù)的排列(數(shù)組)構(gòu)成一張振幅表,表示每一時刻當(dāng)前波形的振幅。舉個例子,在一張振幅表中,前一半的數(shù)全為 0,后一半全為波形振幅的最大值(100%),這些數(shù)據(jù)就表示“方波”了。任何波形都可以通過簡單地改變這些數(shù)據(jù)來產(chǎn)生。
在運(yùn)行這一階段中,累加器受系統(tǒng)時鐘參考源的控制,每一個脈沖自增。相位累加器的輸出(相位)通常就是數(shù)組中依次輸出的各個數(shù)據(jù)。最后會被 DAC 依次轉(zhuǎn)換成模擬波形。
先看控制模塊,這個主要負(fù)責(zé)數(shù)字 DDS 的輸入輸出接口。例如,信號頻率的輸入可以通過串口線,由上位機(jī)輸入;當(dāng)然,也可以通過按鍵在 PCB 板上完成。對于的 ADC 接口,則與選擇的具體器件有關(guān)??赡苓€需要顯示一下頻率數(shù)值,這個就和 BCD(Binary-Coded Decimal?,BCD)譯碼器及其接口,乃至液晶顯示( Liquid Crystal Display, LCD)接口有關(guān)聯(lián)了。這部分很重要,但是不是本講的重點(diǎn),且容貧道一嘴帶過。
累加器部分,更加簡單的,就是一個允許設(shè)置累加步長的累加器了。更加復(fù)雜一點(diǎn)的結(jié)構(gòu)是還允許設(shè)置初始值,也就是所謂初始相位。實(shí)際工程中,初始相位的設(shè)置意義不大,就不寫入代碼了。
?
現(xiàn)在講到關(guān)鍵點(diǎn)正弦函數(shù)發(fā)生器了。一般而言,九成九的正弦函數(shù)發(fā)生器會采用 ROM 的形式。輸入的地址對應(yīng)規(guī)格化的角度值,輸出的數(shù)據(jù)則對應(yīng)該角度的正弦值。問題的核心是:到底存儲多少數(shù)據(jù)。0 度到最接近 360 度的一個分度,自然是一個選擇,但是這樣實(shí)際上浪費(fèi)了大量的存儲空間。
顛來倒去一句話:有 0 度到 90 度的正弦值,就可以得到全部是個象限的正弦值。如圖 2,其中給出了不同象限的正弦值的計(jì)算公式以及其他設(shè)計(jì)中需要的內(nèi)容。圖中的公式就是所謂周期性的公式了,用于非第一象限的正弦值的計(jì)算。另外為了方便,給出了一些特殊角度的地址,以及各個象限的地址開頭兩比特值和正弦值的符號信息。
圖 2 四個象限的正弦函數(shù)
為了實(shí)現(xiàn)用 0 到 90 度的正弦函數(shù)值,計(jì)算 0 到 360 的正弦值的目的,需要將圖 9.1 里面的正弦函數(shù)發(fā)生器劈為四份,如圖 9.3 所示。第一部分是 0 到 90 度的正弦函數(shù)發(fā)生器,這個無需多說。第二個是地址轉(zhuǎn)換模塊,它去掉原來 0 到 360 度對應(yīng)的“長地址”的最高兩個比特(90 度例外,只去掉最高一個比特),這樣得到 0 到 90 度對應(yīng)的“短地址”。第三部分叫符號產(chǎn)生模塊,負(fù)責(zé)根據(jù)當(dāng)前角度對應(yīng)的象限計(jì)算正弦值的符號。注意圖 9.2 的地址與符號部分,正弦值的符號實(shí)際上就是對應(yīng)地址的最高位。由于 0 到 90 度的正弦函數(shù)發(fā)生器可能計(jì)算時候有時延,所以符號產(chǎn)生模塊還負(fù)責(zé)這個時延的矯正。最后一個模塊是正弦值處理模塊,就是正數(shù)值透傳、負(fù)數(shù)值變?yōu)?a class="article-link" target="_blank" href="/baike/1572789.html">補(bǔ)碼的功能。
圖 3 正弦函數(shù)發(fā)生器(0 到 360 度)結(jié)構(gòu)
地址轉(zhuǎn)換與符號產(chǎn)生模塊和正弦值處理模塊的代碼也無需詳述。
把系統(tǒng)結(jié)構(gòu)中除了 0 到 90 度的正弦函數(shù)發(fā)生器的各個部分打包,叫做 DDS 框架,其架構(gòu)與代碼如圖 4 所示。
圖 4 DDS 框架與其他部分的關(guān)系
?
2. 非線數(shù)值,折線逼近
有道是“一將名成萬古枯”,在數(shù)字邏輯設(shè)計(jì)領(lǐng)域雖然沒有那么慘烈,卻也是“領(lǐng)導(dǎo)動動嘴。地下跑斷腿”。就拿前面提到的“用直線 / 折線擬合正弦函數(shù)的”這個思想為例,提出想法的人可以簡單地就是如圖 5 的勾上幾筆,看似就圓滿了。
但是接下來的工作還有很多:幾段折線合適?這些折線的位置如何確定?系數(shù)如何計(jì)算?接著還有定點(diǎn)化如何完成?最后有數(shù)字邏輯系統(tǒng)的結(jié)構(gòu)與實(shí)現(xiàn)細(xì)節(jié)。這些老大可以不考慮,工程師卻不能不研究。
圖 5 折線法計(jì)算正余弦值的示意圖
按照橫軸 / 角度均勻選擇線段的起始點(diǎn)顯然是一個最簡單的方法,但是這絕對不是一個好的方法。理由很簡單,正弦曲線的曲率 -- 或者叫導(dǎo)數(shù) -- 變化時不均勻的。均勻選擇線段會造成曲率大的地方,計(jì)算誤差大;而曲率小的地方,計(jì)算誤差也小。這顯然是不合理的。
具體算法呢,超出了這套書的范圍(欲知詳情,請看小冊子),按下不表。反正施主們得到了下面的數(shù)值:
以橫軸采樣個數(shù) 64 個以及最大允許誤差 0.02 作為輸入,可以得到一個正弦函數(shù)的 14 段折線擬合,有關(guān)信息見表 1。
表 1 折線擬合正弦函數(shù)中,線段信息
折線標(biāo)號 |
起點(diǎn)(度) |
系數(shù) |
折線標(biāo)號 |
起點(diǎn)(度) |
系數(shù) |
||
a |
b |
a |
b |
||||
0 |
0 |
0.9996 |
0 |
7 |
21.4286 |
0.9260 |
0.0188 |
1 |
4.2857 |
0.9971 |
0.0001 |
8 |
25.7143 |
0.8953 |
0.0318 |
2 |
7.1429 |
0.9921 |
0.0006 |
9 |
30.0000 |
0.8529 |
0.0529 |
3 |
10.0000 |
0.9847 |
0.0017 |
10 |
35.7143 |
0.7478 |
0.1158 |
4 |
12.8571 |
0.9748 |
0.0037 |
11 |
50.0000 |
0.5405 |
0.2916 |
5 |
15.7143 |
0.9625 |
0.0068 |
12 |
67.1429 |
0.2577 |
0.6160 |
6 |
18.5714 |
0.9478 |
0.0112 |
13 |
85.7143 |
0.0498 |
0.9217 |
對于每段折線都有:
?
其中,x 為弧度值。例如,對于 5 度(弧度 0.0873)的角度值,其正弦函數(shù)值為 sin(0.0873) ≈ 0.0887;此時 x 位于第二段折線的范圍里面,按照折線計(jì)算 y = 0.9921 × 0.0873 + 0.0006 ≈ 0.0872;誤差大約為 0.001,這已經(jīng)算是很精確了。通過程序掃描,這個算法最大的誤差為 0.019。
然后是定點(diǎn)化,忘記如何做的請回去復(fù)習(xí)則個。
考察折線法有關(guān)的數(shù)值的取值范圍,定義其定點(diǎn)化格式如表 2,其中“value_width”是待輸出的結(jié)果的位寬。需要注意的是 a_f 由于其取值范圍的特殊,設(shè)計(jì)中比其他有關(guān)數(shù)值多了一個比特。
表 2 折線法有關(guān)的數(shù)值的取值范圍與定點(diǎn)化格式
? |
折線起始點(diǎn) / 地址 |
a_f |
b |
結(jié)果 |
取值范圍 |
[0, 2π] |
[0, 2π] |
[0, 1] |
[0, 1] |
定點(diǎn)化格式 |
Q(address_width+1).0 |
Q(value_width+1).(value_address) |
Q(value_width).(value_address) |
Q(value_width).(value_address) |
對應(yīng)定點(diǎn)化計(jì)算的公式為:
其中,A_f 和 B_f 是定點(diǎn)化后的折線的系數(shù)。
此時,y 有(value_width + address_width +1 )個比特的位寬,而要求結(jié)果只有 value_width 個比特的位寬,需要進(jìn)行截位處理。根據(jù)已知條件,這個截位也有些特殊。計(jì)算結(jié)果 y 的最高比特一定為零,這個是公式的含義告訴我們的(提示一下:正弦值)。因此上系統(tǒng)輸出的結(jié)果應(yīng)該是 y 從第二個最高比特開始的 value_width 個比特。
以 address_width = 6 和 value_width = 7 為例,可以獲得折線的信息如表 3 所示。
表 3 折線擬合正弦函數(shù)中,線段定點(diǎn)化信息(十六進(jìn)制表示)
折線標(biāo)號 |
起點(diǎn)的短地址 |
系數(shù) |
折線標(biāo)號 |
起點(diǎn)的短地址 |
系數(shù) |
||
A_f |
B_f |
A_f |
B_f |
||||
0 |
00 |
c8??? |
00????????? |
7 |
0f |
b9 |
03 |
1 |
03 |
c7 |
01 |
8 |
12 |
b3 |
05 |
2 |
05 |
c6 |
01 |
9 |
15 |
ab |
07 |
3 |
07 |
c5 |
01 |
10 |
19 |
96 |
0f |
4 |
09 |
c3 |
01 |
11 |
23 |
6c |
26 |
5 |
0b |
c1 |
01 |
12 |
2f |
34 |
4f |
6 |
0d |
be |
02 |
13 |
3c |
0a |
76 |
另外可以得到:相對浮點(diǎn)運(yùn)算,定點(diǎn)運(yùn)算又帶來了 0.011 的計(jì)算誤差。
至此,定點(diǎn)化結(jié)束,可以交給數(shù)字邏輯設(shè)計(jì)的有關(guān)人員,開始具體實(shí)現(xiàn)方面的工作了。
具體的設(shè)計(jì)思路倒也不難:是“先選系數(shù)后計(jì)算”,也就是先判斷所在折線序號,得到對應(yīng)系數(shù)再計(jì)算,其基本結(jié)構(gòu)見圖 6 所示;值得一提的是,只需要這些折線的終點(diǎn)或者起點(diǎn)里面的一個信息就足夠了,因?yàn)檎劬€是首尾相連的。這里老衲采用了終點(diǎn)。還有一個小技巧是,最后一個折線的終點(diǎn)也是多余的,因?yàn)樗厝粚?yīng)最高的地址。
圖 6 “先選系數(shù)后計(jì)算”結(jié)構(gòu)
多路選擇模塊稍稍復(fù)雜一點(diǎn)點(diǎn),這里捎帶腳介紹一下。如圖 7 所示,多路選擇模塊由若干比較器和一個用“case”書寫的選擇器組成。比較器中 points 為各段折線對應(yīng)的重點(diǎn)。選擇器這有一種特殊的編碼決定選擇哪一個信號,具體編碼大伙兒自己分析。
圖 7 多路選擇模塊的結(jié)構(gòu)
在實(shí)現(xiàn)細(xì)節(jié)上還有一個很多人會跌掉的坑,那就是關(guān)于 90 度的處理。搞不好,就會在 90 度的時候,計(jì)算出 0 度的正弦值。這樣輸出的曲線就會出現(xiàn)在應(yīng)該最大值 1 的時候,輸出一個深坑(0 值)的情況。對于這種情況,可以特殊問題特殊處理,直接賦值 90 度的正弦值。在本回書的例子里面,采用了一個迂回的方式,設(shè) 90 度為最接近它的最大角度(例如,步長為 1 度的時候,輸入的“短地址”為 90 度,計(jì)算時候的地址則取為 89 度),在假設(shè)系統(tǒng) 8 比特輸出位寬的前提下,不會產(chǎn)生輸出誤差的。
?
在例 1 中給出了折線法計(jì)算 0 度到 90 度正弦值的代碼,結(jié)合前面介紹過的 DDS 的框架,就可以得到完整的 DDS 系統(tǒng)了。
【例 1】折線法計(jì)算 0 度到 90 度正弦值的代碼
module line_sin_0_90
#(parameter ADDRESS_WIDTH = 8,
//Bit width for phase counter and step
parameter VALUE_WIDTH = 8
//Output value's bit width
)
? (
??? input CLK,
??? input RESET,
??? input[ADDRESS_WIDTH - 1 - 1: 0] address,
??? output reg[VALUE_WIDTH - 1 - 1 : 0] value
? );
//Definition for Variables in the module
integer loop;
//Loop variable
reg[ADDRESS_WIDTH - 1 - 2: 0] intra_address;
//Intra address for calculation
//Change 90 degree to 111....111
//Cut the MSB
reg[ADDRESS_WIDTH - 1 - 2: 0] intra_address_delay;
//Delay for coefficients selection
reg[VALUE_WIDTH - 1 : 0] ceo_a;
//Fixed point 1.VALUE_WIDTH
reg[VALUE_WIDTH - 2 : 0] ceo_b;
//Fixed point 0.VALUE_WIDTH
//coefficients for the lines
wire[VALUE_WIDTH - 1 + 1 + ADDRESS_WIDTH - 2 - 1: 0] long_value;
//Long function value without truncation
//Length: a * address
wire[VALUE_WIDTH:0] short_value;
//Truncation value
//definition JUDGEMENTS and Coefficients Constant
//Application part: Insert DEFINITION OF JUDGEMENTS and Coefficients Constant(DO NOT REMOVE!)
//Below code/s was/were generated by the application
reg [12 : 0] judgments;
wire [7 : 0] a[13 : 0];
wire [6 : 0] b[13 : 0];
wire [5 : 0] points[12 : 0];
//Above code/s was/were generated by the application
//Logical
//Constant Tables
//Application part: Insert Constant Tables (DO NOT REMOVE!)
//Below code/s was/were generated by the application
//coefficients a and b
assign a[0] = 8'b11001000;
assign b[0] = 7'b0000000;
assign a[1] = 8'b11000111;
……
assign a[13] = 8'b00001010;
assign b[13] = 7'b1110110;
//Connect points between lines
assign points[0] = 6'b000011;
……
assign points[12] = 6'b111100;
//Above code/s was/were generated by the application
//Value calculation on the line
assign long_value = ceo_a * intra_address_delay;
assign short_value =
??????? long_value[VALUE_WIDTH - 1 + 1 + ADDRESS_WIDTH - 2 - 1 : ADDRESS_WIDTH - 2]
?????????? + {1'b0, ceo_b};
always @ (posedge CLK or negedge RESET)
//Address adjust: 90 degree operation
begin
??? if (!RESET)
??? //Reset enable
??? begin
??????? intra_address <= {(ADDRESS_WIDTH - 1){1'b0}};
??? end
??? else
??? begin
??????? if (address[ADDRESS_WIDTH - 1 -1])
??????? //90 degree
??????? begin
??????????? intra_address <= {(ADDRESS_WIDTH - 2){1'b1}};
??????????? //To 111...111
??????? end
??????? else
??????? begin
??????????? intra_address <= address[ADDRESS_WIDTH - 1 - 2: 0];
??????????? //Keep original value???????
??????? end
??? end
end
always @ (posedge CLK or negedge RESET)
//Address delay: waiting for coefficients selection
begin
??? if (!RESET)
??? //Reset enable
??? begin
??????? intra_address_delay <= {(ADDRESS_WIDTH - 1){1'b0}};
??? end
??? else
??? begin
??????? intra_address_delay <= intra_address;
??? end
end
always @ (posedge CLK or negedge RESET)
//coefficients selection
begin
??? if (!RESET)
??? //Reset enable
??? begin
??????? ceo_a <= {(VALUE_WIDTH + 1){1'b0}};
??????? ceo_b <= {(VALUE_WIDTH ){1'b0}};
??? end
??? else
??? begin
??????? case(judgments)
//Application part: Insert Coefficient Selection codes (DO NOT REMOVE!)????????
//Below code/s was/were generated by the application
???????? 13'b1111111111111:
???????? begin
???????????? ceo_a <= a[0];
???????????? ceo_b <= b[0];
???????? end
???????? 13'b1111111111110:
???????? begin
???????????? ceo_a <= a[1];
???????????? ceo_b <= b[1];
???????? end
???????? ……
???????? 13'b0000000000000:
???????? begin
???????????? ceo_a <= a[13];
???????????? ceo_b <= b[13];
???????? end
//Above code/s was/were generated by the application
????????
???????? default:
???????? begin
??????????? ceo_a <= {(VALUE_WIDTH + 1){1'b0}};
?????????????? ceo_b <= {(VALUE_WIDTH ){1'b0}};
???????? end
??????? endcase
??? end
end
always @ (posedge CLK or negedge RESET)
//Function value output
begin
??? if (!RESET)
??? //Reset enable
??? begin
??????? value <= {(VALUE_WIDTH - 1){1'b0}};
??? end
??? else
??? begin
??????? value <= short_value[VALUE_WIDTH - 1 : 0];
??????? //Truncation: MSB and tails
??? end
end
//Judgment for which line here is
always @(*)
begin
//Application part: Insert Comparisons (DO NOT REMOVE!)
//Below code/s was/were generated by the application
??? for (loop = 0; loop < 13; loop = loop + 1)
??? begin
??????? judgments[loop] <= (intra_address < points[loop]);
??? end
//Above code/s was/were generated by the application
end
endmodule
?
3. 系統(tǒng)驗(yàn)證,中規(guī)中矩
這個系統(tǒng)包含很多模塊,其他模塊好說,進(jìn)行仿真驗(yàn)證的時候,肉眼都可以看出它到底合適不。就是 0 到 90 度的正弦函數(shù)發(fā)生器相對輸出復(fù)雜,例如對于 7 比特輸入就有 65 個輸出信號需要對比。對于這樣的模塊,最好的驗(yàn)證方法是測試向量方法。這個方法以前提到過,直接上代碼如例 2。
【例 2】0 到 90 度的正弦函數(shù)發(fā)生器驗(yàn)證代碼
`timescale 10 ns/100 ps
//Simulation time assignment
//Insert the modules
module sin_0_90_test;
//definition for Variables
reg clk;
reg reset;
reg[7:0] cntr;
wire[6:0] result;
reg[6:0] test_vector_monory[64:0];
wire[6:0] test_vector;
//Test Vector Value
wire[7:0] addr;
//Address of test vectors
wire right;
//Results right?
//Connection to the modules
ROM_sin_0_90 LS (.CLK(clk), .RESET(reset), .address(cntr[6:0]),
????????????????? .value(result));
assign test_vector = test_vector_monory[addr];
assign right = (test_vector == result);
assign addr = (cntr >= 3) ? ( cntr - 3): ( 64 - 3 +? cntr);
//Delay for operation
//Clock generation
……
//Reset operation
……
//Load the test vectors
??? initial?
??? begin
????? $readmemh("sin2line_test_vector_2016_3_13_17_3_10.txt",
????????????????? test_vector_monory);
??? end
???????
//Couner as input
??? ……
endmodule
代碼中,“test_vector_monory”里面存儲了其他程序產(chǎn)生的對應(yīng)正弦值,“addr”是對于實(shí)際處理模塊帶來的時延的修正。如果“right”信號一直是高電平,則說明 0 到 90 度的正弦函數(shù)發(fā)生器功能正確。
到了最后的系統(tǒng)驗(yàn)證的階段了,當(dāng)然也可以采用上面的測試向量的方法完成。書不重?cái)?,這里再教施主們一個輸出信號進(jìn)行性能驗(yàn)證的手段。這個手法也在前面一章里面介紹過,莫過于寫文件罷了。但是具體到正弦函數(shù)的性能驗(yàn)證,卻還是有些技巧的。
對于正弦函數(shù)性能的測試,大多數(shù)人一定會想到快速傅里葉變換(Fast Fourier Transform,F(xiàn)FT)。信號頻譜的最高峰就是正弦信號的線譜,其平方為正弦信號的能量;其他部分就是系統(tǒng)產(chǎn)生的噪聲,噪聲能量為其能量值和。這樣就可以得到系統(tǒng)最重要的性能:信噪比 (信號噪聲比,Signal-to-noise ratio ,SNR)。但是實(shí)際中,F(xiàn)FT 也是優(yōu)缺點(diǎn)的。這就是對于非整周期采樣的數(shù)據(jù),會有頻譜散射效應(yīng)。有興趣的人士可以用任何具備 FFT 功能的工具做一個有趣的實(shí)驗(yàn)。分別產(chǎn)生兩個序列:第一個序列為 0 度到 359 度的正弦值,第二個序列為 0 度到 358 度的正弦值。分別對于這兩個序列做 FFT 并且畫出幅度值,兩者的區(qū)別立現(xiàn)。
針對這個情況,在采集 DDS 系統(tǒng)的輸出的時候,不能任意采集。采集的樣本必須滿足“滿周期”的性質(zhì)。細(xì)心的觀眾一定主要到了,在 DDS 的框架里面有一個叫“zero_address”的信號。這個信號當(dāng)長地址為全零的時候?yàn)楦唠娖健Q句話說,該信號兩次為高之間的信號為滿周期的信號。
現(xiàn)在沒什么能夠攔阻人類進(jìn)入 DDS 時代的腳步了,前進(jìn)!圖 8 是本講介紹的 DDS 的輸出,其中還表現(xiàn)了一次頻率變化的過程。
圖 8 DDS 的輸出信號
至于輸出三角波、鋸齒波或者方波的 DDS,相對于上面的系統(tǒng),基本不值一提,就不多說了。
最后再說一下,限于篇幅不好詳細(xì)展開,有求知欲聽眾千萬要買小冊子啊!
這正是:
“
語言本來無情物,上天入地多用途。一般時鐘做輸入,產(chǎn)生正弦片外吐。
外圍框架無特殊,函數(shù)產(chǎn)生玄妙出。驗(yàn)證方法有用處,整周采樣成數(shù)組。
”
與非網(wǎng)原創(chuàng)內(nèi)容,謝絕轉(zhuǎn)載!
系列匯總:
之二:Verilog 編程無法一蹴而就,語言層次講究“名正則言順”
之三:數(shù)字邏輯不容小窺,電路門一統(tǒng)江湖
之五:Verilog 不難學(xué),聊聊時序邏輯那些事兒
之六:數(shù)字電路設(shè)計(jì):有理論、有電路、有代碼“三位一體”