На этой страничке приеден сборник заметок и ресурсов, связанных с передачей и приемом сообщений WSPR (перевод статьи [1]).
WSPR это цифровой протокол для передачи по радио сообщений на малой мощности. WSPR использует технику манипуляции частотой (frequency-shift keying [2]) и опережающую коррекцию ошибок (forward error correction, FEC [3]), чтобы надежно передавать данные на сотни или тысячи миль сигналами мощностью ниже ватта. Кодирование и декодирование WSPR может осуществляться библиотеками с открытым исходным кодом WSJT-X [4], реализованном на языках C и FORTRAN.
На слух передача WSPR слышна как тон, меняющий частоту несколько раз в секунду, и продолжающийся в течение примерно 2 минут. Если более точно:
• Передача продолжается несущей в течение 110.6 сек. • Сдвиг частоты происходит 4 раза каждые 0.683 сек. • Частоты тона отличаются на 1.46 Гц. • Полоса частот передачи составляет около 6 Гц. • 50 бит полезной нагрузки упакованы в 162-битное сообщение в опережающей коррекцией ошибок (FEC). • Передачи всегда начинаются через 1 секунду после четных минут (UTC).
Пример спектрограммы сигнала WSPR, захваченной программой FSKview [5], частота оцифровки 48 кГц, размер окна FFT 216 (1.365 сек), шаг FFT 1/8 от окна FFT (1/4 длительности тона), разрешающая способность FFT 0.366 Гц (1/4 интервала между частотами):
[Описание протокола WSPR]
Standard Message Format. Стандартное сообщение состоит из позывного (callsign) + 4 цифры указателя места размещения (locator) + значение мощности передачи (dBm). Стандартное сообщение содержит 50 бит полезной нагрузки:
• 28 бит callsign • 15 бит locator • 7 бит power level
Пример:
K1ABC FN20 37
В этом примере представлен сигнал от K1ABC, grid FN20, передаваемый 103.7 мВт (~ 5 Вт).
Two-Message Format. Существует формат с составным сообщением, где используется позывной и/или 6-цифровой locator, с последовательностью из 2 сообщений. Первая передача содержит следующую посылку:
callsign + callsign + power или callsign + locator + power
Вторая передача:
Hashed callsign + locator + power
Добавление префиксов и суффиксов. Добавленные префиксы могут содержать до 3 буквенно-цифровых символов. Добавленные суффиксы могут содержать одну букву или одну или 2 цифры.
Forward Error Correction (FEC). Используется нерекурсивный сверточный код с длиной ограничения (constraint length) K = 32, скорость (rate) r = 1⁄2.
Символы. Используется 162 ((50 + K − 1) * 2) возможных символа. Каждый передает один sync-бит (LSB) и один data-бит (MSB).
Скорость и длительности. Скорость изменения частоты (reying rate) составляет 12000⁄8192 = 1.4648 baud. Длительность передачи составляет 162 * 8192⁄12000 = 110.6 сек.
Модуляция, полоса частот. Continuous phase 4 FSK, с разделением тонов 1.4648 Гц. Занимаемая полоса частот составляет около 6 Гц.
Синхронизация. Используется 162-битный псевдослучайный sync-вектор. Передача номинально стартует через 1 секунду после наступления каждой четной минуты UTC (например, в hh:00:01, hh:02:01, и т. д.).
Соотношение сигнал/шум. Минимальный SNR для успешного приема составляет около –34 по шкале WSJT (опорная полоса пропускания 2500 Гц).
[Процесс кодирования WSPR]
Замечание: эта секция была написана Andy Talbot (G4JNT) в 2009 году, и была переведена Markdown by Scott Harden (AJ4VD) в 2020. Оригинал доступен в PDF.
Для кодирования маяка WSPR на основе микроконтроллера PIC и генератора частот DDS был выбран самый простой путь. Whilst Joe K1JT написал утилиту командной строки WSP2INC.EXE (см. [7, 8]) для предоставления листинга символов, потребовалась дальнейшая обработка значений в полезную для использования форму. Автором была написана программа для преобразования этого списка в форму, подходящую для файла ассемблера PIC, однако процесс был неудобным и трудоемким. Отсутствовало понимание, как сгенерированы данные, что было некомфортным.
Поиск в web не дал какого-нибудь простого описания кодирования в протоколе, но был найден оригинальный исходный код полного программного обеспечения WSJT (на Fortran и C), который был слишком сложным, чтобы в нем разбираться. Также было найдено несколько компиляций других авторов на Python и C для генерации символов WSPR на основе этого оригинального материала.
В процессе исследования и модификации кода C была написана программа, которая генерировала файл .INC file для прямого импорта в код микроконтроллера PIC символов WSPR для любого исходного сообщения. Программа была реализована в двух вариантах - на C и PowerBASIC, и проверка показала, что они дают идентичные результаты, совпадающие с оригинальной WSPR.EXE. В результате появилось следующее описание, не привязанное к конкретному языку программирования, которое может помочь понять принцип кодирования WSPR.
Входные данные:
1. Позывной (callsign), состоящий максимум из 6 символов, которыми могут быть только A-Z, 0-9 и [space]. 2. 4-символьный указатель места расположения маяка (locator, такой как IO90). 3. Уровень передаваемой мощности в dBm, закодированный значениями от 0 до 60.
Все символы преобразуются в верхний регистр.
Callsign. Третий символ у позывного ДОЛЖЕН БЫТЬ цифрой. Чтобы справиться с позывными, которые начинаются с буквы, за которой идет цифра, при необходимости спереди добавляется пробел. Так, например, позывной G4JNT станет [space]G4JNT, в то время как GD4JNT останется как есть.
Короткие позывные пополняются в конце пробелами для достижений 6 символов.
Выделены 37 разрешенных символов, кодируемые значениями от 0 до 36 таким образом, что '0' - '9' соответствуют значениям 0 – 9, символы от 'A' до 'Z' значениями 10 - 35, и пробел ([space]) закодирован значением 36.
Дальнейшие правила кодирования позывных определяют, что последние 3 символа (в том числе дополняющие пробелы) могут быть только буквами или [space], так что они будут закодированы значениями только в диапазоне 10 – 36.
С символами, обозначаемыми как [Ch X], принимающие значения от 0 до 36, как определено выше, позывной теперь упаковывается в одно целое число N путем последовательного наращивания.
N1 = [Ch 1] Первый символ может быть любым из указанных 37 значений, включая [space]. N2 = N1 * 36 + [Ch 2] Любой символ кроме пробела. N3 = N2 * 10 + [Ch 3] Третий символ всегда должен быть цифрой, так что для него допускаются одно из 10 значений. N4 = 27 * N3 + [Ch 4] – 10] N5 = 27 * N4 + [Ch 5] – 10] Символы в конце не могут быть числами, так что для них допустимы только 27 вариантов значений. N6 = 27 * N5 + [Ch 6] – 10] Символы в конце не могут быть числами, так что для них допустимы только 27 вариантов значений.
На практике N может быть просто 32-разрядным целым числом, которое может быть построено поэтапно. Максимальное возможное значение для N:
37 * 36 * 10 * 27 * 27 * 27 = 262177560
Удобно, что оно меньше чем 228 = 268435456, это означает, что оно может быть представлено 28 битами с диапазоном кодов, зарезервированных для будущего использования, например для определения специальных случаев и флагов.
Locator. Обозначим 4 символа локатора как [Loc 1] .. [Loc 4]. Первые два из них могут принимать только 18 вариантов значений в диапазоне от A до R, так что здесь будут коды 0 – 17. Вторая пара может принимать только значения 0 – 9.
Другое целое число M1 формируется из следующего:
M1 = (179 - 10 * [Loc 1] - [Loc 3] ) * 180 + 10 * [Loc 2] + [Loc 4]
Это дает диапазон от AA00 (32220) до RR99 (179), что удобно укладывается в 15-разрядное представление (215 = 32768), оставляя запасные коды для дальнейшего расширения.
Power Level. Уровень мощности [Pwr] принимает значения в диапазоне 0 – 60. Хотя в программе WSJT / WSPR будут работать только некоторые значения (только те, которые заканчиваются на 0, 3 или 7), могут быть закодировано любое из 61 значений; недопустимые значения помечаются при декодировании.
Мощность кодируется в M следующим образом:
M = M1 * 128 + [Pwr] + 64
Это дает конечное значение для M с максимумом 4124287, что укладывается в 22 бита (222 = 4194304).
Упаковка бит. Все исходные данные теперь должны быть уложены в 50 бит данных: 28 для позывного в N, для локатора 15 бит, и 7 для мощности M. Несколько специальных случаев кодирования доступно для дальнейших улучшений наподобие текстовых сообщений, но здесь это не рассматривается.
Два целых числа N и M обрезаются и комбинируются в 50 бит с порядком следования callsign-locator-power. Эти биты помещаются в 11-байтный массив c[0] .. c[10], так что первый элемент c[0] содержит самые значащие 8 биты, c[1] следующие по значимости биты, и так далее.
Обратите внимание, что c[3] содержит как 4 LSB от callsign, так и 4 MSB от locator, и c[6] содержит только два LSB от M. Младшие шесть бит c[6] все установлены в 0, и остальные элементы массива c[7] .. c[10] устанавливаются в 0. Таким образом, используются только 81 из общего количества 88 бит.
[Сверточное кодирование / FEC]
Теперь данные расширяются для добавления упреждающей коррекции ошибок (Forward Error Correction, FEC) со скоростью (rate) ½, ограниченной длиной (constraint length) 32. Полезная нагрузка из 81 бит (включающая 31 завершающих нулей) вычитываются старшим битом (MSB) вперед, в следующем порядке:
c[0] MSB ... c[0] LSB, c[1] MSB ... c[1] LSB ... и т. д. ... c[11]
Биты одновременно сдвигаются вправо, или в наименее значимую позицию, в два 32 битных регистра сдвига [Reg 0] и [Reg 1]. Каждый регистр сдвига подает в генератор четности ExclusiveOR из отводов обратной связи, описанных соответственно 32-битными значениями 0xF2D05351 и 0xE4613C47.
Генерация четности начинается немедленно с появлением первого бита в регистрах (которые изначально должны быть очищены), и продолжается пока регистры не будут очищены последним вдвинутым 31-ым нулем.
Каждый из 81 вдвигаемых бит генерирует бит четности от каждого генератора, в результате получается 162 бита. Для каждого вдвинутого бита берутся по очереди два бита четности в порядке, заданном значения двух положений отводов обратной связи, чтобы дать поток из 162 выходных битов.
Общее описание процесса генерации четности. Расширение из 50 исходных бит до 162 добавляет достаточную надежность передачи, чем достигается хороший компромисс между количеством полученных данных и мощной FEC для исправления случайных ошибок.
• Вдвигается следующий исходный бит LSB регистров [Reg 0] и [Reg 1] (существующие биты сдвигаются влево). • Берется содержимое [Reg 0]. • AND со значением 0xF2D05351. • Вычисляется один бит четности (XOR) от результирующей суммы. • Результат добавляется в выходной поток данных. • Берется содержимое [Reg 1]. • AND со значением 0xE4613C47. • Вычисляется один бит четности (XOR) от результирующей суммы. • Результат добавляется в выходной поток данных.
Чередование бит (interleaving). Ошибки на радиоканале редко бывают случайными, поскольку они чаще встречаются в пакетах, против которых такое сверточное кодирование менее эффективно. Заключительный этап кодирования состоит в том, чтобы смешать или применить чередование для 162 бит данных так, чтобы сместить во времени друг от друга соседние биты. В результате близко расположенные друг к другу биты, поврежденные помехами, оказываются распространенными по всему кадру, и таким образом появляются как случайные ошибки, с которыми может справиться обработка FEC.
Процесс интерливинга выполняется таким образом, что берется блок 162 бит, помеченных как S[0] .. S[161], и используется реверсирование адреса бит для их переупорядочивания, чтобы получить результирующий поток бит D[0] .. D[161]. Алгоритм следующий:
• Счетчик P инициализируется нулем.
• Берется каждый 8-битный адрес от 0 до 255, обозначаемый здесь как "I Bit-reverse I", чтобы получить значение J. Например: I = 1 дает J = 128, I = 13 дает J = 176, и т. д.
- Если bit-reversed J дает значение меньше 162, то устанавливается Destination bit D[J] = source bit S[P]. - Инкрементируется P.
• Процесс повторяется, пока P не станет равным 162.
Эта операция полностью перераспределяет 162 бита по кадру.
Слияние с вектором синхронизации. 162 бита данных теперь комбинируются с 162 битами псевдо-случайного слова синхронизации с хорошими свойствами автокорреляции. Каждый исходный бит комбинируется с битом синхронизации, который берется из следующей таблицы, чтобы получить значение символа с 4 состояниями:
Symbol[n] = Sync[n] + 2 * Data[n]
162 bit Synchronization Vector
1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0
0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0
1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1
1,1,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0.0,0
В результате получается 162 последовательных символа со значением от 0 до 3.
Модуляция. Каждый символ представлен сдвигом частоты 12000/8192, или приблизительноo 1.46 Гц, в соответствии со значением символа, что дает 4-уровневую модуляцию Multi-FSK. Длина передаваемого символа является обратной величиной интервала тона, или приблизительно 0.683 секунды, так что полное сообщение из 162 символов занимает около 110.6 секунд, и занимает полосу частот приблизительно 6 Гц.
Упаковка для экспорта и хранение. Для экспорта 162 двухразрядных символа упаковываются по четыре в байты, MSB вперед, занимая 41 байт.
[Ссылки]
1. WSPR site:swharden.com. 2. Frequency-shift keying site:wikipedia.org. 3. Error correction code site:wikipedia.org. 4. WSJT-X site:github.com. 5. FSKview site:swharden.com. 6. Easy WSPR Encoder. 7. The Bell Hill Microwave Beacons site:g4jnt.com. 8. WSPRBCNS.ZIP. 9. swharden / WsprSharp - библиотека .NET для кодирования и декодирования передач WSPR на языке C#. 10. Grid square lookup - карта кодирование ячеек location. 11. WSJT - Weak signal ham radio communication. |