c++ 计算正弦的近似值_一篇文章搞懂正弦保真性
本文介紹數(shù)字信號處理中“正弦保真性”這一概念,想要更好地理解本文所述內(nèi)容,建議讀者先閱讀《一篇文章搞懂卷積》。
正弦保真性定義
一個正弦信號作為線性時不變系統(tǒng)的輸入時,對應(yīng)的輸出信號一定也為正弦信號。輸出正弦信號的振幅和相位相比于輸入正弦信號會發(fā)生變化,然而輸出正弦信號的頻率始終等于輸入正弦信號的頻率。
一種等價的定義
我們知道想要得到一個線性時不變系統(tǒng)的輸出,我們所需的操作是求取輸入信號和系統(tǒng)的單位脈沖響應(yīng)的卷積,因此正弦保真性可以翻譯為,正弦信號和任何信號的卷積均為正弦信號(同頻率,不同相位不同振幅)。
正弦保真性的驗證
如果我們可以驗證正弦信號與任意信號的卷積仍為正弦信號,我們就驗證了正弦保真性。整體驗證過程代碼粘貼如下,這里使用到了《一篇文章搞懂卷積》中設(shè)計的卷積計算接口(頭文件“Convolution.h”的內(nèi)容請參考《一篇文章搞懂卷積》)。
#include <iostream> #include <fstream>#include "Convolution.h"using namespace std;const float C_PI_F = 3.1415926535897F; const float C_2PI_F = 2 * C_PI_F;void GenerateSinSignal(const string &signalFileName,int nSampleNumPerCycle,int nCycleNum,float amplitude,float frequency,float phase) {int nTotalSampleNum = nSampleNumPerCycle * nCycleNum;vector<float> signal(nTotalSampleNum, 0.0F);float radianStep = 1 / frequency / nSampleNumPerCycle;for (int i = 0; i < nTotalSampleNum; ++i) {float radian = radianStep * i;signal[i] = amplitude * sinf(C_2PI_F*frequency*radian + phase);}ofstream ofs;ofs.open(signalFileName, ios::binary);if (!ofs.good()) {throw exception("Create sin signal failed");}ofs.write((char*)signal.data(), nTotalSampleNum * sizeof(float));ofs.close(); }// case2: test sinusoidal fidelity int case2(const string &dataPath) {try {int nSamplePerCycle = 100;int nCycle = 5;//GenerateSinSignal(// dataPath + "case2sinSignal.dat",// nSamplePerCycle,// nCycle,// 6.0F,// 1.0F / C_PI_F,// C_PI_F / 3.0F);int nInSignalNum = nSamplePerCycle * nCycle;vector<float> inSignal(nInSignalNum, 0.0F);ifstream ifs;ifs.open(dataPath + "case2sinSignal.dat", ios::binary);if (!ifs.good()) {throw exception("Read sin signal failed");}ifs.read((char*)inSignal.data(), nInSignalNum * sizeof(float));ifs.close();vector<float> h = { 1.0F,2.0F,2.0F,3.0F,4.0F,5.0F,100.0F,-200.9F };Convolution<float> conv;vector<float> outSignal = conv.ExecuteInputView(inSignal, h);int outSignalNum = static_cast<int>(outSignal.size());ofstream ofs;ofs.open(dataPath + "case2outSignal.dat", ios::binary);if (!ofs.good()) {throw exception("Write out signal of sin failed");}ofs.write((char*)outSignal.data(), outSignalNum * sizeof(float));ofs.close();}catch (const exception &e) {cerr << "UTConvolution exception:" << e.what() << endl;return 1;}return 0; }int main(int argc, char **argv) {if (argc != 2) {cerr << "UTConvolution need data folder." << endl;return 1;}string dataPath = argv[1];if (case2(dataPath)){return 1;}cout << "UTConvolution pass." << endl;return 0; }Step1:使用GenerateSinSignal函數(shù)生成一組離散正弦信號(函數(shù)的各個參數(shù)的含義如下面代碼所示),本例產(chǎn)生的正弦信號擁有五個周期,每個周期有100個采樣點,正弦信號的振幅為6,正弦信號的頻率為
,正弦信號的相位為 ,輸入信號共有500個元素。void GenerateSinSignal(const string &signalFileName, //正弦信號保存成的二進制文件名int nSampleNumPerCycle, //正弦信號每個周期的采樣點數(shù)量int nCycleNum, //正弦信號的周期個數(shù)float amplitude, //正弦信號的振幅float frequency, //正弦信號的頻率float phase); //正弦信號的相位生成的輸入正弦信號如Fig.1所示,當首次使用文中代碼的時候需要將函數(shù)case2中的GenerateSinSignal注釋去掉,用以生成輸入正弦信號并以二進制的形式寫入文件,當生成完正弦信號后,就可以將GenerateSinSignal注釋,從而每次都從已保存的文件中讀取同一個輸入正弦信號。
Fig.1. 輸入正弦信號1Step2:和輸入正弦信號做卷積的信號為h[n]={1.0F,2.0F,2.0F,3.0F,4.0F,5.0F,100.0F,-200.9F} 這是我隨便編寫的一個信號(具備任意性)。讀者可以自己嘗試任意不同的信號。
Step3:使用Convolution<float>類進行卷積的計算,將輸出信號以二進制形式保存成文件。輸出信號如Fig.2所示,由于輸入信號有500個元素,h[n]有8個元素,因此輸出信號有507個元素(500+8-1)。
Fig.2. 輸出信號1我們可以觀察到,輸出信號也是正弦信號,并且輸出信號的頻率與輸入信號一致。但輸出信號的振幅較輸入信號發(fā)生了改變,同時輸出信號的相位較輸入信號也發(fā)生了改變。到這里我們就驗證完了正弦保真性。
正弦保真性研究(實驗一)
讓我們來做下面這樣的實驗,我們將輸入的正弦信號做如下變更:正弦信號的振幅變?yōu)?2(原來的二倍),正弦信號的相位變?yōu)?
,其余保持不變。輸入正弦信號如下圖所示:Fig.3. 輸入正弦信號2我們讓該正弦信號與上文中同樣的信號h[n]={1.0F,2.0F,2.0F,3.0F,4.0F,5.0F,100.0F,-200.9F}做卷積,得到的輸出信號如下Fig.4所示。
Fig.4. 輸出信號2從新的輸出信號我們可以觀察到如下現(xiàn)象:(1)輸入信號2的振幅變?yōu)檩斎胄盘?的振幅的2倍,輸出信號2的振幅也變?yōu)榱溯敵鲂盘?的振幅的2倍。(2)輸入信號2的相位相對于輸入信號1向左平移了
,輸出信號2的相位相對于輸出信號1也向左平移了 。這兩個現(xiàn)象正好可以反應(yīng)出線性時不變系統(tǒng)的齊次性和時不變性。同時該實驗也說明了,該系統(tǒng)對輸入正弦信號1和輸入正弦信號2的作用是相同的,即:
(1)保持輸入信號頻率不變;
(2)輸出信號的振幅是輸入信號振幅的固定常數(shù)倍
;(3)輸出信號的相位和輸入信號的相位差也是一個固定值
。正弦保真性研究(實驗二)
根據(jù)實驗一我們猜測上文中提到的線性時不變系統(tǒng)(脈沖響應(yīng)h[n]={1.0F,2.0F,2.0F,3.0F,4.0F,5.0F,100.0F,-200.9F}),對任何正弦信號的作用均為:
(1)保持輸入信號頻率不變;
(2)輸出信號的振幅是輸入信號振幅的固定常數(shù)倍
;(3)輸出信號的相位和輸入信號的相位差也是一個固定值
。為驗證這個猜想我們設(shè)計了實驗二:使用一個和輸入正弦信號1沒什么關(guān)系的另一個正弦信號。本例產(chǎn)生的正弦信號擁有3個周期,每個周期有100個采樣點,正弦信號的振幅為4.5,正弦信號的頻率為
,正弦信號的相位為 ,輸入信號共有300個元素,輸入正弦信號3如下圖所示:Fig.5. 輸入正弦信號3我們讓該正弦信號與同樣的信號h[n]={1.0F,2.0F,2.0F,3.0F,4.0F,5.0F,100.0F,-200.9F}做卷積,得到的輸出信號如下Fig.6所示。
Fig.6. 輸出信號3觀察輸出信號3可知:我們猜測的該系統(tǒng)對任意正弦信號作用的第一條和第二條都是正確的,而第三條在本例中并不滿足,因為本例中輸出信號的相位和輸入信號的相位差是
,但請大家注意,本例中正弦信號的周期為 ,因此我們的第三條猜測應(yīng)該更正為:輸出信號相位和輸入信號的相位差為 。因此我們可以得出如下結(jié)論:線性時不變系統(tǒng)對所有正弦信號的作用效果相同,如果我們知道了一個線性時不變系統(tǒng)對任意一個正弦信號的響應(yīng),我們就可以知道該系統(tǒng)對所有正弦信號的響應(yīng)。
我們又知道,我們可以將任意離散信號通過傅里葉分解,分解成多個正弦余弦信號,因此我們可以結(jié)合線性時不變系統(tǒng)對任意正弦信號的響應(yīng)和傅里葉分解,得出該線性時不變系統(tǒng)對任意離散信號的輸出。
以上是本人對正弦保真性的理解,其中難免有紕漏,歡迎大家在下方留言批評指正,我一定會認真對待!!!(順便說一下,文中顯示正弦曲線的軟件時一款好用的開源軟件——imageJ,感興趣的讀者可以去官網(wǎng)下載使用)。
總結(jié)
以上是生活随笔為你收集整理的c++ 计算正弦的近似值_一篇文章搞懂正弦保真性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 携程_python 携程爬
- 下一篇: 1G服务器网站,1核1g内存云服务器建网