Цифровая обработка сигналов в Scilab: как декодировать сигнал частотной манипуляции

Добавлено 28 ноября 2018 в 09:47

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

Цифровая обработка сигналов в Scilab: как декодировать сигнал частотной манипуляции
Цифровая обработка сигналов в Scilab: как декодировать сигнал частотной манипуляции

Вспомогательная информация

Предыдущие статьи о цифровой обработке сигналов в Scilab

Один из методов, используемых для кодирования двоичных данных в синусоидальном сигнале, называется частотной манипуляцией (FSK, frequency shift keying). Это простая концепция: одна частота представляет собой ноль, а другая частота представляет собой единицу. Например:

Сигнал с частотной манипуляцией
Сигнал с частотной манипуляцией

Низкочастотный частотно-манипулированный (FSK) сигнал (скажем, в десятки килогерц) может быть сдвинут на более высокую частоту и затем передан. Это эффективный и довольно простой способ создания радиочастотной системы, которая обеспечивает беспроводную передачу цифровых данных, предполагая, что у нас есть приемник, который может преобразовать все эти синусоидальные сигналы обратно в единицы и нули.

Процесс извлечения цифровых данных из передаваемого FSK сигнала можно разделить на две основные задачи. Во-первых, принятый высокочастотный сигнал преобразуется в низкочастотный сигнал основной полосы частот. Я рассматриваю это как «демодуляцию». Во-вторых, сигнал основной полосы должен быть преобразован в единицы и нули. Я не думаю, что было бы неправильно назвать этот второй шаг «демодуляцией», но чтобы избежать путаницы, я всегда буду использовать термин «декодирование», когда буду говорить о преобразовании низкочастотных аналоговых сигналов в цифровые биты.

Программное декодирование

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

В данной статье мы будем использовать Scilab для декодирования сигнала частотной манипуляции, но соответствующие вычисления не являются сложными и могут быть легко реализованы как C-код в цифровом сигнальном процессоре.

Сперва математика

Наша методика декодирования частотной манипуляции основана на умножении синусоидальных сигналов. Рассмотрим следующие тригонометрические тождества:

\[\sin(x) \cdot \sin(y)=\frac{1}{2}(\cos(x-y)-\cos(x+y))\]

\[\cos(x) \cdot \cos(y)=\frac{1}{2}(\cos(x-y)+\cos(x+y))\]

Давайте сделаем это более согласованным с инженерным миром, используя ω1t и ω2t вместо x и y.

\[\sin(\omega_1t) \cdot \sin(\omega_2t)=\frac{1}{2}(\cos((\omega_1-\omega_2)t)-\cos((\omega_1+\omega_2)t))\]

\[\cos(\omega_1t) \cdot \cos(\omega_2t)=\frac{1}{2}(\cos((\omega_1-\omega_2)t)+\cos((\omega_1+\omega_2)t))\]

(Обратите внимание, что мы игнорируем влияние разностей фаз, в этой статье мы предполагаем, что все сигналы имеют одинаковую фазу.) Мы можем умножать два синусоидальных сигнала или два косинусоидальных сигнала, и результат будет состоять из двух косинусоидальных сигналов с частотами равными, сумме и разности двух исходных частот. Критическое наблюдение здесь состоит в том, что сигнал cos((ω1–ω2)t) будет иметь очень низкую частоту, если два входных сигнала имеют очень схожие частоты. В идеализированной математической реальности мы могли бы ввести два сигнала с одинаковыми частотами, cos((ω1–ω2)t) стал бы cos(0t) = cos(0) = 1. Таким образом, если мы умножим два синусоидальных сигнала или два косинусоидальных сигнала, равных по частоте, результирующий сигнал будет иметь относительно большое смещение по постоянному напряжению.

В контексте декодирования частотной манипуляции (FSK) можно сказать следующее. Даже если частоты схожи, а не идентичны, по-прежнему будет большое смещение по постоянному напряжению, потому что сигнал cos((ω1–ω2)t) будет начинаться с 1 и за продолжительность одного бита будет уменьшаться относительно очень медленно. Продолжительность бита – это время, необходимое для кодирования одного цифрового бита; на диаграмме выше, длительность бита соответствует одному периоду частоты логического нуля (или трем периодам частоты логической единицы). Фрагмент аналогового сигнала, который содержится в одной продолжительности бита, называется символом. В данной статье мы используем двоичную (то есть двухчастотную) частотную манипуляцию (FSK), и, следовательно, один символ соответствует одному цифровому биту. Можно использовать более двух частот, в этом случае один символ будет передавать несколько бит.

Декодирование частотной манипуляции (FSK), шаг за шагом

Теперь у нас есть информация, необходимая для формулировки процедуры декодирования частотной манипуляции:

  1. Оцифровать полученный сигнал основной полосы частот.
  2. Определить начало продолжительности бита. Это может быть выполнено с помощью тренировочной/синхронизирующей последовательности; для получения дополнительной информации смотрите подраздел «Преамбула» раздела «Анатомия пакета» в этой статье. Для данной статьи мы будем предполагать, что данные были закодированы как синусоидальные волны (как показано на диаграмме выше), а не как косинусоидальные волны.
  3. Умножить каждый символ на синусоидальную волну с частотой логического 0 и на синусоидальную волну с частотой логической 1.
  4. Вычислить смещение по постоянному напряжению каждого символа.
  5. Выбрать пороговое значение и сделать выбор между логическими 0 и 1 на основании того, является ли смещение символа по постоянному напряжению выше или ниже порогового значения.

Реализация Scilab

Мы начнем с создания односимвольных синусоидальных сигналов на частоте логического 0 (10 кГц) и частоте логической 1 (30 кГц).

ZeroFrequency = 10e3;
OneFrequency = 30e3;
SamplingFrequency = 300e3;
Samples_per_Symbol = SamplingFrequency/ZeroFrequency;
n = 0:(Samples_per_Symbol-1);
Symbol_Zero = sin(2*%pi*n / (SamplingFrequency/ZeroFrequency));
Symbol_One = sin(2*%pi*n / (SamplingFrequency/OneFrequency));
plot(n, Symbol_Zero)
plot(n, Symbol_One)
Сигналы с частотами логических 0 и 1 длительностью 1 символ
Сигналы с частотами логических 0 и 1 длительностью 1 символ

Теперь давайте создадим принятый сигнал основной полосы частот. Мы можем сделать это, объединив массивы Symbol_Zero и Symbol_One; мы будем использовать последовательность 0101:

ReceivedSignal = [Symbol_Zero Symbol_One Symbol_Zero Symbol_One];
plot(ReceivedSignal)
«Принятый» сигнал основной полосы частот
«Принятый» сигнал основной полосы частот

Затем мы умножаем каждый символ в принятом сигнале на символ логического 0 и на символ логической 1. Мы выполняем этот шаг, увеличивая массивы Symbol_Zero и Symbol_One в соответствии с количеством символов в принятом сигнале, а затем используя поэлементное умножение (для дополнительной информации о поэлементном умножении в Scilab смотрите эту статью).

Decoding_Zero = ReceivedSignal .* [Symbol_Zero Symbol_Zero Symbol_Zero Symbol_Zero];
Decoding_One = ReceivedSignal .* [Symbol_One Symbol_One Symbol_One Symbol_One];
plot(Decoding_Zero)
Результаты умножения принятого сигнала на символы логического нуля
Результаты умножения принятого сигнала на символы логического нуля
plot(Decoding_One)
Результаты умножения принятого сигнала на символы логической единицы
Результаты умножения принятого сигнала на символы логической единицы

Не отвлекайтесь на эти сигналы довольно сложной формы; всё, что нас интересует, это смещение по постоянному напряжению, которое в математических терминах является просто средним значением. Если мы хотим отобразить смещение по постоянному напряжению, соответствующее каждому символу, сначала нужно создать несколько новых массивов:

for k=1:(length(Decoding_Zero)/Samples_per_Symbol)
  > SymbolOffsets_Zero(((k-1)*Samples_per_Symbol)+1:k*(Samples_per_Symbol)) = mean(Decoding_Zero(((k-1)*Samples_per_Symbol)+1:k*(Samples_per_Symbol)));
  > end


for k=1:(length(Decoding_One)/Samples_per_Symbol)
  > SymbolOffsets_One(((k-1)*Samples_per_Symbol)+1:k*(Samples_per_Symbol)) = mean(Decoding_One(((k-1)*Samples_per_Symbol)+1:k*(Samples_per_Symbol)));
  > end

Возможно, вам придется немного поразмыслить над этими командами, чтобы точно понять, что я делаю, но вот основная идея. Цикл for используется для прогона по одному символу за один раз через массивы Decoding_Zero и Decoding_One. В массивах SymbolOffsets_Zero и SymbolOffsets_One все точки данных, соответствующие одному символу, заполняются средним значением соответствующего символа в массивах Decoding_Zero и Decoding_One. У нас есть 30 выборок на символ, поэтому первая команда работает со значениями массива от 1 до 30, следующая работает со значениями массива от 31 до 60, и так далее. Вот результаты:

plot(SymbolOffsets_Zero)
Постоянная составляющая в результате умножения принятого сигнала на символы двоичного нуля
Постоянная составляющая в результате умножения принятого сигнала на символы двоичного нуля
plot(SymbolOffsets_One)
Постоянная составляющая в результате умножения принятого сигнала на символы двоичной единицы
Постоянная составляющая в результате умножения принятого сигнала на символы двоичной единицы

Массив SymbolOffsets_Zero показывает нам смещение по постоянному напряжению, возникающее в результате умножения принятого символа в основной полосе на частоту двоичного нуля, а массив SymbolOffsets_One показывает нам смещение по постоянному напряжению, возникающее в результате умножения принятого символа в основной полосе на частоту двоичной единицы. Мы знаем, что умножение двух одинаковых частот приведет к относительно большому смещению по постоянному напряжению. Таким образом, значение 0,5 в массиве SymbolOffsets_Zero указывает, что принятый символ был двоичным 0, а значение 0,5 в массиве SymbolOffsets_One указывает, что принятый символ был двоичной 1.

Заключение

В данной статье представлен математический подход для декодирования частотной манипуляции (FSK). Процедура была реализована в Scilab, но команды Scilab нетрудно перевести на язык программирования высокого уровня, такой как C. В следующей статье мы продолжим работу с декодированием FSK.


На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.


Сообщить об ошибке