寫在前面
本文是本系列的第一篇,參考杜勇老師的數(shù)字濾波器MATLAB和Verilog實(shí)現(xiàn)以及一些網(wǎng)文博客,更新順序參考杜勇老師的書籍目錄。 本文主要介紹關(guān)于數(shù)字信號的一些基礎(chǔ)知識。
固定點(diǎn)數(shù)
數(shù)字既包括整數(shù),又包括小數(shù),而小數(shù)的精度范圍要比整數(shù)大得多,所以如果我們想在計(jì)算機(jī)中,既能表示整數(shù),也能表示小數(shù),關(guān)鍵就在于這個小數(shù)點(diǎn)如何表示。 于是人們想出一種方法,即 約定計(jì)算機(jī)中小數(shù)點(diǎn)的位置 ,且這個位置固定不變,小數(shù)點(diǎn)前、后的數(shù)字,分別用二進(jìn)制表示,然后組合起來就可以把這個數(shù)字在計(jì)算機(jī)中存儲起來,這種表示方式叫做「定點(diǎn)」表示法,用這種方法表示的數(shù)字叫做「定點(diǎn)數(shù)」。 也就是說「定」是指固定的意思,「點(diǎn)」是指小數(shù)點(diǎn),小數(shù)點(diǎn)位置固定即定點(diǎn)數(shù)名字的由來。
在計(jì)算機(jī)中,通常將數(shù)據(jù)的小數(shù)點(diǎn)固定在數(shù)據(jù)的最高位之前或者最低位之后。 前者稱為定點(diǎn)小數(shù),后者稱為定點(diǎn)整數(shù)。 定點(diǎn)小數(shù) 是純小數(shù),約定的小數(shù)點(diǎn)位置在符號位之后、有效數(shù)值部分最高位之前。 若數(shù)據(jù) x 的形式為 x = x0.x1x2… xn ( 其中x0為符號位,x1~xn是數(shù)值的有效部分,也稱為尾數(shù), x1為最高有效位 ),則在計(jì)算機(jī)中的表示形式為:
在數(shù)字處理中,定點(diǎn)數(shù)通常把數(shù)限制-1~ 1之間,把小數(shù)點(diǎn)規(guī)定在符號位和數(shù)據(jù)位之間,而把整數(shù)位作為符號位,用0 、1表示正負(fù),數(shù)本身只有小數(shù)部分,即尾數(shù)。 這是由于經(jīng)過定點(diǎn)數(shù)的乘法后,所得的結(jié)果小數(shù)點(diǎn)位置不確定,除非兩個乘數(shù)都是小數(shù)或者整數(shù)。 對于加法來說,小數(shù)點(diǎn)的位置是固定的,如上圖x0位符號位,x1~xn為數(shù)據(jù)位。 在整個運(yùn)算過程中,要求所有的運(yùn)算結(jié)果的絕對值都不能超過1,否則會出現(xiàn)溢出。 在實(shí)際問題中,處理運(yùn)算的中間過程會可能會出現(xiàn)結(jié)果超過1的情況,為了使得運(yùn)算正確,通常會在運(yùn)算時乘一個比例因子(類似歸一化)避免發(fā)生溢出現(xiàn)象。
定點(diǎn)數(shù)的三種表示方法
定點(diǎn)帶符號數(shù)在計(jì)算機(jī)內(nèi)的四種表示方法是: 原碼,補(bǔ)碼,反碼。 在FPGA處理中,比較都常用。
原碼表示
最高位為符號位,0表示正數(shù),1表示負(fù)數(shù),其余位是數(shù)值位。 原碼的優(yōu)點(diǎn)是簡單直觀,特點(diǎn)是符號位與數(shù)值位在運(yùn)算時要區(qū)別對待。 0的原碼表示有兩種形式。
反碼表示
正數(shù)的反碼表示與原碼表示一樣; 負(fù)數(shù)的反碼表示為該負(fù)數(shù)對應(yīng)的原碼符號位不變,數(shù)值位按位取反。 因此,在反碼表示中,最高位還是符號位,0表示正,1表示負(fù),與原碼相同。 0的反碼表示也有兩種形式。
補(bǔ)碼表示
正數(shù)的補(bǔ)碼表示與原碼表示相同; 負(fù)數(shù)的補(bǔ)碼表示是原碼表示的符號位不變數(shù)值位取反,并在最低位加1。 補(bǔ)碼中0的表示是唯一的。
浮點(diǎn)數(shù)
浮點(diǎn)數(shù)是一種公式化的表達(dá)方式,用來近似表示實(shí)數(shù),并且可以在表達(dá)范圍和表示精度之間進(jìn)行權(quán)衡(因此被稱為浮點(diǎn)數(shù))。 在計(jì)算機(jī)中可以近似表達(dá)任意實(shí)數(shù)。 浮點(diǎn)數(shù)通常被表示為:A=M×B^E,B被稱為階碼的基數(shù),精度為N(使用多少位來進(jìn)行存儲),E在浮點(diǎn)數(shù)中表示為基的指數(shù)。 M被稱為浮點(diǎn)數(shù)的尾數(shù)。
浮點(diǎn)顯示方法
要表示浮點(diǎn)數(shù),一是要給出尾數(shù)M的值,通常用定點(diǎn)小數(shù)形式表示,它決定了浮點(diǎn)數(shù)的表示精度,即可以給出的有效數(shù)字的位數(shù)。 二是要給出階碼,通常用定點(diǎn)整數(shù)形式表示,它指出的是小數(shù)點(diǎn)在數(shù)據(jù)中的位置,決定了浮點(diǎn)數(shù)的表示范圍。 因此,在計(jì)算機(jī)中,浮點(diǎn)數(shù)通常被表示成如下格式:(假定為32位浮點(diǎn)數(shù),基為2,其中最高位為符號位)
一種FPGA處理浮點(diǎn)數(shù)格式
雖然浮點(diǎn)數(shù)的表示范圍更大,但實(shí)現(xiàn)時消耗的資源更多,實(shí)現(xiàn)的步驟也更加繁瑣。 如浮點(diǎn)數(shù)的加法需要以下步驟:
- 對階操作:比較指數(shù)的大小,對指數(shù)小的操作數(shù)進(jìn)行移位,完成尾數(shù)的對階操作。
- 尾數(shù)相加:對階后的尾數(shù)進(jìn)行加減操作。
- 規(guī)格化:規(guī)格化有效位并根據(jù)移位方向和位數(shù)修改最終的階數(shù)。
浮點(diǎn)數(shù)乘法操作,一般需要以下操作:
- 指數(shù)相加:完成兩個操作數(shù)的指數(shù)相加運(yùn)算。
- 尾數(shù)調(diào)整:將尾數(shù)M調(diào)整為1.M的補(bǔ)碼格式。
- 尾數(shù)相乘:完成講個操作數(shù)的尾數(shù)相乘運(yùn)算。
- 規(guī)格化:根據(jù)尾數(shù)運(yùn)算結(jié)果調(diào)整指數(shù)位,并對尾數(shù)進(jìn)行舍入截位操作,規(guī)格化輸出結(jié)果。
浮點(diǎn)數(shù)乘法器的運(yùn)算速度主要由FPGA內(nèi)部集成的硬件乘法器決定。 大部分FPGA芯片內(nèi)部的乘法器為18bitX18bit。 這里以7系列的xilinx為例。 DSP48內(nèi)部的乘法器為25X18的,如下圖:
如果進(jìn)行24位的乘法運(yùn)算,則需要使用4個18bitX18bit乘法器,兩個18位的數(shù)乘法操作只占用一個18bitX18bit乘法器。 由于FPGA的寄存器資源的設(shè)計(jì),可以直接將尾數(shù)表示為補(bǔ)碼的格式。 可以去除尾數(shù)調(diào)整的運(yùn)算,減少一級流水操作。
杜勇老師在他的《多輸入浮點(diǎn)加法器算法研究》中提出了一種新的浮點(diǎn)數(shù)結(jié)格式,也即一個26位寬的數(shù),25--18位表示為8位有符號數(shù),17--0表示為18位有符號的小數(shù)。 浮點(diǎn)數(shù)的表示式為M = f X 2^e;
規(guī)定,數(shù)值1的表示方法為指數(shù)為0,尾數(shù)為01_1111_1111_1111_1111;數(shù)值0表示為指數(shù)為-128,尾數(shù)為0。 這種自定義浮點(diǎn)數(shù)格式,相比24位的普通浮點(diǎn)數(shù)運(yùn)算雖然精度有所下降但是可以大大節(jié)省乘法器的資源由是個乘法器變?yōu)?個,并有效地減少了運(yùn)算步驟,提高了運(yùn)算速率(由二級18X18乘法運(yùn)算減少到一級運(yùn)算)。
自定義浮點(diǎn)數(shù)和實(shí)數(shù)之間的關(guān)系:
FPGA中的運(yùn)算
加減法運(yùn)算
小數(shù)加減法運(yùn)算
在Verilog中比較常用的數(shù)據(jù)類型是wire和reg以及他們的向量形式,在Verilog中,默認(rèn)將所有的二進(jìn)制數(shù)當(dāng)做小數(shù)處理,也就是說小數(shù)點(diǎn)均在最低位的右邊。 帶小數(shù)的運(yùn)算,設(shè)計(jì)者可以通過隱形規(guī)定進(jìn)行,如,假設(shè)規(guī)定一個小數(shù)運(yùn)算的小數(shù)點(diǎn)在最高位和次高位之間,然后進(jìn)行小數(shù)的加減法運(yùn)算。 和十進(jìn)制的運(yùn)算規(guī)則相同,在做加減法運(yùn)算時,參與運(yùn)算的兩個數(shù)的小數(shù)點(diǎn)必須對齊,并且結(jié)果的小數(shù)點(diǎn)位置相同。
還有一種比較常用的處理辦法是,將小數(shù)轉(zhuǎn)換為整數(shù)進(jìn)行運(yùn)算,處理過程為同時把要運(yùn)算的數(shù)進(jìn)行乘一個很大的數(shù)如1024,即乘一個很大的整數(shù)處理掉小數(shù)部分,轉(zhuǎn)化為整數(shù),并約定該整數(shù)為之前的小數(shù)。 但是這樣處理的弊端也比較明顯,相比于直接進(jìn)行隱形規(guī)定小數(shù)運(yùn)算,會消耗更多的資源。
負(fù)數(shù)加減法
Verilog默認(rèn)狀態(tài)都表示的是無符號數(shù),如果要指定某個數(shù)為有符號數(shù),要在聲明前加入關(guān)鍵字signed,如:wire signed [2:0] data; 這里表示data為3bit的有符號數(shù),在運(yùn)算時自動采用有符號運(yùn)算。 下面引用杜勇老師書上的一個示例,并做略微改動。
有無符號數(shù)對比示例:
源文件:
`timescale 1ns / 1ps
module adder_test(
data1,
data2,
sum_signed_out,
sum_unsigned_out,
compare_signed,
compare_unsigned);
input [3:0]data1; //輸入加數(shù)1
input [3:0]data2; //輸入加數(shù)2
output [3:0] sum_unsigned_out; //無符號加法輸出
outputsigned [3:0] sum_signed_out; //有符號加法輸出
output [3:0] compare_signed; //有符號數(shù)比較輸出
output [3:0] compare_unsigned; //無符號數(shù)比較輸出
//無符號加法運(yùn)算
assign sum_unsigned_out = data1 + data2;
//有符號加法運(yùn)算
wiresigned [3:0] s_data1;
wiresigned [3:0] s_data2;
assign s_data1 = data1;
assign s_data2 = data2;
assign sum_signed_out = s_data1 + s_data2;
//比較操作
wiresigned [3:0] cons_1 = 4'b1001;
assign compare_signed = (sum_signed_out < cons_1)? 1 : 0;
assign compare_unsigned = (sum_unsigned_out < cons_1)? 1 : 0;
endmodule
測試文件:
`timescale 1ns / 1ps
module tb_adder();
//輸入
reg [3:0] data1;
reg [3:0] data2;
//輸出
wire [3:0] sum_unsigned_out;
wire [3:0] sum_signed_out ;
wire compare_signed ;
wire compare_unsigned;
//例化
adder_test u_adder_test(
.data1 (data1 ),
.data2 (data2 ),
.sum_unsigned_out (sum_unsigned_out ),
.sum_signed_out (sum_signed_out ),
.compare_signed (compare_signed ),
.compare_unsigned (compare_unsigned )
);
//測試
initialbegin
data1 = 0;
data2 = 0;
repeat(16)begin
data1 = data1 + 1;
data2 = data2 + 1;
#20;
end
end
endmodule
綜合的RTL圖:
此時的仿真結(jié)果為下圖:
通過對比可以知道,在進(jìn)行運(yùn)算時,有無符號數(shù)的運(yùn)算結(jié)果在二進(jìn)制中查看是相同的,但是表達(dá)的數(shù)值大小有區(qū)別,除此之外,有無符號數(shù)的區(qū)別也體現(xiàn)在比較運(yùn)算上。
從下圖中,可以看出,對于有無符號數(shù)來說,4‘b1001有符號數(shù)對應(yīng)的是-7,無符號數(shù)對應(yīng)的是9,所以兩者的結(jié)果是不一樣的。
比較操作中為何不直接使用(sum_signed_out < 4'b1001)?
這里作為對比,將比較操作語句的cons_1直接改為4'b1001;
//比較操作
//wire signed [3:0] cons_1 = 4'b1001;
assign compare_signed = (sum_signed_out < 4'b1001)? 1 : 0;
assign compare_unsigned = (sum_unsigned_out < 4'b1001)? 1 : 0;
在vivado的編譯仿真器環(huán)境下輸出結(jié)果如下:
從波形可以看出,兩個比較操作都是按照無符號數(shù)進(jìn)行比較,這是因?yàn)樵谶M(jìn)行比較操作時,直接把比較數(shù)寫入4'b1001,編譯器會默認(rèn)該數(shù)為無符號數(shù),比較會按照無符號進(jìn)行比較輸出。 所以**有符號數(shù)進(jìn)行比較時加上signed,即可考慮數(shù)值正負(fù),完成正確比較,必須兩個都要加signed,否則當(dāng)作無符號進(jìn)行比較。 否則只會將有符號數(shù)看作無符號數(shù)進(jìn)行比較。 **
乘法運(yùn)算
對于乘法運(yùn)算,可以選擇使用工具中自帶的IP核,也可以使用基本的組件進(jìn)行設(shè)計(jì)乘法電路。 相比加減法,乘法電路更消耗資源,一般情況下,對于信號和信號(數(shù)據(jù))之間的運(yùn)算,通常調(diào)用IP進(jìn)行實(shí)現(xiàn),而常數(shù)和信號直接的乘法運(yùn)算,可以通過進(jìn)行移位和加減法實(shí)現(xiàn)。 例如一個數(shù)乘2,等效為這個數(shù)左移一位; 一個數(shù)乘3等效為這個數(shù)左移一位+該數(shù)本身。
因?yàn)槌朔ㄟ\(yùn)算的結(jié)果數(shù)據(jù)位數(shù)比乘數(shù)位數(shù)多,所以在實(shí)現(xiàn)乘法時,要先進(jìn)行數(shù)據(jù)位數(shù)是擴(kuò)展,以免出現(xiàn)數(shù)據(jù)溢出的現(xiàn)象。
除法運(yùn)算
和乘法類似,可以選擇使用工具中自帶的IP核實(shí)現(xiàn)除法電路。 但是除法不可以在Verilog程序中進(jìn)行直接實(shí)現(xiàn),類比乘法電路的實(shí)現(xiàn)方法,可以將除法進(jìn)行分解成若干右移的小項(xiàng),然后進(jìn)行加減運(yùn)算操作。 例如一個數(shù)除以2,則可以將該數(shù)進(jìn)行右移一位; 一個數(shù)除以3,可以將該數(shù)(記該數(shù)為A)近似分解 為,A右移2位+A右移4位+A右移6位。 (相當(dāng)于該數(shù)乘了0.3281),因?yàn)樵摂?shù)是無限小數(shù),所以對于分解法只能得到近似的結(jié)果,分解的項(xiàng)數(shù)越多,精度越高。 因?yàn)镕PGA這些數(shù)字信號處理平臺不可避免有限字長效應(yīng)引起的。
有效數(shù)據(jù)位的計(jì)算
在FPGA中,所有的數(shù)據(jù)都是通過寄存器來存儲,使用的寄存器越多,消耗的資源也就越多。 所以為了保證硬件資源的有效利用,需要精準(zhǔn)掌握運(yùn)算中的有效數(shù)據(jù)位的長度,盡可能的減少無效數(shù)據(jù)位參與運(yùn)算,浪費(fèi)資源。 有效數(shù)據(jù)位表示有用的數(shù)據(jù)位,例如數(shù)據(jù)范圍為0-9,從寄存器的角度來說,只需要4個寄存器進(jìn)行存儲即可枚舉所有0-9的狀態(tài),如果此時定義了5位的寄存器向量,那么多出來的那一位是無效的,任何時候都不代表任何信息。
加法運(yùn)算的有效數(shù)據(jù)位
對于整數(shù)加法來說,假設(shè)加法中的兩個加數(shù)最大的位數(shù)為N,則加法運(yùn)算結(jié)果需要N+1位 才能保證結(jié)果不溢出。
對于小數(shù)加法來說,如果采用N+1位的數(shù)據(jù)表示運(yùn)算結(jié)果,則小數(shù)點(diǎn)的位置在數(shù)據(jù)次高位的右邊,如果采用N位數(shù)據(jù)表示運(yùn)算結(jié)果,則小數(shù)點(diǎn)的位置在數(shù)據(jù)最高位的右邊。 簡而言之就是,小數(shù)部分的數(shù)據(jù)位數(shù)是不變的 。 為了確保得到N+1位的準(zhǔn)確結(jié)果,要對參加運(yùn)算的兩個數(shù)進(jìn)行一位符號位的拓展 。
乘法運(yùn)算的有效數(shù)據(jù)位
對于數(shù)據(jù)長為M和N的數(shù)據(jù)進(jìn)行乘法運(yùn)算時,需要M+N位的數(shù)據(jù)才能得到準(zhǔn)確的結(jié)果。 對于乘法運(yùn)算當(dāng)乘數(shù)為小數(shù)時,,不需要通過拓展位數(shù)類對齊乘數(shù)的小數(shù)點(diǎn)位置,乘法的結(jié)果的小數(shù)位數(shù)等于兩個乘數(shù)的小數(shù)位數(shù)之和。 對乘法進(jìn)行截取時,為了保證結(jié)果正確,只能取高位,舍棄低位。 只有在兩個乘數(shù)均能表示最小負(fù)數(shù)時,才能拿出現(xiàn)最高位和次高位不同情況。 (最高位為1,其余為0),只有在這種情況下需要M+N位的數(shù)來存放結(jié)果,其他情況下,只需要M+N-1位來存放結(jié)果。
乘加法運(yùn)算的有效數(shù)據(jù)位
在數(shù)字信號處理中,通常會遇到乘加運(yùn)算的情況,一個典型的例子就是有限脈沖響應(yīng)(Finite Impulse Response,F(xiàn)IR)濾波器的設(shè)計(jì)。 當(dāng)乘法系數(shù)是常量時,最終運(yùn)算結(jié)果的有效數(shù)據(jù)數(shù)據(jù)位根據(jù)常量的大小來重新計(jì)算。 假設(shè)乘加運(yùn)算的變量輸入是N位的數(shù)據(jù),乘加運(yùn)算的輸出有效數(shù)據(jù)位計(jì)算如下:計(jì)算所有常數(shù)乘數(shù)絕對值之和SUM,算出SUM所占用的二進(jìn)制數(shù)據(jù)位n,則乘加運(yùn)算的輸出的有效數(shù)據(jù)位數(shù)為N+n。
有限字長效應(yīng)
數(shù)字信號處理的實(shí)質(zhì)是一組數(shù)值運(yùn)算,這些運(yùn)算可以在計(jì)算機(jī)上用軟件實(shí)現(xiàn),也可以用專門的硬件實(shí)現(xiàn)。 無論哪種實(shí)現(xiàn)方式,數(shù)字信號處理系統(tǒng)的一些系數(shù)、信號序列的各個數(shù)值及運(yùn)算結(jié)果都要以二進(jìn)制形式存儲在有限字長的存儲單元中。 如果存儲的是模擬信號,例如常用的采樣信號處理系統(tǒng),輸入的模擬量經(jīng)過采樣和模數(shù)轉(zhuǎn)換后,變成有限長的數(shù)字信號。 有限長的數(shù)就是有限精度的數(shù)。 因此,具體實(shí)現(xiàn)中往往難以保證原設(shè)計(jì)精度而產(chǎn)生誤差,甚至導(dǎo)致錯誤的結(jié)果。 在數(shù)字系統(tǒng)中主要有三種因有限字長而引起誤差的因素:
- 模數(shù)轉(zhuǎn)換器把模擬輸入信號轉(zhuǎn)換為數(shù)字信號時產(chǎn)生的量化效應(yīng)
- 把系數(shù)用有限位二進(jìn)制表示時產(chǎn)生的量化效應(yīng)
- 數(shù)字運(yùn)算過程中,為限制位數(shù)進(jìn)行的位數(shù)處理和為防止溢出而壓縮信號電平的有限字長效應(yīng)
引起這些誤差的根本原因在于寄存器(存儲單元)的字長有限。 誤差的特性與系統(tǒng)的類型、結(jié)構(gòu)形式、數(shù)字的表示法、運(yùn)算方式及字的長短有關(guān)。 在通用計(jì)算機(jī)上,字長較長,量化步很小,量化誤差不大。 但在專用硬件,如FPGA,實(shí)現(xiàn)數(shù)字系統(tǒng)時,其字長較短,就必須考慮有限字長效應(yīng)了。
-
matlab
+關(guān)注
關(guān)注
185文章
2976瀏覽量
230495 -
數(shù)字濾波器
+關(guān)注
關(guān)注
4文章
270瀏覽量
47026 -
計(jì)算機(jī)
+關(guān)注
關(guān)注
19文章
7494瀏覽量
87981 -
數(shù)字信號處理
+關(guān)注
關(guān)注
15文章
560瀏覽量
45863 -
Verilog
+關(guān)注
關(guān)注
28文章
1351瀏覽量
110107
發(fā)布評論請先 登錄
相關(guān)推薦
評論