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

Простая на бумаге азбука и коварство её распознавания на слух

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

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

Скорость передачи выражают чаще всего в словах в минуту, WPM. За эталонное слово принимают условную группу PARIS, чья общая длительность ровно пятьдесят единиц с учётом всех внутренних пауз и межсловного промежутка. Отсюда выводится связь скорости и длительности элемента: длительность точки в миллисекундах равна 1200, делённым на скорость в словах в минуту. На двадцати словах в минуту точка длится шестьдесят миллисекунд, на сорока всего тридцать, и декодер должен подстраиваться под этот разброс.

Существует и второй способ задания темпа, в знаках в минуту, CPM, который иногда расходится с оценкой в словах из-за разной средней длины реальных слов против эталонного PARIS. Отдельная тонкость связана с так называемым кодом Фарнсворта, при котором сами элементы передаются быстро, на высокой скорости, а паузы между символами и словами растягивают. Такой приём применяют в обучении, чтобы ученик с самого начала слышал ритмический образ символа на боевой скорости, но успевал его осмыслить в удлинённой паузе. Для декодера код Фарнсворта это проверка на прочность, ведь скорость элементов и скорость пауз тут различаются, и наивный алгоритм, выводящий единый темп, спотыкается. Поэтому продвинутые распознаватели оценивают длительность точки и длительность межсимвольной паузы как два независимых параметра, что и позволяет им корректно читать обучающие передачи.

Как сигнал превращается в поток нулей и единиц

Первый шаг любого декодера это выделение огибающей. Аудиопоток приходит с микрофона или линейного входа в виде тонального сигнала, обычно в полосе от двухсот до девятисот герц, и задача состоит в том, чтобы отделить моменты, когда тон звучит, от моментов тишины. Узкополосный фильтр настраивается на частоту тона, отсекая всё лишнее, после чего детектор огибающей превращает колебания в плавную кривую уровня. Сравнение этой кривой с порогом даёт бинарный поток: тон есть единица, тона нет ноль.

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

Для выделения тона на фоне шума вместо тяжёлого полного спектрального анализа часто берут алгоритм Гёрцеля, экономичный способ вычислить энергию сигнала на одной заранее известной частоте. Он работает как узкий цифровой фильтр, настроенный на тон, и требует на порядок меньше вычислений, чем полное преобразование Фурье, что позволяет крутить распознавание в реальном времени даже на скромном микроконтроллере. Ширину этого фильтра выбирают компромиссно: слишком узкий теряет сигнал при уходе частоты тона или при дрейфе гетеродина, слишком широкий впускает соседние помехи. Типичное окно в полсотни-сотню герц вокруг тона ловит баланс между избирательностью и устойчивостью к расстройке.

Алгоритм, который делит мир на короткое и длинное

Получив поток включений и пауз с измеренными длительностями, декодер сталкивается с центральной задачей: понять, где точка, а где тире, и где граница символа. Поскольку оператор-человек, а часто и автоматический ключ, не выдерживает идеальный тайминг, длительности расплываются, и жёсткие пороги вроде "всё короче ста миллисекунд это точка" работают плохо при смене скорости.

Классический подход опирается на кластеризацию длительностей. Декодер собирает статистику пришедших сигналов и обнаруживает, что они группируются вокруг двух значений: коротких около одной единицы и длинных около трёх единиц. Граница между кластерами ставится динамически, обычно в районе двукратной длительности точки, и всё, что короче, считается точкой, что длиннее тире. Аналогично паузы делятся на три класса по соотношению один-три-семь. Поскольку текущая скорость восстанавливается из самих данных, такой алгоритм сам подстраивается под темп передачи, и именно это лежит в основе функции автоматического определения скорости WPM, которой хвалятся современные декодеры. Распознав ритм, программа сверяет накопленную последовательность точек и тире с таблицей кода и выдаёт символ, поддерживая стандарт ITU, кириллицу и расширенные наборы.

Двоичное дерево как способ мгновенного поиска символа

Сверять накопленную последовательность точек и тире с таблицей перебором было бы медленно, и потому декодеры хранят код в виде двоичного дерева поиска. Корень дерева пуст, и каждый принятый элемент задаёт направление спуска: точка ведёт по одной ветви, тире по другой. Приняв, скажем, точку, тире и точку, декодер за три шага спускается в узел, где лежит буква, и выдаёт её, не перебирая весь алфавит. Глубина дерева равна максимальной длине кода символа, а это всего несколько уровней, отчего поиск занимает считанные сравнения независимо от размера набора.

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

Борьба с замираниями, дрожанием и ложными срабатываниями

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

Замирания порождают другую напасть, дробление элемента, когда длинное тире на миг проваливается ниже порога и распадается на два коротких куска, имитируя точки. С этим борются фильтрацией коротких провалов: паузу короче некоторой доли длительности точки декодер игнорирует, склеивая разорванный элемент обратно. Зеркальная проблема, слипание двух соседних элементов из-за затянутого спада сигнала, лечится противоположным приёмом, разделением подозрительно длинных включений. Импульсные помехи, щелчки и трески, отсекают по минимальной осмысленной длительности, считая всё короче порога шумом, а не сигналом. Совокупность этих ухищрений и определяет, развалится декодер на первой же помехе или дотянет сообщение до конца, и именно здесь нейросетевые распознаватели обходят пороговые, потому что обучаются на искажённых примерах и обобщают их статистику, а не следуют жёстким, заранее прошитым правилам.

Когда на смену порогам приходит обученная нейросеть

Пороговые и кластерные алгоритмы прекрасно справляются с чистым сигналом, но пасуют там, где эфир грязный, тайминг кривой, а рука оператора дрожит. Здесь в дело вступает машинное обучение. Современные приложения переводят распознавание на нейронные сети, обученные на больших массивах реальных сигналов с их естественными искажениями. Такая сеть не считает миллисекунды по жёстким правилам, а узнаёт ритмический образ, как это делает опытный телеграфист.

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

Из чего собирают декодер и куда его подключают

Аппаратная реализация декодера давно перешла на микроконтроллеры. Радиолюбители разработали множество автономных устройств, где входной тон оцифровывается аналого-цифровым преобразователем, фильтруется и анализируется прямо в чипе, а результат выводится на небольшой дисплей. Свободно распространяемые программы для персонального компьютера, такие как CwType, делают то же самое программно, принимая звук со звуковой карты. Профессиональные онлайн-декодеры идут дальше и принимают целые аудиофайлы в форматах WAV, MP3 и OGG, причём лучший результат дают чёткие однотональные записи с частотой дискретизации от 44,1 килогерца и выше.

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

  1. ставить узкополосный входной фильтр под частоту принимаемого тона, чтобы не пускать в анализ соседние сигналы и шум;
  2. применять адаптивный порог вместо фиксированного, иначе декодер срывается при изменении громкости сигнала;
  3. закладывать автоматическое определение скорости, поскольку темп передачи в эфире меняется от станции к станции;
  4. при работе с грязным эфиром предпочитать нейросетевой распознаватель пороговому, ведь он терпимее к искажениям;
  5. для записанных сигналов брать чистые однотональные файлы с высокой частотой дискретизации ради точности.

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