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

Управление SDR-платами РИТМ в Engee

Для дистанционной работы с SDR-платами DA-AX-FMC-RF9 на машине РИТМ используются EngeeDeviceManager.Targets.RITM_API.SDR — функции программного управления Engee. Подробное описание всех функций приведено на странице Программное управление SDR-платами РИТМ.

В статье приняты следующие сокращения:

  • SDR — программно-определяемая радиосистема;

  • RF — радиочастотная часть;

  • DDS — цифровой синтезатор;

  • JESD — цифровой интерфейс между FPGA и трансивером;

  • FHM — режим перестройки несущей;

  • MCS — синхронизация нескольких плат.

Текущая реализация программного управления рассчитана на два передающих (TX) и два приемных (RX) канала. С помощью программного управления можно обнаружить платы и инициализировать их, управлять несущей, синхронизацией, калибровкой, радиотрактом, затуханием TX, усилением RX и DDS, а также читать состояние платы и линий JESD. Передача и прием массивов I/Q-отсчетов относятся к отдельному интерфейсу.

Как устроено управление

Управление SDR-платами РИТМ в Engee осуществляется с помощью Engee.Интеграции. Engee обменивается данными по AMQP с клиентской программой Engee.Интеграции, установленной на управляющем компьютере пользователя. Клиентская программа обращается по HTTP к менеджеру на машине РИТМ; менеджер выполняет команду ritm-sdr для выбранной платы. Первый аргумент функций SDR — имя зарегистрированной машины, ее сохраненный IP-адрес или полный URL. Имя и IP-адрес должны быть добавлены в Engee; полный URL можно передать напрямую. Аргумент board — идентификатор платы, возвращаемый функцией listBoards, а не порядковый номер платы в списке.

Перед запуском примеров

  • Приложение Engee.Интеграции должно быть запущено и подключено на компьютере пользователя.

  • На машине РИТМ нужна совместимая версия прошивки не ниже v7.10.0.

  • В секции Подготовка замените RITM 1 и 192.168.56.3 данными своей машины. Идентификаторы плат берите из listBoards.

  • До операций с TX подготовьте RF-подключения: успешное выполнение initialize, calibrate и setTxAttenuation в текущей версии драйвера может оставлять радиотракт включенным.

Параметры и порядок работы

Несущая и частота DDS задаются в Гц, границы FHM — в МГц, затухание TX — в миллидецибелах (32_000 = 32 дБ), усиление RX — индексом таблицы, масштаб DDS — в миллионных долях (1_000_000 = 1.0). TX/RX-каналы имеют номера 0 и 1, индексы DDS — от 0 до 3. Для FHM указывайте обе границы в BoardConfig; setFrequency применим к плате, уже инициализированной с FHM. Для MCS конфигурации master и slave передаются одним вызовом initialize; отдельной команды MCS в программном управлении нет.

Выполните подготовку один раз, затем запускайте нужные секции отдельно. Каждая секция меняет состояние оборудования; не выполняйте все секции подряд. Методы изменения возвращают словарь с success и msg, поэтому проверяйте результат. Чтение возвращает значение непосредственно и при неуспешном запросе выбрасывает исключение. Групповая инициализация не атомарна; после ошибки или таймаута сначала прочитайте состояние затронутых плат и только потом решайте, повторять ли команду. Автоматического повтора команд SDR нет. radioOff выключает RF, сохраняя инициализацию; deinitialize завершает работу платы.

Пример использования программного управления для работы с SDR-платами РИТМ

Подготовка

Выполните код ниже один раз в текущей сессии перед выбранной секцией. Он подключает функции программного управления, задает имя машины РИТМ (ritm_name) и при необходимости добавляет ее в Engee через addMachine. Здесь же определяется проверка результата операций. После изменения имени или адреса машины выполните код повторно.

ritm_name = "RITM 1"
if !RITM_API.isMachineExists(ritm_name)
    RITM_API.addMachine(ritm_name, "192.168.56.3")
end

sdr = RITM_API.SDR

require_success = result -> begin
    if !get(result, "success", false)
        message = get(result, "msg", "operation failed")
        error("RITM SDR: " * string(message))
    end
    return result
end

Инициализация одиночной платы

Инициализация платы на фиксированной несущей с внутренней синхронизацией.

let
    board_id = 0
    carrier_frequency_hz = 300_000_000

    config = sdr.BoardConfig(
        id=board_id,
        frequency_hz=carrier_frequency_hz,
        topology="internal",
    )
    require_success(sdr.initialize(ritm_name, config))
end

Деинициализация одиночной платы

Остановка и деинициализация выбранной платы.

let
    board_id = 0

    require_success(sdr.deinitialize(ritm_name, board_id))
end

Инициализация двух плат в MCS

Инициализация master и slave одним групповым вызовом. MCS выполняется драйвером во время этой операции; отдельной команды MCS нет.

let
    master_id = 0
    slave_id = 1
    master_frequency_hz = 300_000_000
    slave_frequency_hz = 300_000_000

    configs = [
        sdr.BoardConfig(
            id=master_id,
            frequency_hz=master_frequency_hz,
            topology="master",
        ),
        sdr.BoardConfig(
            id=slave_id,
            frequency_hz=slave_frequency_hz,
            topology="slave",
        ),
    ]
    require_success(sdr.initialize(ritm_name, configs; slave_fallback=true))
end

Деинициализация двух плат

Деинициализация обеих плат одним групповым вызовом.

let
    board_ids = [0, 1]

    require_success(sdr.deinitialize(ritm_name, board_ids))
end

Калибровка каналов

Плата должна быть инициализирована. В примере выполняется последовательная калибровка каналов 0 и 1. Драйвер оставляет RF включенным после калибровки, поэтому секция выключает RF в блоке finally.

let
    board_id = 0
    channels = (0, 1)

    results = Dict{Int,Any}()
    try
        for channel in channels
            results[channel] = require_success(
                sdr.calibrate(ritm_name, board_id; channel=channel),
            )
        end
    finally
        radio_result = sdr.radioOff(ritm_name, board_id)
        if !get(radio_result, "success", false)
            @warn "Не удалось выключить RF после калибровки" radio_result
        end
    end
    results
end

Установка затухания

Плата должна быть инициализирована. Затухание передатчика задается в миллидецибелах: 32_000 соответствует 32 дБ.

let
    board_id = 0
    channel = 0
    attenuation_mdb = 32_000

    require_success(
        sdr.setTxAttenuation(ritm_name, board_id, channel, attenuation_mdb),
    )
end

Установка чувствительности

Плата должна быть инициализирована. Чувствительность приемника задается индексом таблицы усиления, а не значением в дБ.

let
    board_id = 0
    channel = 0
    gain_table_index = 255

    require_success(
        sdr.setRxGain(ritm_name, board_id, channel, gain_table_index),
    )
end

Контроль RF: включение и выключение

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

let
    board_id = 0

    enabled = require_success(sdr.radioOn(ritm_name, board_id))
    disabled = require_success(sdr.radioOff(ritm_name, board_id))
    Dict("enabled" => enabled, "disabled" => disabled)
end

Получение параметров одной платы

Чтение затухания и чувствительности обоих RF-каналов, состояния инициализации и топологии синхронизации. Функции чтения не включают радиотракт — параметры можно читать в любой момент.

let
    board_id = 0
    channels = (0, 1)

    Dict(
        "tx_attenuation_mdb" => Dict(
            channel => sdr.getTxAttenuation(ritm_name, board_id, channel)
            for channel in channels
        ),
        "initialized" => sdr.isInitialized(ritm_name, board_id),
        "topology" => sdr.getSyncTopology(ritm_name, board_id),
    )
end