2011-02-12 65 views
20

我有一個二進制數據流,想將其轉換爲原始波形聲音數據,我可以發送給揚聲器。數據到音頻和返回。調製/解調源代碼

這是舊學校的調制解調器爲了在電話線上傳輸二進制數據(產生典型的現代聲音)所做的。它被稱爲調製。

然後我需要一個反向過程 - 從原始波形樣本中,我想獲得確切的二進制數據。這被稱爲解調。

  • 任何比特率都可用於開始。
  • 使用電腦揚聲器播放聲音,並使用麥克風採樣。
  • 帶寬不會很寬(低質量麥克風)。
  • 有一些背景噪音,但不是很多。

我發現了一種特殊的方式來做到這一點 - Frequency shift keying。問題是我找不到任何源代碼。

你可以指點我在任何語言的FSK的實現嗎?
或提供任何替代編碼二進制< - >聲音與可用的源代碼?

+1

我在下面給出了一個通用的答案,但如果你明確了你的要求,我可以更具體。你在找什麼比特率?如何播放音頻信號(電腦揚聲器?)和採樣(麥克風?)。任何有關您期待的音頻帶寬和噪音的細節... – 2011-02-12 05:00:01

+0

非常感謝。任何比特率都可以用於開始。聲音使用電腦揚聲器播放,並使用麥克風採樣。帶寬不會很寬(低質量麥克風)。有一些背景噪音,但不是很多。 – 2011-02-12 11:15:36

+1

這聽起來並不像聽起來那麼老舊(wifi,手機)。我們今天可能會使用與聲音不同的東西,但它仍然是數據到波形和背景。 – corsiKa 2011-02-13 20:18:05

回答

20

最簡單的調製方案是amplitude modulation(技術上對於數字領域,這將被稱爲幅移鍵控)。以固定的頻率(比如10Khz),你的「載波」,並使用你的二進制數據中的位來打開和關閉它。如果你的數據速率是每秒10比特,你將會以這個速率開啓和關閉10KHz信號。解調將是一個(可選的)10KHz濾波器,然後與一個閾值進行比較。這是一個相當簡單的實施方案。通常,信號頻率和可用帶寬越高,您可以越快切換該信號。

這裏一個非常酷的/有趣的應用程序將編碼/解碼爲莫爾斯電碼,並看看你能走多快。在兩個頻率之間切換的帶寬更高效,對噪聲免疫性更強,但會使解調器更加複雜,因爲您需要區分這兩個頻率。

先進的調製方案,如Phase Shift Keying擅長獲得給定帶寬和信噪比的最高比特率,但它們實現起來更加複雜。模擬電話調制解調器需要處理某些帶寬(例如低至3Khz)和噪聲限制。如果您需要在給定帶寬和噪聲限制的情況下獲得儘可能高的比特率,那麼就要走了。

對於高級調製方案的實際代碼示例,我將調查DSP供應商的應用筆記(如TIAnalog Devices),因爲這些是DSP的常見應用。

Implementing a PI/4 Shift D-QPSK Baseband Modem Using the TMS320C50

QPSK modulation demystified

V.34 Transmitter and Receiver Implementation on the TMS320C50 DSP

另一個非常簡單和不那麼有效的方法是使用DTMF。這些是由電話鍵盤產生的音調,其中每個符號是兩個頻率的組合。如果你是谷歌,你會發現很多源代碼。根據您的應用/要求,這可能是一個簡單的解決方案。

讓我們在一些簡單的方案實施細節俯衝,有點像莫爾斯電碼我前面提到的。我們可以使用「dot」作爲0,使用「dash」作爲1.類似莫爾斯的方案的一個優點是,它也解決了成幀問題,因爲您可以在每個空間之後重新同步採樣。爲了簡單起見,我們選擇「載波」頻率在11KHz,假設你的波形輸出是44Khz,16位,單聲道,我們也會使用一個方波來產生諧波,但我們並不在乎,如果11KHz超出了你的麥克風的頻率響應,那麼就把所有的頻率除以2例如,我們會挑選一些任意的水平10000等我們「的」波形看起來是這樣的:

{10000, 10000, 0, 0, 10000, 10000, 0, 0, 10000, 0, 0, ...} // 4 samples = 11Khz period 

和我們的「關」波形僅僅是全部爲零我離開這個部分的編碼作爲練習吧讀者。

因此,我們有這樣的事:

const int dot_samples = 400; // ~10ms - speed up later 
const int space_samples = 400; // ~10ms 
const int dash_samples = 800; // ~20ms 

void encode(uint8_t* source, int length, int16_t* target) // assumes enough room in target 
{ 
    for(int i=0; i<length; i++) 
    { 
    for(int j=0; j<8; j++) 
    { 
     if((source[i]>>j) & 1) // If data bit is 1 we'll encode a dot 
     { 
     generate_on(&target, dash_samples); // Generate ON wave for n samples and update target ptr 
     } 
     else // otherwise a dash 
     { 
     generate_on(&target, dot_samples); // Generate ON wave for n samples and update target ptr 
     } 
     generate_off(&target, space_samples); // Generate zeros 
    } 
    } 
} 

解碼器是一個比較複雜一點,但這裏是一個輪廓:

  1. 可選的帶通濾波器周圍11KHZ採樣信號。這會在嘈雜的環境中提高性能。 FIR濾波器非常簡單,並且有幾個在線設計小程序可以爲您生成濾波器。
  2. 閾值信號。每個高於1/2最大幅度的值爲1,每個低於0的值。這假定您已經對整個信號進行了採樣。如果這是實時的,您可以選擇一個固定的閾值,或者在一段時間內追蹤最大信號電平的地方進行某種自動增益控制。
  3. 掃描點或短劃線的開始。您可能希望在點週期內至少看到一定數量的1,以便將樣點視爲點。然後繼續掃描,看看這是否是破折號。不要期待一個完美的信號 - 你會在1的中間看到幾個0,在0的中間看到幾個0。如果噪音很小,那麼區分「開」期和「關」期應該相當容易。
  4. 然後顛倒上述過程。如果你看到破折號向你的緩衝區推一個1位,如果一個點推零。調製/解調的
2

一個目的是適應信道特性。例如,該頻道可能無法傳遞DC。另一個目的是克服信道中給定的數量和類型的噪聲,同時仍然傳輸高於某個給定錯誤率的數據。

對於FSK,只需要例程比可以在位於發送端的兩個不同的頻率,並且過濾生成的正弦波和在接收端檢測兩個不同的頻率。正弦波的每段長度,頻率間隔和幅度取決於您需要克服的數據速率和噪聲量。

在最簡單的情況下,零噪聲,簡單地產生連續的固定時間幀之內N或2N正弦波。喜歡的東西:

x[i] = amplitude * sin(i * 2 * pi * (data[j] ? 1.0 : 2.0) * freq)/sampleRate) 

在接收端,可以對信號進行採樣在遠高於兩倍的最大頻率並測量過零點之間的距離,並且查看是否找到短週期或長週期波形的一羣。使用數字信號處理濾波器(IIR,FIR等)和各種統計檢測器的更奇特的方法可用於存在非零噪聲的情況。