我有一个二进制数据流,想要将其转换为原始波形声音数据,然后可以发送给扬声器。

这就是老式调制解调器为了通过电话线传输二进制数据(产生典型的现代声音)所做的事情。这称为调制。

然后,我需要一个逆过程-从原始波形样本中,我想获得确切的二进制数据。这称为解调。

  • 任何比特率都可以开始使用。
  • 声音使用计算机扬声器播放,并使用麦克风采样。
  • 带宽会非常低(低质量的麦克风)。
  • 有一些背景噪音,但数量不多。

  • 我找到了一种执行此操作的特殊方法-Frequency shift keying。问题是我找不到任何源代码。

    您能指出我用任何一种语言实现的FSK吗?
    还是提供带有可用源代码的任何其他编码二进制声音?

    最佳答案

    最简单的调制方案是amplitude modulation(在数字 Realm 中,技术上称为幅度偏移键控)。采取固定的频率(假设为10Khz),即“载波”,然后使用二进制数据中的位将其打开和关闭。如果数据速率为每秒10位,则将以该速率打开和关闭10KHz信号。解调将是一个(可选)10KHz滤波器,然后与阈值进行比较。这是一个相当简单的实现方案。通常,信号频率和可用带宽越高,则打开和关闭信号的速度就越快。

    这里一个非常酷/有趣的应用程序是将代码编码/解码为莫尔斯电码,并查看您可以走多快。

    FSK,在两个频率之间切换在带宽上更有效,并且更不受噪声影响,但是由于需要区分两个频率,解调器将变得更加复杂。

    诸如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。这些是电话键盘产生的音调,其中每个符号是两个频率的组合。如果您使用Google,则会发现很多源代码。根据您的应用程序/要求,这可能是一个简单的解决方案。

    让我们深入了解一些简单的方案实现细节,例如我之前提到的莫尔斯电码。我们可以将“dot”用于0,将“dash”用于1。摩尔斯式方案的一个优点是它还解决了成帧问题,因为您可以在每个空间之后重新同步采样。为简单起见,我们选择“载波”频率假设您的电波输出为44Khz(16位单声道),频率为11KHz,我们还将使用方波来产生谐波,但我们不在乎。如果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
        }
      }
    }
    

    解码器稍微复杂一点,但这是一个概述:
  • (可选)对11Khz附近的采样信号进行带通滤波。这将在嘈杂的环境中提高性能。 FIR过滤器非常简单,并且有一些在线设计小程序可以为您生成过滤器。
  • 信号阈值。大于1/2最大幅度的每个值都是1,小于1/2最大幅度的每个值都是0。这假设您已经采样了整个信号。如果这是实时的,则可以选择固定的阈值或执行某种自动增益控制,以在一段时间内跟踪最大信号电平。
  • 扫描点或破折号的开始。您可能希望在点周期内看到至少一定数量的1,以将样本视为点。然后继续扫描以查看是否是破折号。不要指望一个完美的信号-您会在1的中间看到几个0,在0的中间看到几个1。如果噪声很小,则将“接通”周期与“断开”周期区分开应该很容易。
  • 然后逆转上述过程。如果看到破折号,则将1推至缓冲区,如果将破折号,则推至零。
  • 关于algorithm - 数据转为音频并返回。带有源代码的调制/解调,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4976213/

    10-09 16:58