新聞中心

EEPW首頁 > 汽車電子 > 學(xué)習(xí)方法與實(shí)踐 > 獻(xiàn)給DSP初學(xué)者

獻(xiàn)給DSP初學(xué)者

——
作者: 時(shí)間:2007-12-14 來源: 收藏
對(duì)于沒有使用過者來說,第一個(gè)困惑就是其他的嵌入式處理器究竟有什么不同,它和單片機(jī),ARM有什么區(qū)別。事實(shí)上,也是一種嵌入式處理器,它完全可以完成單片機(jī)的功能。
唯一的重要的區(qū)別在于DSP支持單時(shí)鐘周期的"乘-加"運(yùn)算。這幾乎是所有廠家的DSP芯片的一個(gè)共有特征。幾乎所有的DSP處理器的指令集中都會(huì)有一條MAC指令,這條指令可以把兩個(gè)操作數(shù)從RAM中取出相乘,然后加到一個(gè)累加器中,所有這些操作都在一個(gè)時(shí)鐘周期內(nèi)完成。擁有這樣一條指令的處理器就具備了DSP功能。
具有這條指令就稱之為數(shù)字信號(hào)處理器的原因在于,所有的數(shù)字信號(hào)處理算法中最為常見的算術(shù)操作就是"乘-加"。這是因?yàn)閿?shù)字信號(hào)處理中大量使用了內(nèi)積,或稱"點(diǎn)積"的運(yùn)算。無論是FIR濾波,F(xiàn)FT,信號(hào)相關(guān),數(shù)字混頻,下變頻。所有這些數(shù)字信號(hào)處理的運(yùn)算經(jīng)常是將輸入信號(hào)與一個(gè)系數(shù)表或者與一個(gè)本地參考信號(hào)相乘然后積分(累加),這就表現(xiàn)為將兩個(gè)向量(或稱序列)進(jìn)行點(diǎn)積,在編程上就變成將輸入的采樣放在一個(gè)循環(huán)buffer里,本地的系數(shù)表或參考信號(hào)也放在一個(gè)buffer里,然后使用兩個(gè)指針指向這兩個(gè)buffer。這樣就可以在一個(gè)loop里面使用一個(gè)MAC指令將二者進(jìn)行點(diǎn)積運(yùn)算。這樣的點(diǎn)積運(yùn)算對(duì)與處理器來說是最快的,因?yàn)閮H需一個(gè)始終周期就可以完成一次乘加。
了解DSP的這一特點(diǎn)后,當(dāng)我們?cè)O(shè)計(jì)一個(gè)嵌入式系統(tǒng)時(shí),首先要考慮處理器所實(shí)現(xiàn)的算法中是否有點(diǎn)積運(yùn)算,即是否要經(jīng)常進(jìn)行兩個(gè)數(shù)組的乘加,(記住數(shù)字濾波,相關(guān)等都表現(xiàn)為兩個(gè)數(shù)組的點(diǎn)積)如果有的話,每秒要做多少次,這樣就能夠決定是否采用DSP,采用多高性能的DSP了。

浮點(diǎn)與定點(diǎn)

浮點(diǎn)與定點(diǎn)也是經(jīng)常是者困惑的問題,在選擇DSP器件的時(shí)候,是采用浮點(diǎn)還是采用定點(diǎn),如果用定點(diǎn)是16位還是32位?其實(shí)這個(gè)問題和你的算法所要求的信號(hào)的動(dòng)態(tài)范圍有關(guān)。
定點(diǎn)的計(jì)算不過是把一個(gè)數(shù)據(jù)當(dāng)作整數(shù)來處理,通常AD采樣來的都是整數(shù),這個(gè)數(shù)相對(duì)于真實(shí)的模擬信號(hào)有一個(gè)刻度因子,大家都知道用一個(gè)16位的AD去采樣一個(gè)0到5V的信號(hào),那么AD輸出的整數(shù)除以2^16再乘以5V就是對(duì)應(yīng)的電壓。在定點(diǎn)DSP中是直接對(duì)這個(gè)16位的采樣進(jìn)行處理,并不將它轉(zhuǎn)換成以小數(shù)表示的電壓,因?yàn)槎c(diǎn)DSP無法以足夠的精度表示一個(gè)小數(shù),它只能對(duì)整數(shù)進(jìn)行計(jì)算。而浮點(diǎn)DSP的優(yōu)勢(shì)在于它可以把這個(gè)采樣得到的整數(shù)轉(zhuǎn)換成小數(shù)表示的電壓,并不損失精度(這個(gè)小數(shù)用科學(xué)記數(shù)法來表示),原因在于科學(xué)記數(shù)法可以表示很大的動(dòng)態(tài)范圍的一個(gè)信號(hào),以IEEE754浮點(diǎn)數(shù)為例,單精度浮點(diǎn)格式: [31] 1位符號(hào) [30-23]8位指數(shù) [22-00]23位小數(shù),這樣的能表示的最小的數(shù)是+-2^-149,最大的數(shù)是+-(2-2^23)*2^127.動(dòng)態(tài)范圍為20*log(最大的數(shù)/最小的數(shù))=1667.6dB 這樣大的動(dòng)態(tài)范圍使得我們?cè)诰幊痰臅r(shí)候幾乎不必考慮乘法和累加的溢出,而如果使用定點(diǎn)處理器編程,對(duì)計(jì)算結(jié)果進(jìn)行舍入和移位則是家常便飯,這在一定程度上會(huì)損失是精度。原因在于定點(diǎn)處理處理的信號(hào)的動(dòng)態(tài)范圍有限,比如16位定點(diǎn)DSP,可以表示整數(shù)范圍為1-65536,其動(dòng)態(tài)范圍為20*log(65536/1)=96dB.對(duì)于32定點(diǎn)DSP,動(dòng)態(tài)范圍為20*log(2^32/1)=192dB,遠(yuǎn)小于32位ieee浮點(diǎn)數(shù)的1667.6dB,但是,實(shí)際上192dB對(duì)絕大多數(shù)應(yīng)用所處理的信號(hào)已經(jīng)足夠了。
由于AD轉(zhuǎn)換器的位數(shù)限制,一般輸入信號(hào)的動(dòng)態(tài)范圍都比較小,但在DSP的信號(hào)處理中,由于點(diǎn)積運(yùn)算會(huì)使中間節(jié)點(diǎn)信號(hào)的動(dòng)態(tài)范圍增加,所以主要考慮信號(hào)處理流程中中間結(jié)果的動(dòng)態(tài)范圍,以及算法對(duì)中間結(jié)果的精度要求,來選擇相應(yīng)的DSP。另外就是浮點(diǎn)的DSP更易于編程,定點(diǎn)DSP編程中程序員要不斷調(diào)整中間結(jié)果的P,Q值,實(shí)際就是不斷對(duì)中間結(jié)果進(jìn)行移位調(diào)整和舍入。

DSP與RTOS

TI的CCS提供BIOS,ADI的VDSP提供VDK,都是基于各自DSP的嵌入式多任務(wù)內(nèi)核。DSP編程可以用單用C,也可以用匯編,或者二者結(jié)合,一般軟件編譯工具都提供了很好的支持。我不想在這里多說BIOS,VDK怎么用這在相應(yīng)的文檔里說的很詳細(xì)。我想給者說說DSP的RTOS原理。用短短幾段話說這個(gè)復(fù)雜的東西也是挑戰(zhàn)!^_^

其實(shí)DSP的RTOS和基于其他處理器的通用RTOS沒什么大的區(qū)別,現(xiàn)在幾乎人人皆知的uCOSii也很容易移植到DSP上來,只要把寄存器保存與恢復(fù)部分和堆棧部分改改就可以。一般在用BIOS和VDK之前,先看看操作系統(tǒng)原理的書比較好。uCOS那本書也不錯(cuò)。
BIOS和VDK其實(shí)是一個(gè)RTOS內(nèi)核函數(shù)集,DSP的應(yīng)用程序會(huì)和這些函數(shù)連接成一個(gè)可執(zhí)行文件。其實(shí)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的多任務(wù)內(nèi)核并不復(fù)雜,首先定義好內(nèi)核的各種數(shù)據(jù)結(jié)構(gòu),然后寫一個(gè)scheduler函數(shù),功能是從所有就緒任務(wù)中(通過查找就緒任務(wù)隊(duì)列或就緒任務(wù)表)找出優(yōu)先級(jí)最高的任務(wù),并恢復(fù)其執(zhí)行。然后在此基礎(chǔ)上寫幾個(gè)用于任務(wù)間通信的函數(shù)就可以了,比如event,message box,等等。
RTOS一般采用搶先式的任務(wù)調(diào)度方式,舉例說當(dāng)任務(wù)A等待的資源available的時(shí)候,DSP會(huì)執(zhí)行一個(gè)任務(wù)調(diào)度函數(shù)scheduler,這個(gè)函數(shù)會(huì)檢查當(dāng)前任務(wù)是否比任務(wù)A優(yōu)先級(jí)低,如果是的話,就會(huì)把它當(dāng)前掛起,然后把任務(wù)A保存在堆棧里寄存器值全部pop到DSP處理器中(這就是所謂的任務(wù)現(xiàn)場(chǎng)恢復(fù))。接著scheduler還會(huì)把從堆棧中取出任務(wù)A掛起時(shí)的程序執(zhí)行的地址,pop到PC,使任務(wù)A繼續(xù)執(zhí)行。這樣當(dāng)前任務(wù)就被任務(wù)A搶先了。
使用RTOS之后,每個(gè)任務(wù)都會(huì)有一個(gè)主函數(shù),這個(gè)函數(shù)的起始地址就是該任務(wù)的入口。一般每個(gè)任務(wù)的主函數(shù)里有一個(gè)死循環(huán),這個(gè)循環(huán)使該任務(wù)周期地執(zhí)行,完成一部分算法模塊的功能,其實(shí)這個(gè)函數(shù)跟普通函數(shù)沒任何區(qū)別,類似于C語言中的main函數(shù)。一個(gè)任務(wù)創(chuàng)建的時(shí)候,RTOS會(huì)把這個(gè)函數(shù)入口地址壓入任務(wù)的堆棧中,好象這個(gè)函數(shù)(任務(wù))剛發(fā)生過一次中斷一樣。一旦這個(gè)新創(chuàng)建任務(wù)的優(yōu)先級(jí)在就緒隊(duì)列中是最高的,RTOS就會(huì)從其堆棧中彈出其入口地址開始執(zhí)行。
有一個(gè)疑問是,不使用RTOS,而是簡(jiǎn)單使用一個(gè)主循環(huán)在程序中調(diào)用各個(gè)函數(shù)模塊,一樣可以實(shí)現(xiàn)軟件的調(diào)度執(zhí)行。那么,這種常用的方法與使用RTOS相比有什么區(qū)別呢?其實(shí),使用主循環(huán)的方法不過是一種沒有優(yōu)先級(jí)的順序執(zhí)行的調(diào)度策略而已。這種方法的缺點(diǎn)在于,主循環(huán)中調(diào)用的各個(gè)函數(shù)是順序執(zhí)行的,那么,即使是一個(gè)無關(guān)緊要的函數(shù)(比如閃爍一個(gè)LED),只要他不主動(dòng)返回,也會(huì)一直執(zhí)行直到結(jié)束,這時(shí),如果發(fā)生一個(gè)重要的事件(比如DMA buffer full 中斷),就會(huì)得不到及時(shí)的響應(yīng)和處理,只能等到那個(gè)閃爍LED的函數(shù)執(zhí)行完畢。這樣就使整個(gè)DSP處理的優(yōu)先次序十分不合理。而在使用了RTOS之后,當(dāng)一個(gè)重要的事件發(fā)生時(shí),中斷處理會(huì)進(jìn)入RTOS,并調(diào)用scheduler,這時(shí)scheduler 會(huì)讓處理這一事件的任務(wù)搶占DSP處理器(因?yàn)樗膬?yōu)先級(jí)高)。而哪個(gè)閃爍LED任務(wù)即使晚執(zhí)行幾毫秒都沒任何影響。這樣整個(gè)DSP的調(diào)度策略就十分合理。
RTOS要說的內(nèi)容太多,我只能講一下自己的一點(diǎn)體會(huì)吧

DSP與正(余)弦波

在DSP的應(yīng)用中,我們經(jīng)常要用到三角函數(shù),或者合成一個(gè)正(余)弦波。這是因?yàn)槲覀兿矚g把信號(hào)通過傅立葉變換映射到三角函數(shù)空間來理解信號(hào)的頻率特性。信號(hào)處理的一些計(jì)算技巧都需要在DSP軟件中進(jìn)行三角函數(shù)計(jì)算。然而三角函數(shù)計(jì)算是非線性的計(jì)算,DSP并沒有專門的指令來求一個(gè)數(shù)的正弦或余弦。于是我們需要用線性方法來近似求解。
一個(gè)直接的想法是用多項(xiàng)式擬合,這也正是大多數(shù)DSP C編譯器提供正余弦?guī)旌瘮?shù)所采用的方法。其原理是把三角函數(shù)向函數(shù)空間{1,x,x^2,x^3....}上投影,從而獲得一系列的系數(shù),用這些系數(shù)就可以擬合出三角函數(shù)。比如,我們?cè)赱0,pi/2]區(qū)間上擬合sin,只需在matlab中輸入以下命令:
x=0:0.05:pi/2;
p=polyfit(x,sin(x),5)
就得到5階的多項(xiàng)式系數(shù):
p =
0.00581052047605 0.00580963216172 -0.17193865685360
0.00209002716293 0.99969270087312 0.00000809543448
于是在[0,pi/2]區(qū)間上:
sin(x)= 0.00000809543448+0.99969270087312*x+ 0.00209002716293*x^2-0.17193865685360*x^3+
0.00580963216172*x^4+0.00581052047605*x^5
于是在DSP程序中,我們可以通過用乘加(MAC)指令計(jì)算這個(gè)多項(xiàng)式來近似求得sin(x)
當(dāng)然如果用定點(diǎn)DSP還要把P這個(gè)多項(xiàng)式系數(shù)表用一定的Q值來改寫成定點(diǎn)數(shù)。

這樣的三角函數(shù)計(jì)算一般都需要幾十個(gè)cycle 的開銷。這對(duì)于某些場(chǎng)合是不能容忍的

另一種更快的方法是借助于查表,比如,我們將[0,pi/2]分成32個(gè)區(qū)間,每個(gè)區(qū)間長(zhǎng)度就為pi/64,在每個(gè)區(qū)間上我們使用直線段擬合sin曲線,每個(gè)區(qū)間線段起點(diǎn)的正弦值和線段斜率事先算好,存在RAM里,這樣就需要在在RAM里存儲(chǔ)64個(gè)
常數(shù):
32個(gè)起點(diǎn)的精確的正弦值(事先算好): s[32]={0,sin(pi/64),sin(pi/32),sin(pi/16)....}
32個(gè)線段的斜率: f[32]={0.049,.....}
對(duì)于輸入的每一個(gè)x,先根據(jù)其大小找到所在區(qū)間i,通常x用定點(diǎn)表示,一般取其高幾位就是系數(shù)i了,然后通過下式即可求出sin(x):
sin(x)= s[i]*f[i]
這樣一般只需幾個(gè)CYCLE就可以算出正弦值,如果需要更高的精度,可以將區(qū)間分得更細(xì),當(dāng)然,也就需要更多的RAM去存儲(chǔ)常數(shù)表。
事實(shí)上,不僅三角函數(shù),其他的各種非線性函數(shù)都是這樣近似計(jì)算的。



關(guān)鍵詞: DSP 初學(xué)

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉