Изучаем распространение радиосигналов в ионосфере с помощью SDR

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

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



Я покажу как с помощью SDR-приемника и 50 строк кода на Python получить визуализацию сигналов радиостанций с точностью до долей герца, и увидеть довольно-таки любопытные атмосферные эффекты.

Продолжение под катом.

Общий принцип


Большинство АМ-радиостанций работает круглосуточно, что позволяет весьма наглядно изучить передаваемые ими радиосигналы. Для этого мы запишем сигнал радиостанции в формате WAV и построим его спектр при помощи FFT (Быстрого Преобразования Фурье). FFT позволяет из сигнала во «временной области» (time domain) получить изображение в «частотной области» (frequency domain), проще говоря, спектр сигнала. Чем больше размер окна преобразования, тем большее разрешение по частоте мы можем получить.

Как известно, сигналы АМ-станций выглядит в эфире следующим образом:



Собственно содержимое передачи нас интересовать не будет (кто-то еще слушает вообще радио?), для нас важна несущая — центр сигнала. Она является хорошим маркером, по которой удобно контролировать сигнал станции на спектре.

Запись


Для записи нам потребуется практически любой радиоприемник, умеющий принимать сигнал в формате боковой полосы (USB, Upper Side Band). SDR в этом плане наиболее удобен, но теоретически, даже обычный китайский Tecsun/Degen может подойти, если подключить его к линейному входу ПК.

Важный момент: станция передает в АМ, но но нам нужен сигнал до демодуляции, поэтому в настройках нужно выставить режим USB а не AM. Выберем ширину записи так, чтобы несущая радиостанции попадала в середину спектра. Это важно, т.к. при обработке мы будем вырезать из спектра именно середину.

Чем длиннее запись, тем интереснее результаты, основное ограничение тут в размере получаемого файла. Я использовал прием в режиме USB с полосой 4 КГц, формат записи WAV 8000 семплов/с, частоту SDR выбрал так, чтобы несущая частота радиостанции была в середине полосы фильтра. При таких настройках запись длительностью 24ч занимает в WAV около 1.3 ГБайт (на всякий случай напомню, что MP3 или другое сжатие с потерями для анализа сигналов использовать нельзя). Мои настройки HDSDR при записи выглядят так (важные моменты обозначены цифрами 1, 2, 3):



Обработка


Исходный код на языке Python приведен под спойлером. Мы последовательно читаем данные из WAV-файла, применяем к каждому блоку данных FFT + оконную функцию, и сохраняем результат в виде изображения. Яркость спектра можно варьировать в коде с помощью изменения параметра k_brightness, размер блока FFT передается в виде параметра командной строки. При использовании больших размеров FFT, например 4194304, мы не можем создать изображение такого же размера, поэтому из спектра сохраняется только центр (именно поэтому важно, чтобы несущая была по центру, хотя при желании смещение можно скорректировать вручную в коде).

spectrum.py
import numpy as np
import matplotlib.pyplot as plt
import wave
from PIL import Image
import sys
import time


def wav_process(filename: str, fft_size: int):
    # FFT size can be a number like 1024 or power of 2, like 2**20
    if fft_size < 512:
        fft_size = 2**fft_size

    w = wave.open(filename, 'r')
    num_columns = w.getnframes() // fft_size
    if num_columns > 4096:
        num_columns = 4096

    # Spectum parameters
    width, height = num_columns, 2048
    k_brightness = 16
    palette_r, palette_g, palette_b = 4, 1, 4

    # Output image
    data_out = np.zeros([height, width, 3])
    if fft_size < 2*height:
        fft_size = 2*height

    print("WAV Sample width:", w.getsampwidth())
    print("WAV Frame rate:", w.getframerate())
    print("Image size: {}x{}".format(width, height))
    print("Columns max. count:", w.getnframes() // fft_size)
    print("FFT Size:", fft_size)
    print("Spectrum width, Hz:", height*w.getframerate()/fft_size)
    print()

    pos_top = 0
    if fft_size > 2 * height:
        # Auto align vertical
        spectrum_center_y = height//2
        pos_top = spectrum_center_y*fft_size//(2*height) - height//2

    # Draw
    for x in range(num_columns):
        if (x % 50) == 0:
            print("Column {} of {}".format(x, num_columns))

        data = w.readframes(fft_size)
        raw_data = np.frombuffer(data, dtype=np.int16)

        if raw_data.shape[0] != fft_size:
            break
        data_h = np.hanning(fft_size)*raw_data
        raw_fft = np.fft.fft(data_h, n=fft_size, norm="ortho")[1:fft_size]
        raw_abs = np.absolute(raw_fft)
        raw_int = (raw_abs/k_brightness)  # (raw_abs/k).astype(int)

        for p1 in range(height):
            lum_val = raw_int[pos_top + p1]
            v = lum_val if lum_val < 255 else 255
            data_out[p1][x] = [v/palette_r, v/palette_g, v/palette_b]

    # Numpy array to PIL image
    img = Image.fromarray(np.uint8(data_out), 'RGB')
    # img.save('spectrum_{}x{}.png'.format(width, height))
    
    # Display
    plt.figure(tight_layout=True)
    time_total = num_columns*fft_size//w.getframerate()
    hz_total = height*w.getframerate()//fft_size
    extent = [0, time_total/3600, -hz_total//2, hz_total//2]
    plt.xlabel('Time, Hr')
    plt.ylabel('Freq, Hz')
    plt.imshow(img, extent=extent, aspect='auto')
    plt.show()


if __name__ == '__main__':
    print("WAV Spectrum Builder v0.1. (c) DmitrySpb79 for habr.com")
    if len(sys.argv) < 2:
        print("Usage: python spectrum.py file.wav [fft_size]")
        exit()

    wav_process(sys.argv[1], fft_size=int(sys.argv[2]) if len(sys.argv) == 3 else 0)

    print("App done")

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

python spectrum.py C:\HDSDR\HDSDR_20201023_083057Z_6068kHz_AF.wav 524288

Чтобы читателям не считать степени двойки вручную, приведу значения здесь: 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216,… Чем больше размер блока, тем выше разрешение по частоте, но ниже разрешение по времени, соответственно больше отсчетов требуется для отображения результата. Так, при размере блока FFT в 4194304, мы получаем разрешение по вертикали 0.002 Гц на пиксел, но всего лишь 70 пикселов спектра из 8-часовой записи. В коде нет никаких оптимизаций, возможно картинку можно улучшить перекрытиями спектра или варьированием вида оконной функции, но в разы лучше вряд ли будет, по сути все ограничивается длиной записи.

Результаты


Несколько примеров работы программы.

Запись на частоте 894 КГц. Небольшой размер блока FFT (4096 отсчетов), файл с большой шириной полосы записи, мы видим сигналы АМ-станций практически в том виде, в каком они передаются в эфире. Собственно, на картинке можно наблюдать сразу две станции, стандартный шаг в АМ между станциями 9 КГц.



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

Рассмотрим запись с большей детализацией. Та же частота, по центру картинки расположена несущая, размер FFT 262144 семпла. На экране ~5ч записи.



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

Одна такая линия начинается на отметке «1ч» и пропадает на отметке «4.4ч», при увеличении вполне четко виден симметричный спектр АМ-сигнала:



Скорее всего, здесь мы видим сигнал какого-то далекого передатчика, который принимался отражаясь от ионосферы, затем прохождение завершилось. Он расположен на той же частоте 894 КГц, но настройка не является идеальной, и реальная частота отличается от первого передатчика примерно на 20 Гц, что и позволило увидеть их раздельно. На слух уловить такое, разумеется, невозможно. Как и в астрономии, такие эффекты видны лишь при накоплении сигнала очень большой длительностьи.

И последний пример. Короткие волны, станция на частоте 6070 КГц. Запись продолжительностью сутки:



Как можно видеть, станция проходила наиболее сильно с 10 утра до 10 вечера, ночью сигнал сильно ослаб, а к утру на пару часов совсем исчез. Также интересен медленный дрифт частоты несущей в пределах 10Гц, но относится ли он к передатчику или к приемнику, мне неизвестно. Интересны также периодические моменты «раздвоения» несущей, возможно это какая-то турбулентность слоев ионосферы, отражение которых вызывает допплеровский сдвиг частоты. Возможно, это связано с текущей активностью Солнца и солнечного ветра. Теоретически, большое количество работающих АМ-станций представляет собой некое подобие «пассивного радара», что позволяет, зная частоты и местоположение станций, фактически «бесплатно», без затрат на излучение, анализировать состояние ионосферы. Проводились ли такие работы, мне впрочем, неизвестно.

Кстати, как бонус отображения спектра — по нему можно видеть моменты, когда станция проходила наиболее сильно. В связи с этим, у любителей DX может возникнуть вопрос, как же прослушать саму передачу. Для этого лучше записывать сигнал с большей частотой дискретизации, например 16 КГц, а центр несущей расположить на частоте 4 КГц. Далее, сдвинуть спектр в ноль несложно в GNU Radio с помощью такого графа соединений:



При запуске блок-схемы в GNU Radio будет создан сконвертированный WAV-файл, прослушать который можно любым плеером.

Заключение


Как можно видеть, обработка сигналов дальних станций с помощью спектрального анализа может быть довольно интересной. Любопытно и то, что метод не требует дорогостоящего оборудования. Основная сложность лишь в длительности записи, но наверное, чтобы не держать ПК постоянно включенным, хватит и ресурсов Raspberry Pi 4.

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

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

Средняя зарплата в IT

110 000 ₽/мес.
Средняя зарплата по всем IT-специализациям на основании 8 550 анкет, за 2-ое пол. 2020 года Узнать свою зарплату
Реклама
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее

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

    0
    Простите, может вопрос показаться нубским, я в Python не особо умею. Ругается на неправильный синтаксис:
    data = w.readframes(fft_size)
      0
      Проверьте что Python 3.7 и выше, под 2.7 я не тестировал.
        0
        У меня 3.7.4
          0
          Вижу, спасибо, опечатка была, пропущена закрывающая скобка строкой выше.
      0
      Сигналы навигационных спутников, принимают с помощью SDR. Для усиления воздействия ионосферы нужно использовать сигналы от спутников, максимально близких к горизонту. От широкополосного сигнала можно ожидать большей информативности.
        +4
        По теме прохождения могу порекомендовать книжки Propagation and Radio Science, автор Eric Nickols (KL7AJ) и Radio Wave Propagation в четырех частях по ~200 страниц каждая, автор Marcel De Canck (ON5AU). Эффект Допплера бывает на коротких и средних волнах, как правило в пределах 100 Гц, но вроде регистрировали и 1000+ Гц. «Раздвоение» сигнала скорее всего вызвано тем, что сигнал распространялся больше чем по одному пути. Это возможно по ряду причин, например long/short path. Также в результате двойного лучепреломления (birefringence) могут возникать X- и О-лучи, которые распространяются по разным траекториям.

        Кстати, я делал нечто похожее на то что вы описали, но методика была другая. Меня просто интересовало изменение уровня сигнала от известных радиостанций в зависимости от времени. Тут подробности.
          0
          Спасибо. Действительно, мысли сходятся :) Только вы анализировали амплитуду, я частоту.

          Есть еще мысль настроить запись на Raspberry Pi и пособирать статистику за сутки на разных диапазонах от ДВ до КВ.
          +1
          Визуализация великая вещь. Сразу понятно и наглядно.
            +2
            Простая физическая модель — односкачковое отражение от ионосферы.
            Доступное обощение — многоволновая регистрация (радио-вещающие станции
            с выделенными и фиксированными частотами).
            Сложнее — допплер-сдвиг, и уж для многоволновой регистрации.
            А там — кросс-спектральные характеристики, выделение примитивных круговых волн
            в ионосфере, триангуляция источников. Обычно это разрушающиеся вихри
            из стратосферы (триангуляция на уровне шумовых различий), но есть примеры
            НАЗЕМНЫХ источников (инфразвук с наименьшим затуханием), как-то
            — тепловые приливы на горных грядах (2-ды в сутки)
            — зоны повышения сейсмической активности.
              0

              Отражения вещательных УКВ-сигналов от самолётов и БПЛА используют военные. Про пассивную радиолокацию — это от них пришло.

              0

              "Проводились ли такие работы, мне впрочем, неизвестно."


              1. Поищите, например, на сайте ИЗМИ РАН.
              2. Как-то давным-давно видел подобный призыв к радиолюбителям коротковолновикам. Но как давно? Ещё в журнале или уже в сети?
                0
                Работы по зондированию ионосферы проводились 100%, наверно еще лет 50 назад, когда был расцвет СВ-ДВ-КВ. А вот делались ли опыты с пассивным приемом, тут не знаю.
                  0

                  Именно 1991+ по по времени и именно к коротковолновикам (что с их типовой мощностью излучения можно принимать за "пассивное" зондирование).

                0
                У меня знакомый делал контур размером 50см из нескольких витков проволоки и ловил радио частоты, которые излучают молнии. Так как пакет расплывается в зависимости от расстояния, то можно примерно оценить сколько километров до молнии.
                0

                DVE ?

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое