Данная работа демонстрировалась на конференции «Технологии разработки и отладки сложных технических систем» 27-28 марта 2018 года.
Постановка задачи
Требуется разработка системы из генератора сигналов и АЦП которая будет формировать сигнал с заданными параметрами и производить его оцифровку. Полученные данные должны быть переданы в Simulink на обработку.
Аппаратура
Для работы собран стенд из модуля АЦП и генератора. В качестве АЦП используется субмодуль FM412x500M в котором есть четыре канала АЦП с частотой дискретизации 500 МГЦ. Субмодуль установлен на несущий модуль FMC128E в котором есть ПЛИС Artix 7 и интерфейс USB 3.0. Оба устройства подключены к ноутбуку с запущенным Simulink. Для контроля работоспособности разумеется используется осциллограф.
Внешний вид стенда:
Структурная схема стенда:
Сформированный сигнал:
Алгоритм работы стенда:
- Simulink подготавливает к запуску АЦП и генератор
- Simulink даёт команду генератору на запуск
- Генератор формирует строб (жёлтый сигнал) и собственно сигнал (голубой)
- АЦП по фронту строба начинает сбор данных
- АЦП собирает массив и передаёт его в Simulink
- Simulink отображает принятый сигнал от АЦП
Это классический однократный режим сбора. Его особенностью является именно однократность. Аппаратура по фронту сигнала собирает заданный массив данных. Фаза сбора данных происходит в режиме «жёсткого реального времени», а вот обработка — как получиться. Скорость сбора определяется числом выбранных каналов и частотой дискретизации. Для четырёх каналов АЦП и частоте дискретизации 500 МГц скорость потока данных составляет 4 Гбайт/с. С этой скоростью данные могут быть записаны в SODIMM модуля FMC128E. То есть может быть сохранена выборка объёмом 4 Гбайт.
Далее данные должны быть переданы в компьютер. Модуль FMC128E подключается к компьютеру через интерфейс USB 3.0. Скорость передачи данных составляет 300 Мбайт/c.
Simulink принимает массив данных и передаёт его на дальнейшую обработку. Время этой обработки уже определяется сложностью модели. В данном примере массив просто отображается на панели осциллографа.
В какой-то момент Simulink решает что нужно проводить следующий цикл и всё повторяется. Опять по USB передаются команды на подготовку АЦП, на запуск генератора и на сбор данных.
Такой режим очень удобен для отладки аппаратуры и алгоритмов. Можно никуда не торопиться. Собрать массив данных. На него спокойно посмотреть, записать на диск, выпить кофе. А вот когда всё будет отработано, то тогда уже можно переходить на непрерывный режим сбора.
Подключение DLL
Matlab позволяет подключать функции реализованные во внешних DLL. Simulink также имеет возможность подключения внешних DLL, при этом он добавляет некоторые требования. Внутри Simulink внешняя DLL выглядит как блок S-Function.
MATLAB предоставляет огромное количество примеров, в том числе и по созданию внешних DLL. Однако способ который предлагает MATLAB не очень удобный. Существует OpenSource проект easyLink. В этом проекте разработана библиотека классов для подключения к Simulink.
Для создания компонента требуется создать класс наследник от BaseBlock и объявить порты:
Проблемы подключения DLL
Внешние DLL позволяют очень многое, но при работе с ними есть ряд проблем. Наиболее существенными лично для меня являются следующие:
- Затруднена отладка DLL
- Неудобно смотреть вывод printf()
- Перекомпиляция DLL требует выхода из MATLAB
При отладке программы требуется проводить пошаговую отладку. В случае DLL существует возможность подключиться к уже загруженной в память DLL, назначить там точку останова и провести сеанс отладки. Но это надо отлавливать момент загрузки DLL через Simulink, каким то образом задерживать старт работы. Всё это сделать можно, но неудобно.
В процессе работы очень хочется видеть отладочный вывод который формируется как стандартный потоко stdout. В случае с DLL этот поток как то можно перехватить, но мне это не удалось.
Ну и наконец самое главное неудобство это необходимость выхода из MATLAB при перекомпиляции DLL. Иначе просто не удаётся записать новый файл. А выход и последующий запуск MATLAB занимает много времени.
Для решения этих проблем существует классический способ построения сложных программных комплексов. Это взаимодействие между программами через разделяемую память.
Подключение через разделяемую память
Современные операционные системы, как Windows так и Linux, позволяют организовывать общие области памяти. Это позволяет создавать надёжные программы. Например одна программа может содержать графический интерфейс и взаимодействовать с оператором, а другая программа может взаимодействовать с аппаратурой. При этом зависание программы которая взаимодействует с аппаратурой не приведёт к зависанию программы взаимодействия с оператором. В случае с Simulink такой подход также даёт некоторые преимущества. Программа для работы с аппаратурой будет запущена один раз, она подготовит аппаратуру и будет ждать команды через разделяемую память. DLL будет загружаться каждый раз при запуске Simulink на моделирование. Поскольку DLL не работает напрямую с аппаратурой, то это этот запуск будет производиться быстро.
Для данного стенда разработаны две программы и две DLL:
- simulink_a7dac — программа управления генератором
- simulink_adc — программа управления АЦП
- sm_ctrl — DLL управления генератором
- sm_adc — DLL управления АЦП
Структурная схема представлена на рисунке ниже:
Программа simulink_adc построена на основе библиотеки Bardy. Эта программа позволяет работать с любыми АЦП производства АО «ИнСис». Настройка на конкретный АЦП и несущий модуль производится через файлы инициализации.
Вид схемы в Simulink
Ну и наконец как это выглядит внутри Simulink:
Всё выглядит так как и принято в Simulink. Один блок для управления АЦП. Второй блок для управления генератором. Для управления генератором доступен ряд параметров. Для АЦП — всё через файл инициализации. При необходимости ряд параметров АЦП также можно вывести на уровень блока.
Обратите внимание на два задающих генератора. Они задают в терминах модельного времени момент старта и момент сбора данных. Эти моменты очень важны. Они собственно и задают связь между моделью и реальным миром. Сигнал старта поступает в блок АЦП, он обрабатывается в DLL. Через разделяемую память он поступает в программу АЦП. Далее он преобразуется в последовательность команд записи в регистры, которые через USB поступают в ПЛИС. А внутри ПЛИС взводится автомат поиска фронта сигнала старта. И только после того как автомат будет взведён в обратную сторону по этой же цепочке пойдёт подтверждение. Когда подтверждение дойдёт до Simulink на выходе блока sm_adc появиться сигнал start_out который будет передан в блок sm_ctrl. Причём это будет всё тот же самый момент модельного времени. В блоке sm_ctrl по такой же цепочке сигнал будет передан в ПЛИС генератора и она сформирует посылку сигнала. АЦП захватит этот сигнал в своей памяти. От второго задающего генератора будет сформирован сигнал сбора данных. По такому же пути данные попадут в Simulink и поступят на выход данных блока sm_adc. В данный момент возвращается блок размером 16384 отсчёта. Принятый блок отображается в осциллографе.
Результаты
Работа через разделяемую память показала свою эффективность. Программа управления АЦП позволяет работать с любыми нашими АЦП. При этом остаётся удобный способ настройки параметров через файл конфигурации. Программа разработана как консольное приложение, при этом виден весь отладочный вывод. Есть индикация работоспособности. Компонент SM_CTRL позволяет подключать различные внешние приложения для управления аппаратурой. Отладка программы управления АЦП не вызывает никаких трудностей. Это обычная программа, в которой можно установить точки останова и проводить отладку. По этой же технологии могут быть разработаны и другие программы для взаимодействия между Matlab/Simulink и внешним миром.
Работа опубликована на сайте hub.exponenta.ru;
Ссылки:
Комментарии (15)
ser-mk
07.10.2019 03:19Существует OpenSource проект easyLink. В этом проекте разработана библиотека классов для подключения к Simulink.
Последний коммит в 15 году((
Затруднена отладка DLL
Неудобно смотреть вывод printf()
Перекомпиляция DLL требует выхода из MATLAB
1.Зачем отлаживать в симулинке? Можно использовать же тестовые фреймворки!
2. Я так понял его вообще невозможно смотреть. Но на этот случай надо просто правильно писать систему логирования.
3. Может вы просто не делали unloadlibrary?dsmv2014 Автор
07.10.2019 09:27Последний коммит в 15 году((
Ну если проект достиг совершенства, то зачем коммиты :-)
1. Симулинк как раз и является тестовым фреймворком. И мне нужен полный контроль за моим кодом. Как за тем что есть в схеме симулинка, так и за тем что в DLL и программах управления аппаратурой. Я этого достиг.
2. Про тестовый вывод — printf() как раз и является системой логирования. Простой и очень эффективной. И легко переносимой между разными программами. Ну вот я его и использую. Причём везде, в том числе и в программах с GUI.
3. Может. Вот только я не вижу места где бы я мог его вызвать. У меня есть код DLL на С++, есть S-Function которая вставляется в схему Simulink. А вот отдельного m-файла нет. И вроде бы он не предполагается. Я не прав?ser-mk
07.10.2019 14:10Ну если проект достиг совершенства, то зачем коммиты :-)
Это очень хорошо, то вот что делать когда matlab поменяет API, будет очень неприятно остаться без поддержки
1. Симулинк как раз и является тестовым фреймворком. И мне нужен полный контроль за моим кодом. Как за тем что есть в схеме симулинка, так и за тем что в DLL и программах управления аппаратурой. Я этого достиг.
Интересное мнение. А какие вы нашли у него преимущества по сравнению с другими фреймворками для тестирования? Хотя бы по сравнению с Google Test и Ctest+Cmake…
2. Про тестовый вывод — printf() как раз и является системой логирования. Простой и очень эффективной. И легко переносимой между разными программами. Ну вот я его и использую. Причём везде, в том числе и в программах с GUI.
printf — всего лишь ф-ция вывода в терминал. И вы сами написали что матлаб обламывает с такой отладкой. Более менее простую систему логирования можно посмотреть на qDebug в QT.
3. Может. Вот только я не вижу места где бы я мог его вызвать. У меня есть код DLL на С++, есть S-Function которая вставляется в схему Simulink. А вот отдельного m-файла нет. И вроде бы он не предполагается. Я не прав?
А вы не могли бы показать код S-Function. Кстати, статье как раз кода оч не хватает…dsmv2014 Автор
07.10.2019 14:45Это очень хорошо, то вот что делать когда matlab поменяет API, будет очень неприятно остаться без поддержки
Это общая проблема работы с Open Source — всё на свой страх и риск.
Интересное мнение. А какие вы нашли у него преимущества по сравнению с другими фреймворками для тестирования? Хотя бы по сравнению с Google Test и Ctest+Cmake…
Если сравнивать с Google Test и другими системами unit тестирования то Simulink конечно другой. В более общем смысле — это система тестирования и разработки чего-то. Например алгоритмов, или других вещей. И да, возможность создать тесты и провести регрессионное тестирование там тоже есть.
А вы не могли бы показать код S-Function. Кстати, статье как раз кода оч не хватает…
Так его то и нет. Есть код DLL: https://github.com/dsmv/simulink_sm/blob/master/simulink_sm/src/mex/sm_adc.cpp
lingvo
07.10.2019 13:02ИМХО лучше вместо USB использовать Ethernet. В Симулинке для этого есть стандартные блоки, типа UDP, не надо возиться с DLL-ками и еще меньше мороки с отладкой, так как трафик можно смотреть прямо в Wireshark. Вы можете повесить сколько угодно плат без проблем с конфигурацией. Выше уже подсказали лайвфак с локальными сокетами, но с ПЛИС это можно сделать напрямую.
Еще проблема данного подхода в том, что у вас генератор->АЦП синхронизируется самостоятельно. А в реальной жизни генератор может быть отдельно, а АЦП отдельно и запуск надо синхронизировать через ПК — а тут непредвиденные задержки начнут мешать.
dsmv2014 Автор
07.10.2019 13:39Ethernet сразу ограничивает скорость обмена. А главное — накладывает ограничения на выбор аппаратуры. Предложенный подход не накладывает ограничений на интерфейс связи. USB взят исключительно для примера, что бы удобнее было подключиться к ноутбуку. А так конечно напрашивается применение модулей на основе PCI Express.
По поводу синхронизации — в данном примере АЦП стартует по фронту сигнала «START», этот сигнал формируется генератором. Но разумеется вместо генератора может быть и другой источник.
С точки зрения Simulink непредвиденные задержки на ПК совершенно не мешают. Он просто ждёт когда сигнал старта пройдёт через sm_adc и вернётся обратно. Это будет всё тот же момент модельного времени.lingvo
07.10.2019 13:56Ethernet сразу ограничивает скорость обмена. А главное — накладывает ограничения на выбор аппаратуры. Предложенный подход не накладывает ограничений на интерфейс связи. USB взят исключительно для примера, что бы удобнее было подключиться к ноутбуку. А так конечно напрашивается применение модулей на основе PCI Express
PCIexpress требователен по физическому интерфейсу — карта должна либо стоять прямо в в материнке, а всякие iPass с оптикой не очень хорошо дружат. А с Ethernet — у вас на плате SFP слот — туда можно все что угодно впихнуть — от меди и до оптики на 10км. По скоростям, да PCIe еще выигрывает за счет количества линий, но у вас обработка в компьютере все равно будет медленней, чем пропускная способность канала, так что выше все равно не надо.
ПС. Мы протестировали Ethernet 10Гбит и серьезно думаем перелезть с PCIe Gen2 на Ethernet для связи ПЛИС<->PC. Получается гораздо проще в разработке и сопровождении.
dsmv2014 Автор
07.10.2019 14:12Плата с PCI Express не обязательно должна стоять в компьютере, мы активно используем внешние модули на PCI Express. Есть стандарт для медного кабеля, есть и оптические удлинители.
Для ускорения обработки данных в компьютере есть различные способы, включая видеокарты, ПЛИС, сигнальные процессоры. Ну и от самого алгоритма обработки тоже зависит. Например я умею проверять 64-х битный счётчик на скорости 11 Гбайт/с.
Решение с вводом данных в Simulink через Ethernet является альтернативным подходом. Оно вас устраивает — и это хорошо. В статье приведён другой, более мощный подход. Вот он устраивает меня.
Brak0del
07.10.2019 15:09Если не ошибаюсь, то Artix-ы, используемые в статье, 10Гбит Ethernet не умеют, только гиг.
dsmv2014 Автор
07.10.2019 15:20Теоретически есть возможность подключения. Надо использовать внешний преобразователь из 4x3.125 Гбит/с в 10 Гбит/с. Но для 10G Ethernet своих сложностей хватает. У меня вот сейчас есть устойчивое соединение с 10G коммутатором, а вот с сетевой платой Intel — не получается. И не хватает времени разобраться.
Brak0del
07.10.2019 15:27Надо использовать внешний преобразователь из 4x3.125 Гбит/с в 10 Гбит/с.
Вас понял, благодарю.
Pyhesty
такой, вопрос, какая достижима производительность, есть ли оповещение при пропуске отсчетов. Интересует производительность десятки и сотни мегабайт в секунду (поток видеокадров)? Возможна ли синхронизация потока, по началу кадра или строки?
ps: у вас кажется были универсальные платы PCI-E, можно ли такой же фокус провернуть с ними? то есть захватить большой поток с PCI-E сразу в матлаб?
pss: к сожалению, обычно приходится отдельно захватывать данные и загружать в матлаб ( что очень не производительно, а современные потоки доходят до 10-40Гбит в секунду…
dsmv2014 Автор
Здесь главный вопрос — режим захвата однократный или непрерывный?
Если однократный — то определяется только возможностями аппаратуры по скорости регистрации сигнала. Если регистрировать в память при ПЛИС — 8-12 Гбайт/с. Если регистрировать в память компьютера, то зависит от интерфейса связи. Для USB 3.0 это 300 Мбайт/с. На PCI-Express до 13 Гбайт/с.
А если интересует непрерывный режим — то тогда уже надо учитывать скорость обработки в Matlab. Надо что он успел обработать блок данных до прихода следующего.
По такой технологии можно обеспечить скорость передачи в Matlab до 13 Гбайт/с.
У нас сейчас нет готового решения для захвата видеопотока, но я готов обсудить такую задачу. Сделать можно.
Pyhesty
Спасибо за ответ.
Режимы как однократные (большие потоки ограниченные памятью ЭВМ,), так и непрерывные (скорость соответствует скорости обработки или регистрации).
Приятно, что достижимая скорость соответствует пропускной PCIE.
Бывает, возникают задачи принять скоростной поток по оптике, смотрим на ваши платы… но опыта и знаний по ним не хватает и берем какой-нибудь CameraLinkHS (максимальная пропускная способность 2.6Гбайта на слот).
Мы на текущий момент используем следующий лайв-хак: захватываем данные своим ПО и сразу же перекладываем на локальный (127.0.0.1) сокет IP, а далее вычитываем матлабом из сокета. Но в такой реализации есть ограничение на максимальный поток(сотни мегабайт в секунду, точно не помню)
Еще раз спасибо за статью, будем иметь ввиду.