Привет, Хабр.

Сегодня мы продолжим тему SDR-приема и обработки сигналов. Приемом аналогового ТВ я заинтересовался совершенно случайно, после вопроса одного из читателей. Однако это оказалось не так просто, из-за банального отсутствия образцов сигнала — во многих местах аналоговое ТВ уже отключено. Читатель даже прислал запись с RTL-SDR, однако ширина записи у RTL порядка 2МГц, в то время как полоса ТВ-сигнала занимает около 8МГц, и на записи было ничего не понятно. В итоге, тема была надолго заброшена, и наконец, только сейчас, в очередную поездку к родственникам я взял с собой SDRPlay, и настроившись на частоты ТВ-каналов, увидел на экране искомый сигнал.

Небольшая программа на Python, и все работает:



Для тех, кому интересны подробности, продолжение под катом.

Теория


В те давние послевоенные годы, когда о цифровой передаче сигналов знали только в секретных лабораториях, но люди уже хотели смотреть ТВ, существовали три конкурирующих аналоговых стандарта. Первым был американский NTSC (National Television System Committee), который разрабатывался еще с 40х годов, был «заточен» под американскую частоту сети 60Гц и имел вертикальное разрешение всего лишь в 486 строк. Чуть позже в Германии стал разрабатываться стандарт PAL (Phase Alternating Line), который был немного лучше американского (разрешение «целых» 576 строк и ориентированность на европейскую частоту сети 50Гц), и еще чуть позже появился французский SECAM (Sequentiel couleur a memoire). В нем были устранены некоторые недостатки PAL, которые касались передачи цвета, ну и есть версия, что принятие двух стандартов также было политическим решением, чтобы жители одних стран не могли смотреть передачи из стран других (до единого Евросоюза и Шенгена было еще около 50 лет). Так или иначе, но весь мир оказался разделен примерно так:



Т.к. Хабр все-таки сайт русскоязычный, то в дальнейшем мы будем рассматривать именно SECAM, хотя если кто-то пришлет образец сигнала PAL, тоже было бы интересно.

Спектр SECAM, если верить старинным свиткам, выглядит следующим образом:



Слева, на частоте F0, находится амплитудно-модулированный яркостный (L) сигнал. Это фактически черно-белое изображение, которое до сих пор может быть показано на старом теплом и ламповом черно-белом ТВ. Проблема Legacy и наличия у пользователей старых девайсов существовала уже тогда, так что цветовой канал был добавлен отдельно, без потери совместимости со старыми телеприемниками. Два канала цвета передавались поочередно в частотной модуляции на частотах 4.25 и 4.406МГц. И наконец, еще выше по частоте отдельно передавался звук, также в частотной модуляции.

Кстати, с приемом ТВ в Петербурге есть забавный момент. Как отрапортовали российские СМИ, аналоговое ТВ было отключено еще в октябре:



Однако это касается лишь государственных каналов, коммерческие никто не принуждает отключать свое вещание. По крайней мере, на момент написания статьи (декабрь 2019) примерно 5-6 каналов еще доступны в «аналоге» прямо в центре Питера. Но сколько это продлится, неизвестно, так что желающим записать «для истории» образцы сигналов наверное все-таки стоит поторопиться.

Наконец, настала пора включить SDR и посмотреть, что мы имеем в реале:



Звуковой канал сложности не представляет, на него можно просто навестись «мышкой» в HDSDR, выбрать FM с шириной полосы порядка 50КГц и послушать. Мы начнем декодирование с канала яркостного, это позволит нам получить готовую «картинку».

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


Как было написано выше, сигналы яркости передаются в АМ. Чтобы не писать декодер самостоятельно, воспользуемся GNU Radio — перенесем спектр на нулевую частоту, запустим АМ-декодер и сохраним результат в файл.



Теперь мы можем открыть сохраненный файл в Python:

import numpy as np
import matplotlib.pyplot as plt


lum_data = np.fromfile("pal_lum.raw", dtype='int32')
lum_data = -lum_data - 4700

fs = 9000000//2
x_time = np.linspace(0, len(lum_data)/fs, num=len(lum_data))
plt.plot(x_time, lum_data)

Мы видим на экране последовательность из 4х кадров.



Длина одного кадра 0.02с — это как раз 1/50 — кратно частоте сети 50Гц, сигналы которой служат в качестве «тактового генератора» (не забываем, что сигнал аналоговый). За каждый кадр передается 320 строк — развертка у нас черезстрочная, так что итоговая частота кадров составляет 25Гц.

Посмотрим отдельные строки подробнее:



Как можно видеть, началу каждой строки соответствует «синхроимпульс», затем размах сигнала соответствует текущим значениям яркости в данной строке. Все довольно просто, и вероятно, практически без изменений такой сигнал и подавался на электронно-лучевую трубку ТВ.

Остальное дело техники. Создаем в памяти изображение и копируем в него два кадра, т.к. развертка у нас черезстрочная. Размах сигнала не превышает +200, что позволяет нам записать эти значения напрямую как цвета RGB.

# Output image
frame_size = fs*1//50

img_x, img_y = 320, 650
img_size = (img_y, img_x, 3)
img_data = np.zeros(img_size, dtype=np.uint8)
img_data.fill(255)

frame_num = 0
# Frame #1
pos_x, pos_y = 0, 0
for px in range(frame_num*frame_size, (frame_num+1)*frame_size):
    val = lum_data[px]

    if val < 0: val = 0
    if val > 255: val = 255
    img_data[pos_y][pos_x] = (0, val, 0)
    pos_x += 1
    if lum_data[px] <= 0 and lum_data[px+1] > 0:
        pos_x = 0
        pos_y += 2

print("Scan lines 1:", pos_y)

# Frame #2
pos_x, pos_y = 0, 0
for px in range((frame_num+1)*frame_size, (frame_num+2)*frame_size):
    val = lum_data[px]

    if val < 0: val = 0
    if val > 255: val = 255
    img_data[pos_y+1][pos_x] = (0, val, 0)
    pos_x += 1
    if lum_data[px] <= 0 and lum_data[px+1] > 0:
        pos_x = 0
        pos_y += 2

img_resized = cv2.resize(img_data, dsize=(3*img_x, img_y), interpolation=cv2.INTER_CUBIC)
plt.imshow(img_resized, interpolation='nearest')

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

Окончательный результат на анимации из 10 кадров (больше не принимает файловый архив Хабра):



Заключение


Подобные стандарты интересно анализировать, т.к. во-первых, они довольно-таки простые для реализации, во-вторых, их изучение представляет еще и отчасти исторический интерес. Разумеется, цели сделать полноценный софтовый ТВ-тюнер у меня не было, так что код приведен в минимально-работоспособном виде.

Если оценки статьи будут положительны, во второй части можно будет рассмотреть работу с цветом, и вывести полноценную цветную картинку.

Для желающих поэкспериментировать самостоятельно, IQ-файл можно скачать по ссылке.

Всем удачных экспериментов.

Комментарии (17)


  1. Mogwaika
    27.12.2019 14:42

    Как-то некрасиво синхронизация получается, надо бы петли какие-нибудь использовать. Как вы вообще на пиксели разбили я не очень понял…
    Слишком завязано на частоту семплирования, хорошо бы ей же просемплировать 50 Гц из сети)).

    p.s. Почему не все цвета, а только зелёный использовали?


    1. quwy
      28.12.2019 03:19

      Слишком завязано на частоту семплирования, хорошо бы ей же просемплировать 50 Гц из сети)).

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

      Почему не все цвета, а только зелёный использовали?

      Аналоговое телевидение — это не RGB, там как бы нет зеленого и остальных цветов. Есть яркостная составляющая и два хитро закодированных сигнала, которые в сумме с яркостным уже дают RGB для кинескопа (с кучей ограничений и артефактов, причем в каждой системе — своих). Так что тут очевидно используется только яркостная составляющая (как при приеме на старый черно-белый телевизор), зачем-то выводимая на экран пикселами зеленого цвета (чтобы имитировать «инструментальные» зелено-черные трубки?).


  1. dvserg
    27.12.2019 14:43

    С чем связаны построчные сдвиги? Может быть задержка обратного хода луча не учтена (строка/кадр)?


    1. Mogwaika
      27.12.2019 14:44

      Я думаю это не точный выбор начала и длины строки.


  1. dvserg
    27.12.2019 14:50

    Размах сигнала не превышает +200, что позволяет нам записать эти значения напрямую как цвета RGB.

    Secam использует цветоразностные сигналы R-Y и B-Y. Есть формула его вычисления?


    1. bodqhrohro
      28.12.2019 08:07

      Y=0.3R+0.6G+0.1B


  1. Otard
    27.12.2019 14:54
    +3

    Два канала цвета передавались поочередно в частотной модуляции на частотах 4.25 и 4.406МГц.

    Правильнее будет «на частотах F0+4.25 и F0+4.406 Мгц»


  1. enclis
    27.12.2019 15:46

    Окончательный результат на анимации из 10 кадров (больше не принимает файловый архив хабра)

    Хабр до сих пор не поддерживает WebM?


  1. JerleShannara
    27.12.2019 17:36
    +4

    199х года: Айтишники наконец-то додумались до использования видеомагнитофона, чтобы смотреть видео(Заставив АрВид читать с ленты MPEG-1 файлы в реальном времени)
    201х года: Айтишники наконец-то додумались до использования ТВ тюнера, чтобы смотреть телепередачи


  1. Shyster
    27.12.2019 17:49
    +2

    http://rtl-sdr.ru/category/tvsharp
    Вроде давно есть.


  1. interrupt
    27.12.2019 20:24
    +2

    Интересная задача при декодировании аналогового TV IMHO это декодирование цвета. А именно разделение яркостного сигнала и сигнала цветовой поднесущей. Желательно без потери четкости. Я как то писал симуляцию NTSC подобного кодирования, получилось так:

    Показать рыбок
    Исходная картинка (здесь и далее картинки кликабельны):


    Она же в черно-белом виде с поднесущей (примерно так принимал черно-белый телевизор). Если смотреть без ресайза то хорошо видна поднесущая на окрашенных деталях.


    Она же после декодирования. Тут можно увидеть артефакты от примененного мной подхода к фильтрации.


  1. lbv
    27.12.2019 22:17
    +2

    В аналоговом телевидении один полный кадр состоит из 625 строк, разбитых на два поля по 312,5 строк. Это обеспечивает чересстрочность. Каждое поле часть строк отводит на кадровую синхрогруппу, раньше это называлось кадровый синхроимпульс со строчными синхроврезками (на мой взгляд, это было более понятно). Для нормальной синхронизации следует через одно поле начинать вывод строки с середины экрана.
    Синхронизация по переходу через ноль — нормально при достаточно чистом сигнале.
    А в качестве лирического отступления могу сказать, что применение SECAM в СССР было вызвано не только политическими, но и техническими причинами. При большой протяженности линий передачи и не особо высоком их качестве, в телевизионном сигнале за счет дисперсии происходило искажение цвета. В SECAM дисперсия приводила к незначительному сдвигу цветного сигнала по отношению к яркостному, практически незаметному невооруженным глазом.
    UPD. Для исключения дрожи изображения частота дискретизации должна быть кратна частоте строк, т.е. быть равной N*15625 Гц


  1. danfee
    28.12.2019 09:27

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


  1. FSA
    28.12.2019 10:24

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


    1. lbv
      28.12.2019 15:30

      Если серьезно смотреть, то структуру сигнала нужно из ГОСТа брать. ГОСТ 7845, последняя редакция в 1992 году. Ссылка на официальный текст: protect.gost.ru/v.aspx?control=8&baseC=-1&page=0&month=-1&year=-1&search=&RegNum=1&DocOnPageCount=15&id=128340


  1. Byteman
    28.12.2019 11:43

    Если нужен образец сигнала, возьмите любой видеомагнитофон или DVD-плеер с модулятором.


  1. afiskon
    29.12.2019 04:47

    Спасибо, интересно. Пишите еще!