Простой декодер медленного телевидения (SSTV)


Jоn Dаwsоn
https://101-things.readthedocs.io/en/latest/sstv_decoder.html

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

thumbnail6.jpg

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

Используя микроконтроллер Raspberry Pi Pico и недорогой TFT-дисплей, вы можете собрать компактный SSTV-декодер, для работы которого не требуется ПК. С помощью всего нескольких резисторов и конденсаторов декодер напрямую подключается к выходу для наушников любого радиоприемника, что делает его очень универсальным и простым в настройке.

В этом руководстве вы узнаете, как собрать и запрограммировать декодер, который позволит вам быстро принимать и отображать изображения SSTV. Независимо от того, являетесь ли вы опытным радиолюбителем или просто любопытным энтузиастом, этот проект предоставит вам прекрасную возможность изучить мир SSTV с минимальными затратами и усилиями.

Аппаратное обеспечение

wiring1.png

Аппаратная часть довольно проста и требует Raspberry Pi Pico и нескольких недорогих компонентов. Ниже приведен список всех необходимых деталей для сборки декодера.

Компонент

Количество

Пример URL

Дисплей ILI9341 или ILI9342 с разрешением 320x240 (SPI)

1

https://shorturl.at/Kwjb0

Raspberry Pi Pico

1

https://shorturl.at/bKibr

Резистор 10 кОм

2

https://shorturl.at/aSetc

Керамический конденсатор 100 нФ

1

https://shorturl.at/smvFK

Стереоразъем 3,5 мм

1

https://shorturl.at/KUiZ2

(Обратите внимание: ссылки приведены для иллюстрации и не обязательно являются рекомендациями)

Pi-Pico оснащен 12-битным АЦП, который используется для выборки выходного сигнала наушников с приемника. АЦП Pico требует напряжения от 0 до 3 В. Это означает, что он может обрабатывать пиковое напряжение до 3 В на выходе наушников большинства приемников без необходимости дополнительного усиления. Конденсатор является блокирующим конденсатором постоянного тока, а два резистора образуют делитель напряжения, обеспечивающий среднее напряжение смещения для АЦП.

Я использую дисплей ILI9341 с интерфейсом SPI, который недорогой и легкодоступный. Они также выпускаются в нескольких размерах, я использую 2,4-дюймовую версию. Вам нужно приобрести дисплей с интерфейсом SPI и убедиться, что вы подаете на него правильное напряжение питания.

Приобретенные мной дисплеи позволяют выбирать источник питания 5 В или 3,3 В. На обратной стороне есть перемычка, которую можно замкнуть, чтобы обойти стабилизатор напряжения и работать от источника 3,3 В. Сигналы ввода-вывода используют стандарт 3,3 В, поэтому они напрямую совместимы с Pi Pico.

В схеме используется 4-проводной интерфейс SPI для управления дисплеем. (Существуют дисплеи с более быстрым параллельным интерфейсом, но интерфейс SPI более экономичен с точки зрения ввода-вывода). Дисплей является однонаправленным и требует только выводов MOSI и SCK, сигнал MISO не используется. Кроме того, дисплею необходимы вывод выбора микросхемы и вывод «DC». Хотя дисплей имеет аппаратный сброс, я обнаружил, что его можно жестко запрограммировать на 3,3 В для экономии ввода-вывода, и пока что я получал надежные результаты, используя только программный сброс. В следующей таблице показана схема подключения дисплея.

Сигнал

Дисплей

Номер пина Pico

Номер GPIO Pico

Vcc

1

36 (3v3 out)

NA

GND

2

18 (GND)

NA

CS

3

17

13

RESET

4

36 (3v3 out)

NA

DC

5

15

11

MOSI

6

20

15

SCK

7

19

14

LED

8

36 (3v3 out)

NA

Программное обеспечение

block_diagram.png

Существует довольно много различных стандартов SSTV, но протоколы Martin и Scottie, похоже, являются наиболее популярными. Я также обнаружил, что довольно много сигналов используют PD50 и PD90. Режимы PD используют формат YCrCb вместо GBR, что позволяет более эффективно передавать информацию о цвете и, следовательно, передавать изображения намного быстрее, но они менее устойчивы к ошибкам частоты и часто имеют зеленоватый оттенок, если передатчик/приемник плохо откалиброван.

Сигналы SSTV предназначены для работы в узкополосных голосовых каналах. В них используется схема частотной модуляции, при которой интенсивность пикселя представляется тоном в диапазоне от 1500 Гц до 1900 Гц с горизонтальными синхронизирующими импульсами частотой 1200 Гц между каждой строкой.

martin.png

Каждое изображение начинается с импульса вертикальной синхронизации, за которым следует VIS-код. VIS-код — это 7-битное число, которое позволяет определить, какой стандарт используется.

Различные сигналы SSTV используют довольно схожую структуру, но, как правило, различаются по временным параметрам. Например, режим Scottie похож на режим Martin, но использует немного другую длину цветовой линии, и (что необычно) горизонтальная синхронизация появляется посередине линии между синей и красной составляющими.

scottie.png

Встроенный в Pi-Pico АЦП заменяет звуковую карту, используемую в «традиционной» системе SSTV. АЦП представляет собой 12-битное устройство с частотой дискретизации 500 кГц. Этого более чем достаточно для декодирования сигналов SSTV. Я использую АЦП с частотой 15 кГц, чего можно достичь, используя целочисленное деление тактовой частоты USB 48 МГц, что обеспечивает достаточную полосу пропускания.

Данные АЦП захватываются с помощью DMA в чередующиеся «пинг-понг» буферы. Это означает, что процесс захвата данных АЦП выполняется аппаратно автономно, в то время как программное обеспечение одновременно декодирует предыдущий блок (при этом второе ядро ??ЦП остается полностью свободным).

Я предполагаю, что приемник правильно настроен в режиме USB. АЦП выдает один «реальный» отсчет звука, захваченного с выхода для наушников. Существует множество методов измерения частоты, но в данном случае измерение изменения фазы между отсчетами кажется самым простым подходом.

Если у нас есть комплексный (I и Q) отсчет, мы можем напрямую измерить фазу каждого отсчета, поэтому первым шагом является преобразование действительного отсчета в комплексный отсчет с компонентами I и Q. Этого можно достичь с помощью преобразования Гильберта (или эквивалентного). Сигнал, состоящий только из действительных чисел, можно рассматривать как сигнал с мнимой составляющей, равной нулю. Действительный сигнал всегда имеет симметричный спектр с положительными и отрицательными боковыми полосами. Преобразование Гильберта можно рассматривать как асимметричный фильтр, который удаляет отрицательную боковую полосу, одновременно добавляя к сигналу мнимую составляющую, сдвинутую по фазе ровно на 90 градусов.

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

Следующий шаг — определение фазы каждого отсчета. Этого можно достичь с помощью функции atan2(i, q) . В проекте передатчика реализовано быстрое (и достаточно точное) приближение с использованием алгоритма CORDIC . Я снова использовал код из проекта передатчика.

Зная фазу каждого отсчета, мы можем вычислить частоту изменения фазы от одного отсчета к другому, используя простое вычитание. Фазовый выход алгоритма CORDIC масштабируется таким образом, чтобы полный диапазон 16-битного целого числа представлял 2*? радиан фазы. Это означает, что обычное поведение переполнения числа в дополнительном коде дает нам развертывание фазы (по модулю 2?) бесплатно. Для наглядности частота затем масштабируется, чтобы получить целочисленную частоту в Гц.

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

В ранних версиях декодера я декодировал VIS-код, чтобы определить, какой режим используется. Я обнаружил, что это ненадежный метод, и что отсутствие (или неправильное декодирование) VIS-кода приводит к потере всего изображения.

Я обнаружил, что измерение интервала между импульсами горизонтальной синхронизации позволяет мне приблизительно определить используемый режим, что приводит к более надежному декодированию, позволяя декодировать изображения даже при отсутствии информации о видимом диапазоне (например, из-за помех или замирания сигнала). Декодирование изображения завершается либо после получения максимально ожидаемого количества строк, либо по истечении времени ожидания. Длительность времени ожидания — это компромисс: короткие тайм-ауты могут привести к декодированию изображения в двух отдельных частях, если замирание сигнала происходит в процессе передачи. Длительный тайм-аут может привести к пропуску начала нового изображения. Я обнаружил, что тайм-аут в 30-40 секунд является хорошим компромиссом, но ваши результаты могут отличаться.

Еще одна полезная (или даже необходимая?) функция — автоматическая коррекция наклона. Наклон возникает, когда частота дискретизации в передатчике и приемнике не совпадает. Ошибка даже в доли процента может привести к значительному наклону изображения. При передаче SSTV рекомендуется тщательно калибровать частоту дискретизации, и при соблюдении этой практики можно добиться минимального наклона без какой-либо коррекции.

without_slant_correction.png

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

with_slant_correction.png

Между дисплеями ILI9341 существует множество различий; у меня были совершенно одинаковые дисплеи, отличавшиеся только цветом и поворотом. Поворот и цвет дисплея можно настроить с помощью параметров компиляции в скетче. Изменяя параметры поворота и цвета в скетче, можно добиться работоспособности кода с большинством вариантов дисплеев.


#define PIN_MISO 12 //not used by TFT but part of SPI bus
#define PIN_CS   13
#define PIN_SCK  14
#define PIN_MOSI 15
#define PIN_DC   11
#define SPI_PORT spi1

#define ROTATION R0DEG
//#define ROTATION R90DEG,
//#define ROTATION R180DEG,
//#define ROTATION R270DEG,
//#define ROTATION MIRRORED0DEG,
//#define ROTATION MIRRORED90DEG,
//#define ROTATION MIRRORED180DEG,
//#define ROTATION MIRRORED270DEG

#define INVERT_COLOURS false
//#define INVERT_COLOURS true

#define STRETCH true
//#define STRETCH false

#define ENABLE_SLANT_CORRECTION true
//#define ENABLE_SLANT_CORRECTION false

#define LOST_SIGNAL_TIMEOUT_SECONDS 40

Корпус, напечатанный на 3D-принтере

enclosure1.jpg

Я разработал простой корпус для SSTV-декодера, напечатанный на 3D-принтере. Дизайн в FreeCAD и STL-файлы можно найти здесь.

Заключение

snow.jpg

Я вполне доволен декодером SSTV и мне удалось принять довольно много SSTV-изображений, используя очень простое оборудование. В будущем я хотел бы рассмотреть возможность расширения диапазона принимаемых SSTV-режимов. Должна быть возможность добавить поддержку SD-карт, чтобы изображения автоматически сохранялись по мере загрузки. Я также думаю, что должна быть возможность декодировать гораздо более широкий диапазон сигналов, используя идентичное оборудование. При наличии соответствующего программного обеспечения, я считаю, что оборудование должно быть способно принимать факс, CW, RTTY, PSK31 и FT8.

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

Cсылки


Примечание от RA3TOX.

Для проверки работоспособности проекта был собран макет декодера.

Макет RA3TOX

В качестве софта использовался файл декодера с SD-картой: sstv_receive_with_sd.uf2

Процедура загрузка программы очень простая:

  1. Переводим плату в режим программирования
    • подаем питание на плату
    • нажимаем обе кнопки BOOT и RST
    • отпускаем сначала кнопку RST потом BOOT
  2. Убеждамся, что у нас на ПК появился новый диск
  3. Копируем на этот диск файл нашей программы с расщирением .DFU
  4. После этого наш новый диск перезагружается.
  5. Радостно выдыхаем... Процесс загрузки завершен!

Если всё сделано правильно (софт загружен, разводка платы и дисплея правильная), то при включении на дисплее вы увидите картинку с заставкой автора программы:

Макет RA3TOX

В своей работе в эфире для передачи-приема SSTV я использую программу MMSSTV.
Для проведения тестов я соединил выход звуковой карты ПК со входом декодера. Выбрал картинку для передачи и наблюдал процесс приема на дисплее декодера.
Для тестирования вы можете просто выбрать звуковой файл с примерами картинок на сайте Spacecomms и запустить его на проигрывание.
У меня получилось нечто такое:

Макет RA3TOX

Картинка получилась достаточно шумновата. Я предполагаю, что это вызвано помехами от внешних источников, наведенных на достаточно длинные провода моего макета.
При "чистовом" изготовлении надо тщательно экранировать все входные элементы и выполнить их максимально короткими проводами.

Хочу остановится на некоторых нюансах, которые у меня возникли при запуске программы.
  • При запуске программы первоначально происходит инициализация SD-карты. Поэтому, если она не произошла - программа не будет работать!

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

  • Во время процесса приема картинки в левом нижнем углу дисплея появляется строка с модой картинки и её размер в пикселях (см. фото).

Макет RA3TOX

Удачи!
73


[ На главную ] [ В раздел ] [ Декодер SSTV - часть 2 ]