快速計算正弦波

2021-05-28 12:38:16 字數 2494 閱讀 9438

快速計算正弦波

在dsp運用中,經常需要產生正弦波。如果直接用c的數學函式sin,當然可以產生正弦波,但是由於sin函式本身的效率很低,產生正弦波所需要的mips就會占去dsp處理能力的相當大的一部分。本章介用遞推數列算正弦波的方法,先介紹原理,推導出遞推公式,然後用浮點小數實現計算,再用定點小數進一步優化演算法,最後進行誤差分析,並提出更精確的定點小數演算法。

先來看看如何推導出遞推數列的公式。

我們所要產生的正弦波,其實是一系列的整數,把這些整數按照一定的取樣頻率傳送給數模轉換器,就可以變成真正的正弦波了。假設取樣週期是ts,產生的正弦波的圓頻率為w,那麼我們需要產生的數列就是:

sin(0), sin(w*ts), sin(2*w*ts), ... sin(n*w*ts)

假設f(n)= sin(n*w*ts),則問題就變成,從f(n-1), f(n-2), f(n-3),..., 如何計算f(n)了。解決了這個問題,也就找到了遞推公式。

下面是這個遞推公式的求解過程,假設x=w*ts:

公式:sin( a + b) = sin(a)*cos(b) + cos(a)*sin(b)

sin( x + (n-1)x ) = sin(x)*cos( (n-1)x ) + cos(x)*sin( (n-1)x )

公式:sin(a)*cos(b) = 1/2 * [ sin( a+b ) + sin( a-b ) ]

sin(x)*cos( (n-1)x ) = 1/2 * [ sin(nx) - sin( (n-2)x ) ]

sin(nx) = 1/2 * [ sin(nx) - sin( (n-2)x ) ] + cos(x)*sin( (n-1)x )

sin(nx) = 2*cos(x)*sin( (n-1)x ) - sin( (n-2)x )

我們看到這個遞推公式是:

f(n)=2*cos(w*ts)*f(n-1) - f(n-2)

也就是說只要知道最初始的兩項f(0)和f(1),就可以計算出整個正弦波了。

根據上面的遞推公式,很容易寫出下面的正弦波計算程式。只要事先計算一次sin(w*ts)和cos(w*ts),以後的值就可以通過遞推公式得到,所以計算乙個值所需要的工作就是一次乘法,一次加法,兩次變數複製而已了。

以下內容為程式**:

float y[3] = ; // y(n), y(n-1), y(n-2)

float a1=2*cos(w*ts);

float a2=-1;

float singen()

假如我們需要產生取樣頻率為8khz的440hz的正弦波,那麼a1=2*cos(2*pi*440/8000)=1.8817615,而y[1]=sin(2*pi*440/8000)=0.33873792。

現在看如何用定點小數來更快的計算正弦波。我們使用16bit也就是short型的整數來表示定點小數。首先需要決定的是小數的q值,雖然我們最後計算的正弦波的值都是小於1的,但是在計算過程中需要用2*cos(w*ts),而這個值最大為2,所以我們選擇的q值必須至少最大能表示2。這裡我們選擇 q14,q14的定點小數能表示-2到2的取值範圍,對於本例的正弦波計算正好合適。1.8817615的q14值是1.8817615*2^14= 5550=0x786f,同樣0.33873792的q14值為0x15ae。

下面就是完整的計算8khz取樣頻率的400hz的定點小數的正弦波的程式。

以下內容為程式**:

short y[3] = ; // y(n), y(n-1), y(n-2)

short a1=0x786f;

short a2=0xc000;

short singen()

使用定點小數計算不但速度比浮點更快,而且計算得出來的值是整數,這個數值可以直接傳遞給dac(數模轉換器)轉換為模擬的聲音頻號,如果使用浮點小數計算的話,還必須把浮點數轉換為整數才能傳遞給dac。

使用定點小數計算必須仔細分析誤差,下面來看看我們產生的正弦波的誤差是多少。定點小數計算中的誤差就是由定點小數表達精度決定的。在上面的例子中我們用 0x786f表示1.8817615,這存在一定的誤差,把q14的0x786f再轉換為浮點數就是0x786f/2^14=1.8817749,我們可以看到相對誤差非常小,也就是說最終得到的正弦波在頻率上的誤差也是非常小的。

但是,定點小數並不是什麼時候都這麼精確。例如如果用cd 音質的取樣頻率44100hz來產生100hz的正弦波,那麼a1=2*cos(2*pi*440/44100)= 1.9960713,這個數轉換為16位元的q14的值是0x7fc0。我們可以看到這時定點小數已經十分接近0x7fff了,最終產生的正弦波的頻率也會有很大的誤差。為了能夠精確地計算這樣的正弦波,必須使用32bit的q30定點小數。關於32bit定點小數的計算方法將在別的章節介紹。

另外上面的singen函式每呼叫一次只產生乙個值,如果要產生實時的正弦波的話,函式的呼叫頻率和取樣頻率相同,dsp的負擔相對比較大。一般dsp計算都採取塊計算方式,一次計算n個(例如64)個取樣值,這樣不但減少了函式的呼叫負擔,也可以減少中間的記憶體移動的次數(y[2]=y[1];y[1]= y[0];)

正弦波振盪器

高頻電子線路課程設計 正弦波振盪器 1.振盪電路部分 本實驗要求是產生10.7mhz的 波形,選用西勒電路。在西勒電路中,c4與l併聯,所以它的變化不會改變迴路的接入係數,可是可以通過調節它來改變電路的振盪頻率。根據上式以及實驗要求的振盪頻率,可以計算得 選用 l 30pf,選用了100pf 的可變...

關於正弦波的演算法

剛剛來到了乙個新的公司工作,以前是做bs專案的,而這個公司則是做cs專案,於是各種凌亂。最要命的是需要寫各種演算法,這讓咱這個數學成績極度可恥的人各種鬱悶。在專案中的正弦波演算法咱就鬱悶了好久,後來才發現如此的簡單。為了防止咱再次忘掉,果然還是記下來為好。list pointx new list l...

用記憶體占用曲線畫正弦波

今天突然想起原來看用cpu使用率曲線畫正弦波,於是打算換個思路用記憶體佔用率畫正弦波形。主要用到malloc函式和free函式來操作記憶體。畢竟我不是acmer所以就中規中矩的寫。首先實現矩形波。首先找找思路,先寫函式介面,這是乙個很好的程式設計習慣。那麼就 int occupy mbyte int...