Документация Engee

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)

Результатом работы являются два графика: осциллограмма сигнала и его спектральное представление, обновляемые в режиме реального времени.

image.png