【问题标题】:Data to audio and back. Modulation / demodulation with source code数据到音频并返回。带源代码的调制/解调
【发布时间】:2011-06-25 23:04:54
【问题描述】:

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

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

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

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

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

能否请您指出任何语言的 FSK 实现?
或者提供任何替代编码二进制带有可用源代码的声音?

【问题讨论】:

  • 我在下面给出了一个通用的答案,但如果您详细说明您的要求,我可以更具体。您在寻找什么比特率?音频信号如何播放(电脑扬声器?)和采样(麦克风?)。有关您期望的音频带宽和噪音的任何详细信息...
  • 非常感谢。任何比特率都可以开始。声音使用计算机扬声器播放并使用麦克风进行采样。带宽不会很宽(低质量麦克风)。有一些背景噪音,但不大。
  • 这并不像听起来那么老套(wifi、手机)。这些天我们可能会使用与声音不同的东西,但它仍然是数据到波并返回。

标签: algorithm encoding audio signal-processing


【解决方案1】:

最简单的调制方案是amplitude modulation(从技术上讲,对于数字领域,这称为幅移键控)。采用固定频率(比如说 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。这些是电话键盘产生的音调,其中每个符号是两个频率的组合。如果你谷歌你会发现很多源代码。根据您的应用程序/要求,这可能是一个简单的解决方案。

让我们深入了解一些简单的方案实现细节,比如我之前提到的摩尔斯电码。我们可以用“点”表示 0,用“破折号”表示 1。类似 morse 的方案的一个优点是它还解决了框架问题,因为您可以在每个空间之后重新同步采样。为简单起见,让我们选择“载波”频率在 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 的中间看到几个 1。如果噪音很小,那么区分“开启”时段和“关闭”时段应该相当容易。
  4. 然后反转上述过程。如果您看到破折号将 1 位推入缓冲区,如果点则推入 0。

【讨论】:

  • 非常感谢!看来解码不是那么容易,我也没有找到任何代码来做。最后我们使用了完全不同的有损方式,只适合传输图片:mobreactor.com/soundwise
  • 在解码(解调)方面,有一种用于 FSK 解调的良好且快速的算法,称为 Goertzel 算法。这个PDF 提供了一个很好的总结。
  • 多年后,这里有一个移动应用程序的视频。同样,它使用有损方法(光谱仪),与上述方法不同。它只能传输图片。这是因为我是 DSP 新手,这是作为黑客马拉松的一部分进行的,并且只有一天时间来实现一些相对简单的东西:youtube.com/watch?v=ElkmzoqD9PM
【解决方案2】:

调制/解调的一个目的是适应信道特性。例如,通道可能无法通过 DC。另一个目的是克服信道中给定数量和类型的噪声,同时仍以高于给定错误率的方式传输数据。

对于 FSK,您只需要能够在发送端生成两个不同频率的正弦波并在接收端过滤和检测两个不同频率的例程。每段正弦波的长度、频率间隔和幅度将取决于您需要克服的数据速率和噪声量。

在最简单的情况下,零噪声,只需在连续的固定时间范围内产生 N 或 2N 个正弦波。比如:

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

在接收端,您可以以远高于最大频率两倍的频率对信号进行采样,并测量过零之间的距离,看看您是否发现了一堆短周期或长周期波形。在存在非零噪声的情况下,可以使用许多使用数字信号处理滤波器(IIR、FIR 等)和各种统计检测器的更高级的方法。

【讨论】:

  • 我认为最好不要让一个频率加倍另一个频率,因为较高频率是较低频率的谐波。我认为您通常希望频率尽可能接近,但不要太接近以至于无法区分它们。 300bps 调制解调器使用 1180Hz 和 980Hz,以及在另一个方向使用 1850Hz 和 1650Hz。
  • @Guy:是的。但是在频率分离和数据速率之间需要权衡取舍,这取决于带宽、S/N 和错误率要求等其他因素。
猜你喜欢
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-22
  • 2013-05-05
相关资源
最近更新 更多