ГлавнаяБлогДекодирование азбуки Морзе: почему это сложнее, чем кажется
Алгоритмы

Декодирование азбуки Морзе: почему это сложнее, чем кажется

Декодирование азбуки Морзе — нетривиальная задача. Узнайте, как отличать точки от тире и буквы от слов. Попробуйте свой код прямо сейчас!

Al
Редакция Algolitalgolit.ru
8 мин чтения10 августа 2026 г.

Декодирование азбуки Морзе: почему это не обратная задача генерации

Когда я закончил генератор текста в азбуку Морзе, я думал, что декодирование будет той же задачей, но в обратную сторону. Как же я ошибался. Генерация сигнала означает, что вы контролируете каждую границу времени точно. Декодирование — это поиск этих границ в чужом несовершенном сигнале, и «несовершенный» — это норма, а не исключение. В этой статье я покажу, как решить эту задачу на Python, и объясню, почему тестирование на собственных данных может вас обмануть.

Почему декодирование — это принципиально другая задача

Когда вы генерируете азбуку Морзе, каждая точка, тире и пауза создаются из одной чистой базовой единицы. Нет никакой двусмысленности: тире — это всегда ровно 3 единицы, потому что вы так задали. При декодировании вы работаете с сырым сигналом (амплитуда звука во времени или позиции пикселей в изображении) и должны ответить на два отдельных вопроса для каждого импульса:

  • Это точка или тире? Ответ зависит от сравнения длительности с другими длительностями в том же сообщении, а не с фиксированным порогом, потому что разные отправители передают с разной скоростью.
  • Это пауза между буквами или между словами? Та же проблема: пауза в 3 единицы и в 7 единиц выглядит совершенно по-разному на скорости 20 слов в минуту, но если захардкодить эти точные значения, декодирование сломается, как только кто-то передаст на 15 слов в минуту.

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

def classify_durations(pulses):
    """Классифицирует длительности импульсов как точки или тире.
    pulses: список длительностей в миллисекундах.
    """
    shortest = min(pulses)          # аппроксимация единицы точки
    unit = shortest
    result = []
    for d in pulses:
        ratio = d / unit
        if ratio < 2:
            result.append('dot')
        elif ratio < 5:
            result.append('dash')
        else:
            result.append('dash')   # запасной вариант для шумного входа
    return result

Это упрощённая версия — реальная реализация также должна фильтровать фоновый шум, обрабатывать дрейф скорости в длинном сообщении и решать, что делать, когда сигнал не группируется чётко (что случается чаще, чем вы думаете, если новичок стучит рукой).

Две разные задачи декодирования, два разных инструмента

В итоге я создал два отдельных инструмента, а не один, потому что входные данные принципиально различаются:

Декодирование аудио

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

Декодирование изображений

Изображение — это пространственная, а не временная структура: точки и тире как отметки на странице, где «длительность» — это ширина в пикселях, а паузы измеряются в пикселях, а не в миллисекундах. Логика соотношений та же, но конвейер обработки совершенно другой.

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

Что меня по-настоящему смирило

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

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

Практический вывод: что делать прямо сейчас

Если вы работаете с декодированием импульсных сигналов — Морзе или любым бинарным ритмом — попробуйте такой подход: возьмите реальные данные (например, записи с радио) и посмотрите, как ваш алгоритм справляется с шумом. Не ограничивайтесь идеальными тестами. Начните с простой классификации по относительным длительностям, как в примере выше, а затем добавьте фильтрацию шума и обработку дрейфа. И помните: если ваш код работает на синтетике, это только первый шаг.

#азбука Морзе#декодирование сигналов#Python#обработка сигналов#алгоритмы
Al
Редакция Algolit

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

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →