Данные на аудио и обратно. Модуляция / демодуляция с исходным кодом - PullRequest
22 голосов
/ 12 февраля 2011

У меня есть поток двоичных данных, и я хочу преобразовать его в необработанные звуковые данные формы волны, которые я могу отправить динамикам.

Это то, что модемы старой школы сделали для передачи двоичных данных.по телефонной линии (производит типичный модемный звук).Это называется модуляцией.

Тогда мне нужен обратный процесс - из необработанных выборок формы сигнала я хочу получить точные двоичные данные.Это называется демодуляцией.

  • Любой битрейт будет работать для начала.
  • Звук воспроизводится с использованием компьютерных колонок и дискретизируется с помощью микрофона.
  • Пропускная способность будетдовольно низкий (микрофон низкого качества).
  • Есть некоторый фоновый шум, но незначительный.

Я нашел один конкретный способ сделать это - Частотная манипуляция ,Проблема в том, что я не могу найти исходный код.

Можете ли вы указать мне на реализацию FSK на любом языке?
Или предложить альтернативную кодировку двоичного <-> звука с доступным исходным кодом?

Ответы [ 2 ]

20 голосов
/ 12 февраля 2011

Простейшей схемой модуляции будет амплитудная модуляция (технически для цифровой области это будет называться Amplitude Shift Keying). Возьмите фиксированную частоту (скажем, 10 кГц), вашу "несущую", и используйте биты в ваших двоичных данных, чтобы включить и выключить ее. Если ваша скорость передачи данных составляет 10 бит в секунду, вы будете включать и выключать сигнал 10 кГц с этой скоростью. Демодуляция будет (необязательным) фильтром 10 кГц с последующим сравнением с пороговым значением. Это довольно простая схема для реализации. Как правило, чем выше частота сигнала и доступная полоса пропускания, тем быстрее вы можете включать и выключать этот сигнал.

Очень классное / забавное приложение здесь - кодировать / декодировать как азбуку Морзе и видеть, как быстро вы можете идти.

FSK, переключение между двумя частотами более эффективно в полосе пропускания и более устойчиво к шуму, но сделает демодулятор более сложным, поскольку вам нужно различать две частоты.

Усовершенствованная схема модуляции, такая как Фазовая манипуляция хороша для получения максимальной скорости передачи данных для данной полосы пропускания и отношения сигнал / шум, но их сложнее реализовать. Аналоговые телефонные модемы должны были работать с определенной полосой пропускания (например, всего 3 кГц) и шумовыми ограничениями. Если вам нужно получить максимально возможную скорость передачи данных с учетом полосы пропускания и ограничений по шуму, то это путь.

Для фактических примеров кода усовершенствованных схем модуляции я бы изучил замечания по применению от поставщиков DSP (таких как TI и Analog Devices ), поскольку они были общими приложениями для DSP.

Внедрение модема D-QPSK PI / 4 Shift с использованием TMS320C50

QPSK модуляция демистифицирована

Внедрение передатчика и приемника VSP на TMS320C50 DSP

Еще один очень простой и не очень эффективный метод - использовать DTMF. Это тоны, генерируемые телефонными клавиатурами, где каждый символ представляет собой комбинацию двух частот. Если вы Google, вы найдете много исходного кода. В зависимости от вашего приложения / требований это может быть простое решение.

Давайте углубимся в некоторые простые детали реализации схемы, что-то вроде кода Морзе, который я упоминал ранее. Мы можем использовать «точку» для 0 и «тире» для 1. Преимущество схемы типа Морзе состоит в том, что она также решает проблему кадрирования, поскольку вы можете ресинхронизировать свою выборку после каждого пробела. Для простоты давайте выберем частоту «Несущая волна». на 11 кГц и предположим, что ваш выходной сигнал составляет 44 кГц, 16 бит, моно. Мы также будем использовать прямоугольную волну, которая будет создавать гармоники, но нам все равно. Если 11 кГц выше частотной характеристики вашего микрофона, то просто разделите все частоты на 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. Опционально полосовой фильтр дискретизированного сигнала около 11 кГц. Это улучшит производительность в шумной обстановке. КИХ-фильтры довольно просты, и есть несколько онлайн-апплетов, которые сгенерируют этот фильтр для вас.
  2. Порог сигнала. Каждое значение выше 1/2 максимальной амплитуды равно 1, каждое значение ниже равно 0. Это предполагает, что вы сэмплировали весь сигнал. Если это в режиме реального времени, вы либо выбираете фиксированный порог, либо выполняете какую-то автоматическую регулировку усиления, где вы отслеживаете максимальный уровень сигнала в течение некоторого времени.
  3. Сканирование для начала точки или тире.Вы, вероятно, хотите увидеть хотя бы определенное число единиц в периоде точек, чтобы считать выборки точкой.Затем продолжайте сканирование, чтобы увидеть, если это тире.Не ожидайте идеального сигнала - вы увидите несколько 0 в середине ваших 1 и несколько 1 в середине ваших 0.Если шумов мало, то отличить периоды «включения» от периодов «отключения» должно быть довольно просто.Если вы видите тире, нажмите 1 бит в буфере, если точка нажмите ноль.
2 голосов
/ 12 февраля 2011

Одной из целей модуляции / демодуляции является адаптация к характеристикам канала. Например, канал может быть не в состоянии пройти DC. Другая цель состоит в том, чтобы преодолеть определенное количество и тип шума в канале, в то же время передавая данные выше некоторой заданной частоты ошибок.

Для FSK вам просто нужны процедуры, которые могут генерировать синусоидальные волны на двух разных частотах на передающем конце, а также фильтровать и обнаруживать две разные частоты на приемном конце. Длина каждого сегмента синусоидальных волн, разделение по частоте и амплитуда будут зависеть от скорости передачи данных и количества шума, которое вам необходимо преодолеть.

В простейшем случае нулевого шума просто создайте N или 2N синусоидальных волн в последовательных фиксированных временных рамках. Что-то вроде:

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

На приемном конце вы можете сэмплировать сигнал с частотой, значительно превышающей максимальную частоту в два раза, и измерить расстояние между переходами через ноль, и посмотреть, найдете ли вы короткопериодные или длиннопериодные сигналы. При наличии ненулевого шума можно использовать гораздо более изощренные методы с использованием фильтров цифровой обработки сигналов (БИХ, КИХ и т. Д.) И различных статистических детекторов.

...