Подтвердить что ты не робот

Данные для аудио и обратно. Модуляция/демодуляция с исходным кодом

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

V.34 Внедрение передатчика и приемника на DSP TMS320C50

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

Давайте погрузиться в некоторые детали реализации простой схемы, что-то вроде кода Морзе, о котором я упоминал ранее. Мы можем использовать "точку" для "0" и "тире" для 1. Преимущество такой же схемы, как и морская схема, заключается в том, что она также решает проблему кадрирования, поскольку вы можете повторно синхронизировать свою выборку после каждого пространства. Для простоты позвольте выбрать частоту "несущей волны" на частоте 11 кГц, и предположим, что ваш волновой выход равен 44 кГц, 16 бит, моно. Мы также будем использовать прямоугольную волну, которая создаст гармоники, но нам все равно. Если 11 кГц превышает частоту вашего микрофона, тогда просто разделите все частоты на 2 например, мы выберем некоторый произвольный уровень 10000, и поэтому наша форма волны "on" будет выглядеть так:

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

а наш "выключенный" сигнал - это всего лишь нули. Я оставляю кодировку этой части как excersize для читателя.

И у нас есть что-то вроде:

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
    } 
  }
}

Декодер немного сложнее, но здесь схема:

  • Опционально полосовой фильтр сэмплированный сигнал около 11 кГц. Это улучшит работу в шумном окружении. Фильтры FIR довольно просты, и есть несколько сетевых апплетов, которые будут создавать фильтр для вас.
  • Порог сигнала. Каждое значение выше 1/2 максимальной амплитуды составляет 1, каждое значение ниже 0. Это предполагает, что вы пробовали весь сигнал. Если это в реальном времени, вы либо выбираете фиксированный порог, либо выполняете какое-то автоматическое регулирование усиления, когда вы отслеживаете максимальный уровень сигнала в течение некоторого времени.
  • Сканировать начало точки или тире. Вероятно, вы захотите увидеть хотя бы определенное число в один из десяти пунктов, чтобы считать образцы точками. Затем продолжайте сканирование, чтобы убедиться, что это тире. Не ожидайте идеального сигнала - вы увидите несколько 0 в середине вашего 1 и несколько 1 в середине ваших 0. Если есть небольшой шум, то дифференцирование периодов "on" из периодов "off" должно быть довольно простым.
  • Затем переверните описанный выше процесс. Если вы видите, что тире нажмите 1 бит в буфер, если точка толкает ноль.

Ответ 2

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

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

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

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

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