|
Разместил: |
DVE |
|
Всем привет.
Здесь на сайте выложено много статей по замечательной программе Signals Analyzer, которая является уникальным инструментом, аналогов которому среди общедоступного софта просто нет. Но SA как известно, не работает с файлами больше 50 Мб, что при скоростях сегодняшних SDR довольно мало, да и часть функций (в том числе и открытие IQ-файлов) залочены в платной версии, которую увы, больше не купить.
Я покажу как сделать частотную демодуляцию сигнала на примере IQ файла, записанного участником форума на частоте 403 МГц. IQ-файл c метеозонда записан приемником rtl-sdr, имеет размер около 500 Мб, и работать с такими файлами в SA весьма затруднительно. Python в свою очередь, имеет немало библиотек для обработки и визуализации данных, что позволяет обойтись весьма простым и понятным кодом.
Если открыть IQ-файл в SDR#, видно что сигнал находится на 100 КГц выше от центральной частоты. Запомним это значение, оно нам пригодится.
Увеличить
А теперь перейдем к Python. Для использования кода из статьи понадобится Python 3.7 и библиотеки numpy, scipy и matplotlib. Установить их можно с помощью pip.exe (RTFM), который входит в дистрибутив Python. Код кроссплатформенный и может работать где угодно, на Windows, Linux Или OSX.
Шаг 1. Подключаем необходимые библиотеки и загружаем файл
import matplotlib.pyplot as plt
import numpy as np
import scipy.signal as signal
import scipy.io.wavfile as wav
from scipy.fftpack import fft, fftfreq, fftshift
import os
wav_path = "SDRSharp_20201118_173512Z_403100kHz_IQ.wav"
fs, data = wav.read(wav_path, mmap=True)
Шаг 2. Вывод на экран
Этот шаг является опциональным, но удобным для контроля. Чтобы отрисовка работала быстрее, оставим только первые 3 секунды записи. При окончательной конвертации файла целиком эту строку можно закомментировать.
data = data[1*fs:4*fs]
Преобразуем данные в комплексные числа и выводим на экран спектрограмму:
data_iq = data[:, 0] + 1j * data[:, 1]
plt.specgram(data_iq, NFFT=1024, Fs=fs)
plt.title(os.path.basename(wav_path))
plt.xlabel("Time")
plt.ylabel("Frequency")
plt.show()
Если все было сделано правильно, получаем на экране спектр файла:
Его можно увеличить, скроллить и пр. Можно навести мышь на сигнал и убедиться, что он находится на частоте 100 КГц. Запомним эту частоту как параметр.
Шаг 3. Конвертация и фильтрация
Сдвинем сигнал вниз по частоте, для чего умножим его на другой комплексный сигнал, и отфильтруем. Для фильтрации мы будем использовать только вещественную часть, мнимую можно откинуть.
sig_new_center_hz = 30000
sig_bandwith_hz = 10000
freq = sig_freq_hz - sig_new_center_hz
fc = np.exp(-1.0j * 2.0 * np.pi * freq / fs * np.arange(len(data_iq)))
y = data_iq * fc
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = signal.butter(order, [low, high], btype='band')
return b, a
def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
b, a = butter_bandpass(lowcut, highcut, fs, order=order)
y = signal.lfilter(b, a, data)
return y
real = y.real
real_filteded = butter_bandpass_filter(real, sig_new_center_hz - sig_bandwith_hz, sig_new_center_hz + sig_bandwith_hz, fs, order=4)
Шаг 4. Децимация и запись
Децимация позволяет уменьшить размер файла за счет удаления избыточных значений. Этот шаг является опциональным, значение можно поменять на другое при необходимости.
resample = 4
if resample > 1: real_filteded = real_filteded[::resample]
wav.write(wav_path.replace(".wav", "-converted.wav"), fs//resample, real_filteded.astype(np.int16))
print("WAV saved")
Если все было сделано правильно, на выходе мы получим сконвертированный файл.
Результат: из исходного IQ-файла размером 500 Мб мы получили сконвертированный и отфильтрованный файл размером 64 Мб. Для проверки его можно открыть в том же SA, в бесплатной версии:
Если тема будет интересна, декодирование до битового потока можно рассмотреть в следующей части.
|
|
Автор |
Комментарий |
atmel49 Участник
|
27 Ноя 2020 18:51
Если тема будет интересна
Конечно интересна! Мне по крайней мере, поскольку под Linux вообще нет никакого адекватного софта для радиоконтроля. Одна винда кругом, которая никак не загнется.
|
Ernk Участник
|
25 Дек 2020 00:14
Не пойму где ошибка,но на выходе получается файл 2.74 мб
|
Ernk Участник
|
05 Янв 2021 23:15 · Поправил: 05 Янв 2021 23:26
Не пойму где ошибка,но на выходе получается файл 2.74 мб
Понятно с ошибкой просто нужно При окончательной конвертации файла целиком эту строку можно закомментировать.
data = data[1*fs:4*fs]
спасибо автору за помощь
|
Ernk Участник
|
05 Янв 2021 23:18 · Поправил: 05 Янв 2021 23:21
Рабочий код:
import matplotlib.pyplot as plt
import numpy as np
import scipy.signal as signal
import scipy.io.wavfile as wav
from scipy.fftpack import fft, fftfreq, fftshift
import os
wav_path = "SDRSharp_20201118_173512Z_403100kHz_IQ.wav"
fs, data = wav.read(wav_path, mmap=True)
# data = data[1*fs:4*fs]
data_iq = data[:, 0] + 1j * data[:, 1]
#plt.specgram(data_iq, NFFT=1024, Fs=fs)
#plt.title(os.path.basename(wav_path))
#plt.xlabel("Time")
#plt.ylabel("Frequency")
#plt.show()
sig_freq_hz = 100000
sig_new_center_hz = 30000
sig_bandwith_hz = 10000
freq = sig_freq_hz - sig_new_center_hz
fc = np.exp(-1.0j * 2.0 * np.pi * freq / fs * np.arange(len(data_iq)))
y = data_iq * fc
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = signal.butter(order, [low, high], btype='band')
return b, a
def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
b, a = butter_bandpass(lowcut, highcut, fs, order=order)
y = signal.lfilter(b, a, data)
return y
real = y.real
real_filteded = butter_bandpass_filter(real, sig_new_center_hz - sig_bandwith_hz, sig_new_center_hz + sig_bandwith_hz, fs, order=4)
resample = 4 # Для последующего декодирования заменить на 2
if resample > 1: real_filteded = real_filteded[::resample]
wav.write(wav_path.replace(".wav", "-converted.wav"), fs//resample, real_filteded.astype(np.int16))
print("WAV saved")
|
DVE Участник
|
05 Янв 2021 23:33
Спасибо что выложили. Только тем кто будет копировать, имейте в виду что форматирование здесь в текстах не сохраняется, отступы (например внутри def) придется добавлять вручную.
|
Ernk Участник
|
06 Янв 2021 14:26
Точно, сразу и не заметил
|
Добавлять комментарии могут только зарегистрированные, активировавшие регистрацию и не ограниченные в доступе участники сайта!
|
Файл создан: 26 Ноя 2020 21:30, посл. исправление: 08 Янв 2021 20:56 |
|