Python UDH API
В Engee поддерживается Python (подробнее см. Работа с Python). Для управления РИТМ SDR USRP в среде Python используется библиотека uhd. Основная проблема при работе с РИТМ SDR USRP на Python заключается в задержках при одновременной передаче и приеме сигнала. Ее можно решить с помощью разделения задач на два независимых процесса:
-
передача данных;
-
прием, обработка и визуализацией данных (с помощью
matplotlib).
В начале работы необходимо создать объект управления SDR. В Python это делается через класс uhd.usrp.MultiUSRP. При инициализации указывается IP-адрес устройства:
usrp = uhd.usrp.MultiUSRP("addr=192.168.2.100")
Далее нужно настроить частоту дискретизации, центральную частоту несущей и усиление для трактов приема (RX) и передачи (TX):
usrp.set_tx_rate(SAMP_RATE)
usrp.set_rx_rate(SAMP_RATE)
usrp.set_tx_freq(uhd.types.TuneRequest(CENTER_FREQ))
usrp.set_rx_freq(uhd.types.TuneRequest(CENTER_FREQ))
usrp.set_tx_gain(TX_GAIN)
usrp.set_rx_gain(RX_GAIN)
Для непосредственной передачи и приема выборок создаются объекты-стримеры. В них указываются форматы данных. В данном примере показано использование формата fc32 (комплексные числа с плавающей точкой) для вычислений в Python и sc16 (16-битные целые числа) для передачи по сети.
st_args = uhd.usrp.StreamArgs("fc32", "sc16")
tx_streamer = usrp.get_tx_stream(st_args)
rx_streamer = usrp.get_rx_stream(st_args)
Генерируем тестовый однотональный синусоидальный сигнал. Для этого используется библиотека numpy. Создаем массив комплексных чисел, смещенных относительно несущей частоты на заданный сдвиг.
t = np.arange(BUFFER_SIZE) / actual_rate tx_data = (AMPLITUDE * np.exp(1j * 2 * np.pi * TONE_OFFSET * t)).astype(np.complex64)
Для обеспечения бесперебойной работы SDR без задержек интерфейса, логика управления выносится в отдельный процесс mp.Process. Обмен данными с графической оболочкой происходит через Shared Memory (общую память). Это позволяет GUI-процессу мгновенно получать доступ к принятым выборкам.
existing_shm = shared_memory.SharedMemory(name=shm_name) shared_array = np.ndarray((BUFFER_SIZE,), dtype=np.complex64, buffer=existing_shm.buf)
Запускаются два параллельных потока:
-
Передатчик: бесконечно отправляет сформированный массив синусоиды в тракт передатчика с помощью функции
tx_streamer.send. -
Приемник: постоянно опрашивает буфер приемника командой
rx_streamer.recvи записывает полученные данные в общую память.
В основном процессе приложения происходит чтение данных из общей памяти и их визуализация. Для анализа спектра применяется быстрое преобразование Фурье (FFT) с использованием оконной функции Блэкмана для устранения спектральных утечек.
spec = np.fft.fftshift(np.fft.fft(local_snap * np.blackman(BUFFER_SIZE))) pwr = 20 * np.log10(np.abs(spec) / BUFFER_SIZE + 1e-12)
Результатом работы являются два графика: осциллограмма сигнала и его спектральное представление, обновляемые в режиме реального времени.