Использование кода MATLAB в проектах LabVIEW NXG

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Предположим, существует некий проект, где перед двумя разработчиками стоит задача расчёта/сбора каких-либо данных, а также их грамотной визуализации. При этом, один из разработчиков хорошо разбирается в матанализе или физике и имеет представление о том, как эта задача может решаться, а также дружит с MATLAB. Другой же разработчик, напротив, знает, как правильно интерпретировать набор данных и представить наглядный анимированный график, а также дружит с LabVIEW. Для подобных задач существует инструмент "Interface for MATLAB" в LabVIEW NXG, который позволяет обращаться к синтаксису MATLAB и совмещать преимущества графического и текстового языков программирования. Именно этот инструмент будет рассмотрен в данной статье.

Рис. 1 – Пример непрерывного вывода данных на экран
Рис. 1 – Пример непрерывного вывода данных на экран

Статья расчитана на тех, кто на базовом уровне знаком с пакетами MATLAB и LabVIEW. Показанные примеры воспроизводились на версиях MATLAB R2020b и LabVIEW NXG 5.10 Community. Поставленная задача и методы её решения имеют показательный характер, основной упор делается на демонстрации возможности использования синтаксиса MATLAB при создании проектов LabVIEW.

Статья будет разделена на следующие части:

  1. Постановка задачи.

  2. Решение задачи с помощью MATLAB.

  3. Интеграция кода MATLAB в LabVIEW NXG на примере поставленной задачи.

  4. Решение задачи с помощью MATLAB и LabVIEW NXG.

  5. Заключение.

1. Постановка задачи

В качестве примера будет численно решаться система уравнений Лоренца, а полученное решение будет воспроизводиться похожим образом, как это продемонстрировано на рис. 1.

Система Лоренца представляет из себя три дифференциальных уравнения:

\begin{equation*} \begin{cases}     \frac{dx}{dt}=\sigma y-\sigma x  \\   \frac{dy}{dt}=rx-xz-y  \\  \frac{dz}{dt} =xy-\beta z   \end{cases}  \end{equation*},

где x, y, z – искомые переменные; t – время; σ, r, β – параметры, которые, как правило, задаются в виде чисел и не меняются в ходе решения.

Тем, кто не особо хорошо знаком с дифференциальными уравнениями, не стоит пугаться, потому что данная система решается численно множеством способов. Один из самых простых способов - метод Эйлера, представленный ниже:

\begin{equation*} \begin{cases}     x_{i+1}=x_{i}+\Delta t (\sigma y_{i}-\sigma x_{i})  \\   y_{i+1}=y_{i}+\Delta t (rx_{i}-x_{i}z_{i}-y_{i})  \\  {z}_{i+1} =z_{i}+\Delta t (x_{i}y_{i}-\beta z_{i})  \\  t_{i+1}=t_{i}+\Delta t   \end{cases}  \end{equation*},

где Δt – шаг по времени, с которым производится расчёт, чем он меньше, тем "точнее" вычисление; i = 1, 2, 3, ... – порядковый номер.

Иными словами, процедура, описанная выше, имеет следующий смысл: для нахождения каждого последующего значения искомой переменной xi+1 требуется к предыдущему значению xi добавить правую часть дифференциального уравнения, умноженную на заданный шаг по времени Δt.

Таким образом, для данной задачи у нас будут следующие входные данные:

  • Начальные условия: xi, yi, zi, ti,

  • Параметры: σ, r, β,

  • Шаг интегрирования: Δt.

Выходными же данными будут: xi+1, yi+1, zi+1, ti+1. Стоит также отметить, что найденные выходные данные будут служить входными начальными условиями для следующей итерации. Все найденные значения x, y, z должны либо сохраняться в памяти, для последующей обработки, либо сразу выводиться на график, динамично удаляя ненужные "хвосты".

2. Решение задачи с помощью MATLAB

Для начала создадим подпрограмму вида function, которая будет производить основные вычисления и которую мы будем использовать далее с помощью LabVIEW. Начнём с входных и выходных параметров, а также с имени функции:

function [X_out,Y_out,Z_out,T_out]=FLorenz(par,dt,X_in,Y_in,Z_in,T_in)

end

В данном случае "FLorenz" – имя функции; par – вектор-строка 1x3 из параметров σ, r, β; dt – шаг интегрирования Δt; X_in, Y_in, Z_in, T_in – векторы-строки входных данных; X_out, Y_out, Z_out, T_out – векторы-строки выходных данных. Далее напишем тело программы, выполняющее вычисления в соответствии с тем, что было описано в первом пункте:

function [X_out,Y_out,Z_out,T_out]=FLorenz(par,dt,X_in,Y_in,Z_in,T_in)

dx=dt*(par(1)*Y_in(end)-par(1)*X_in(end)); %Нахождение приращения X
dy=dt*(par(2)*X_in(end)-X_in(end)*Z_in(end)-Y_in(end)); %Нахождение приращения Y
dz=dt*(X_in(end)*Y_in(end)-par(3)*Z_in(end)); %Нахождение приращения Z

X_out=[X_in,X_in(end)+dx]; %Добавление найденной координаты X
Y_out=[Y_in,Y_in(end)+dy]; %Добавление найденной координаты Y
Z_out=[Z_in,Z_in(end)+dz]; %Добавление найденной координаты Z
T_out=[T_in,T_in(end)+dt]; %Добавление элемента времени T

end

Далее добавим логической условие, которое будет контролировать размер вычисленных данных и удалять ненужные элементы. Для этого нам понадобится добавить входную переменную ms к остальным входным данным:

function [X_out,Y_out,Z_out,T_out]=FLorenz(par,dt,X_in,Y_in,Z_in,T_in,ms)

dx=dt*(par(1)*Y_in(end)-par(1)*X_in(end)); %Нахождение приращения X
dy=dt*(par(2)*X_in(end)-X_in(end)*Z_in(end)-Y_in(end)); %Нахождение приращения Y
dz=dt*(X_in(end)*Y_in(end)-par(3)*Z_in(end)); %Нахождение приращения Z

X_out=[X_in,X_in(end)+dx]; %Добавление найденной координаты X
Y_out=[Y_in,Y_in(end)+dy]; %Добавление найденной координаты Y
Z_out=[Z_in,Z_in(end)+dz]; %Добавление найденной координаты Z
T_out=[T_in,T_in(end)+dt]; %Добавление элемента времени T

nowsize=length(T_out); %Нахождение размера массивов
if nowsize>ms                                  
    randot=nowsize-ms+1:nowsize; %Определение диапазона сохранения данных
    X_out=X_out(randot); %Сохранение X в рамках диапазона
    Y_out=Y_out(randot); %Сохранение Y в рамках диапазона
    Z_out=Z_out(randot); %Сохранение Z в рамках диапазона
    T_out=T_out(randot); %Сохранение T в рамках диапазона
end

end

На этом написание функции закончено. Разумеется, её можно дополнить и оптимизировать или заставить производить несколько итераций за один вызов, но в рамках показательного примера будет достаточно того, что изложено выше. Теперь напишем скрипт в котором будут численно определены все параметры и который будет ссылаться на нашу функцию. Важно отметить, что при стандартных настройках MATLAB можно вызывать только те функции (не считая базовых или библиотечных), которые находятся в одной папке со скриптом, поэтому создаём следующий скрипт в той же папке, что и наша написанная функция:

clear
clc

sigma=10; r=28; beta=8/3;   %Параметры системы
par=[sigma r beta];         %Объединение параметров в один вектор
x0=1; y0=1; z0=1;           %Начальные условия
t0=0; dt=0.005;             %Начальное время и шаг интегрирования
X=x0; Y=y0; Z=z0; T=t0;     %Создание векторов координат и времени
ms=4000;                    %Максимальное количество элементов

[X,Y,Z,T]=FLorenz(par,dt,X,Y,Z,T,ms); %Вызов ранее созданного файла function

Скрипт выдаёт нам следующий результат:

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

clear
clc

sigma=10; r=28; beta=8/3;   %Параметры системы
par=[sigma r beta];         %Объединение параметров в один вектор
x0=1; y0=1; z0=1;           %Начальные условия
t0=0; dt=0.005;             %Начальное время и шаг интегрирования
X=x0; Y=y0; Z=z0; T=t0;     %Создание векторов координат и времени
ms=4000;                    %Максимальное количество элементов

F=figure;                   %Создание окна figure
F.WindowState='maximized';  %Включение полноэкранного режима
P=plot(T,X,'linewidth',2);  %Создание графика с толщиной линии 2
grid on; grid minor;        %Создание сетки на графике
xlabel('Время, t');         %Создание подписи горизонтальной оси
ylabel('Координата, x(t)'); %Создание подписи вертикальной оси
ylim([-20 20]);             %Задание пределов по вертикальной оси
while isvalid(F) %Создание цикла, прекращающего работу в случае закрытия figure
    [X,Y,Z,T]=FLorenz(par,dt,X,Y,Z,T,ms); %Вызов ранее созданного файла function
    P.XData=T; P.YData=X;   %Обновление данных зависимости на графике
    xlim([T(1) T(end)]);    %Обновление пределов по горизонтальной оси
    drawnow limitrate;      %Ограничение количества обновлений figure
end

Результатом будет являться следующая анимация:

3. Интеграция кода MATLAB в LabVIEW NXG на примере поставленной задачи

Открываем LabVIEW NXG и создаём новый проект VI:

Сохраняем проект. В данном случае будет неважно место сохранения, путь к файлу MATLAB мы будем задавать вручную далее:

Создаём Interface for MATLAB:

Справа, на вкладке Document выбираем тип файла function:

В главной рабочей области указываем путь к нашему файлу function (.m):

Нажимаем Add interface node. Перед нами появляется область, которую требуется заполнить входными и выходными параметрами точно в таком порядке, как они заданы в самом файле function (.m). Начнём с создания входного вектора параметров par, нажав Add parameter:

Как видно, нам потребовалось указать Array в графе Shape, By row в графе Orientation и Input в окне Behavior. Разумееся, что это справедливо для par – входного вектора-строки 1x3, следующий параметр dt будем обычным скаляром (переменной):

Хочу обратить внимание, что в столбце Prototype показан пример функции MATLAB, которую мы хотим создать. Желательно регулярно сверяться с тем, что написано в этом столбце при добавлении и настройке входных/выходных параметров. Добавим остальные входные параметры:

Обращаю внимание, что входные X, Y, Z, T – векторы-строки, а ms – скаляр. Теперь добавим выходные X, Y, Z, T, которые также будут векторами-строками:

Теперь LabVIEW полностью готов работать с нашим MATLAB файлом. Сохраняем проделанную работу сочитанием CTRL+SHIFT+S, переходим в рабочее пространство VI в блок Diagram и находим нашего FLorenz'a в палитре Project Items:

Видим, что у нашего элемента FLorenz имеется 7 входных и 4 выходных терминала, остаётся только правильно их подключить, что будет показано в следующей части:

4. Решение задачи с помощью MATLAB и LabVIEW NXG

Добавим цикл while:

Добавим требуемые Numeric Control и график на переднюю панель:

Соединим входные терминалы с созданными Numeric Control. Следует обратить внимание, что входные скаляры X, Y, Z, T мы должны преобразовать в массив 1x1 с помощью Build Array:

Нажимаем на все входные Tunnel и преобразуем их в Shift Register, попутно добавляя их с правого (выходного) края цикла while:

Подключаем выходные X, Y, Z, T к выходным Shift Register:

Объединяем данные с X и T в кластер и подключаем его к графику, тем самым завершая работу с блок-диаграммой:

Заполним входные данные:

В итоге получаем следующий результат:

5. Заключение

В стаье был рассмотрен способ интеграции кода MATLAB в проект LabVIEW на примере задачи о численном решении уравнений Лоренца методом Эйлера. Для получения большей информации советую ознакомиться со следующими источниками:

  • https://www.ni.com/documentation/en/labview/latest/language-integration/calling-matlab-functions-scripts/

  • https://knowledge.ni.com/KnowledgeArticleDetails?id=kA03q000001DkT5CAK&l=ru-RU

  • https://www.ni.com/documentation/en/labview/latest/language-integration/debug-matlab-functions-scripts/

  • https://en.wikipedia.org/wiki/Lorenz_system

Источник: https://habr.com/ru/post/574606/


Интересные статьи

Интересные статьи

ApexWidget - это сниппет-менеджер и генератор кода. Полезен для автоматической генерации шаблонов кода и технической документации.
Актуальность Конечные автоматы (finite state machines, fsm) — штука полезная. Особенно они могут быть востребованы в средах, где в принципе нет развитой многозадачности (например, в Octa...
Мы продолжаем рассказывать о выпускных проектах слушателей наших образовательных проектов. В этом выпуске мы расскажем про три проекта по дисциплине «Разработка на С++» в Технопар...
Написанной мной инструмент командной строки Sloc Cloc and Code (scc), который теперь доработан и поддерживается многими отличными людьми, подсчитывает строки кода, комментарии и оценивает сложнос...
Здравствуйте. Не так давно Ericsson выпустил новую систему управления Ericsson Network Manager (ENM), которая уже успела появится у некоторых операторов сотовой связи. Было бы интересно разобрать...