最近在業餘的時間裏一直在搞C++ 版本的FM解調程序,使用的硬件是RTLSDR, 很便宜的一個淘寶貨,FM解調的C++代碼網上有很多,但是很多都是linux 下的, 嫌麻煩,又要裝虛擬機之類的,(其實後來還是迫不得已裝了),想在WIN7下實現,用的是VS2015,網上還沒有現成的代碼,都是自己東拼西湊的。
代碼涉及的技術:
- RTLSDR的IQ數據獲取
- FM的解調
- 信號濾波
- 音頻播放
- 多線程,線程間通信,資源衝突
- 數據緩衝,緩存
- 程序速度問題
- 界面
- FFT頻譜
別小看這麼一個收音機程序,這裏所涉及的知識足以讓一個工程師搞上一陣子,要把這麼多東西柔和在一起,不但需要紮實的射頻功底,也是非常鍛鍊C++功底的。其實搞這個RTL的收音機程序最主要目的是鍛鍊自己C++代碼搬磚。
最核心的,FM的解調代碼部分最主要是參考這個JvanKatwijk老大爺的,一個退休的工程師。
https://github.com/JvanKatwijk
https://www.sdr-j.tk/index.html
音頻播放,WIN7下我找到了兩種方式的聲音播放方法。
- Windows WaveOut, 用這個最主要是如何處理好音頻數據緩衝,以及音頻數據格式的轉換, 一般來說解調完的FM信號是double類型的,需要轉換成Int16聲卡可以接受的形式, 數據的緩衝可以參考這篇double buffering的文章,
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=4422&lngWId=3
- LabVIEW有個lvsound2.dll,這個其實好用多了,只管往裏丟數據
多線程的問題
IQ數據獲取 -> 濾波 -> FM解調 -> audio播放, 這些必要的操作有的快有的慢,不可能只放在一個線程裏操作,電波里傳來的FM信號是連續的,需要實時不斷的處理這些信號,可以參考JvanKatwijk這個老傢伙的處理方法,其實就是生產者-消費者的模式,實際就是
- IQ數據獲取一個線程(生產者1)
- FM解調一個線程(消費者1,同時也是生產者2--音頻數據的生產者)
- Audio播放一個線程(消費者2)
這裏最大的問題是大量的數據如何在線程間傳遞,消費者如果處理不過來,最終播放的時候會產生嚴重的卡頓。
速度問題
如果程序的運行速度不夠快,不管是多線程還是單線程,音頻播放都會出現卡頓。在這裏,FM的解碼(decode)部分是最慢最佔資源的函數,由於FM的解碼太慢,單一線程解碼不夠快,聲音播放卡頓,,於是嘗試開闢了10個線程同時進行FM解碼,結果發現解碼更慢了,線程越多是有代價的,各種線程的花銷,和線程間的切換,導致了FM 解碼更慢。所以最終還是回到了一個FM解碼線程的結構。
提高VS2015代碼運行速度的方法:
- 有debug模式改爲release模式,這可以讓執行程序快好幾十倍。
- 項目屬性 --> C/C++ --> Optimization, 選擇最大速度,速度優先等等,如下圖。這也可以讓程序快很多。