![](https://habrastorage.org/getpro/habr/upload_files/3a6/971/db9/3a6971db90bc45465605eaf17f9d862f.jpg)
Предположим, существует некий проект, где перед двумя разработчиками стоит задача расчёта/сбора каких-либо данных, а также их грамотной визуализации. При этом, один из разработчиков хорошо разбирается в матанализе или физике и имеет представление о том, как эта задача может решаться, а также дружит с MATLAB. Другой же разработчик, напротив, знает, как правильно интерпретировать набор данных и представить наглядный анимированный график, а также дружит с LabVIEW. Для подобных задач существует инструмент «Interface for MATLAB» в LabVIEW NXG, который позволяет обращаться к синтаксису MATLAB и совмещать преимущества графического и текстового языков программирования. Именно этот инструмент будет рассмотрен в данной статье.
![Рис. 1 – Пример непрерывного вывода данных на экран Рис. 1 – Пример непрерывного вывода данных на экран](https://habrastorage.org/getpro/habr/upload_files/3b5/f28/64b/3b5f2864b356b922fdd771e8996428e3.gif)
Статья расчитана на тех, кто на базовом уровне знаком с пакетами MATLAB и LabVIEW. Показанные примеры воспроизводились на версиях MATLAB R2020b и LabVIEW NXG 5.10 Community. Поставленная задача и методы её решения имеют показательный характер, основной упор делается на демонстрации возможности использования синтаксиса MATLAB при создании проектов LabVIEW.
Статья будет разделена на следующие части:
-
Постановка задачи.
-
Решение задачи с помощью MATLAB.
-
Интеграция кода MATLAB в LabVIEW NXG на примере поставленной задачи.
-
Решение задачи с помощью MATLAB и LabVIEW NXG.
-
Заключение.
1. Постановка задачи
В качестве примера будет численно решаться система уравнений Лоренца, а полученное решение будет воспроизводиться похожим образом, как это продемонстрировано на рис. 1.
Система Лоренца представляет из себя три дифференциальных уравнения:
где x, y, z – искомые переменные; t – время; σ, r, β – параметры, которые, как правило, задаются в виде чисел и не меняются в ходе решения.
Тем, кто не особо хорошо знаком с дифференциальными уравнениями, не стоит пугаться, потому что данная система решается численно множеством способов. Один из самых простых способов — метод Эйлера, представленный ниже:
где Δ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 – вектор-строка 1×3 из параметров σ, 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 можно вызывать только те функции (не считая базовых или библиотечных), которые находятся в одной папке со скриптом, поэтому создаём следующий скрипт в той же папке, что и наша написанная функция:
![](https://habrastorage.org/getpro/habr/upload_files/e09/4b9/c37/e094b9c37b7e053e2a9a0f936cffb0bc.png)
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
Скрипт выдаёт нам следующий результат:
![](https://habrastorage.org/getpro/habr/upload_files/981/003/cd0/981003cd0eb5b97e11ed0931550e26a8.png)
Мы видим, что к нашим начальным условиям добавились вычисленные функцией значения, поэтому можем считать, что скрипт и функция работают правильно, и двигаться дальше. Теперь осталось дописать скрипт, чтобы при запуске воспроизводилась анимация, и на этом, можно сказать, поставленная задача полностью решена:
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
Результатом будет являться следующая анимация:
![](https://habrastorage.org/getpro/habr/upload_files/ebe/d8f/10d/ebed8f10d6fc27af2b6bc319db9eadfb.gif)
3. Интеграция кода MATLAB в LabVIEW NXG на примере поставленной задачи
Открываем LabVIEW NXG и создаём новый проект VI:
![](https://habrastorage.org/getpro/habr/upload_files/2ac/2e0/375/2ac2e0375515c6544415680684895bad.png)
Сохраняем проект. В данном случае будет неважно место сохранения, путь к файлу MATLAB мы будем задавать вручную далее:
![](https://habrastorage.org/getpro/habr/upload_files/3f6/c85/211/3f6c852118792ef10e8ddc26b8305635.png)
Создаём Interface for MATLAB:
![](https://habrastorage.org/getpro/habr/upload_files/b9f/68a/92a/b9f68a92a13e32e5c57f6202710f3e20.png)
Справа, на вкладке Document выбираем тип файла function:
![](https://habrastorage.org/getpro/habr/upload_files/24d/288/ed4/24d288ed4a523d825ef1293a0e83bd2a.png)
В главной рабочей области указываем путь к нашему файлу function (.m):
![](https://habrastorage.org/getpro/habr/upload_files/377/05d/8ca/37705d8caff5becc1a650715a3aac9d1.png)
Нажимаем Add interface node. Перед нами появляется область, которую требуется заполнить входными и выходными параметрами точно в таком порядке, как они заданы в самом файле function (.m). Начнём с создания входного вектора параметров par, нажав Add parameter:
![](https://habrastorage.org/getpro/habr/upload_files/f7c/d4a/422/f7cd4a422dd8e62f976df49105860a6a.png)
Как видно, нам потребовалось указать Array в графе Shape, By row в графе Orientation и Input в окне Behavior. Разумееся, что это справедливо для par – входного вектора-строки 1×3, следующий параметр dt будем обычным скаляром (переменной):
![](https://habrastorage.org/getpro/habr/upload_files/fea/ce4/c25/feace4c25a76e6eb33c42c6c03362341.png)
Хочу обратить внимание, что в столбце Prototype показан пример функции MATLAB, которую мы хотим создать. Желательно регулярно сверяться с тем, что написано в этом столбце при добавлении и настройке входных/выходных параметров. Добавим остальные входные параметры:
![](https://habrastorage.org/getpro/habr/upload_files/e5e/bcd/2d1/e5ebcd2d1c8b0ce0ad8168edcb351907.png)
Обращаю внимание, что входные X, Y, Z, T – векторы-строки, а ms – скаляр. Теперь добавим выходные X, Y, Z, T, которые также будут векторами-строками:
![](https://habrastorage.org/getpro/habr/upload_files/e1c/4bc/382/e1c4bc382c7dd03e8aacf08380abbc59.png)
Теперь LabVIEW полностью готов работать с нашим MATLAB файлом. Сохраняем проделанную работу сочетанием CTRL+SHIFT+S, переходим в рабочее пространство VI в блок Diagram и находим нашего FLorenz’a в палитре Project Items:
![](https://habrastorage.org/getpro/habr/upload_files/0ac/edd/f48/0aceddf48730b1541b9a99e7b2740029.png)
Видим, что у нашего элемента FLorenz имеется 7 входных и 4 выходных терминала, остаётся только правильно их подключить, что будет показано в следующей части:
![](https://habrastorage.org/getpro/habr/upload_files/a62/cbb/98d/a62cbb98dd0bbea991162823e96e1d38.png)
4. Решение задачи с помощью MATLAB и LabVIEW NXG
Добавим цикл while:
![](https://habrastorage.org/getpro/habr/upload_files/cd5/42d/5ad/cd542d5ad6c90a35019d88a9e747770b.png)
Добавим требуемые Numeric Control и график на переднюю панель:
![](https://habrastorage.org/getpro/habr/upload_files/0c8/07f/52b/0c807f52b1022462fcccd720e3fcdc2e.png)
Соединим входные терминалы с созданными Numeric Control. Следует обратить внимание, что входные скаляры X, Y, Z, T мы должны преобразовать в массив 1×1 с помощью Build Array:
![](https://habrastorage.org/getpro/habr/upload_files/962/ae9/021/962ae90217928ace3996da8a4c6cb2a3.png)
Нажимаем на все входные Tunnel и преобразуем их в Shift Register, попутно добавляя их с правого (выходного) края цикла while:
![](https://habrastorage.org/getpro/habr/upload_files/881/20e/244/88120e244a52fd84c97882f8f30ecff7.png)
![](https://habrastorage.org/getpro/habr/upload_files/e90/73f/ec2/e9073fec2a1cde862f33ddb73f68bebd.png)
Подключаем выходные X, Y, Z, T к выходным Shift Register:
![](https://habrastorage.org/getpro/habr/upload_files/425/2a6/dc9/4252a6dc979058da3a4e003d02ccadb6.png)
Объединяем данные с X и T в кластер и подключаем его к графику, тем самым завершая работу с блок-диаграммой:
![](https://habrastorage.org/getpro/habr/upload_files/1b3/84f/988/1b384f9882eceb8fff20b4134a085601.png)
![](https://habrastorage.org/getpro/habr/upload_files/640/882/d32/640882d32cdcabe2c015bdb6c35ebe92.png)
Заполним входные данные:
![](https://habrastorage.org/getpro/habr/upload_files/157/32b/e11/15732be11c9550a337530811e53b6329.png)
В итоге получаем следующий результат:
![](https://habrastorage.org/getpro/habr/upload_files/ade/1ea/230/ade1ea230db1e862f00a9a50874c8e11.gif)
5. Заключение
В стаье был рассмотрен способ интеграции кода MATLAB в проект LabVIEW на примере задачи о численном решении уравнений Лоренца методом Эйлера. Для получения большей информации советую ознакомиться со следующими источниками:
ссылка на оригинал статьи https://habr.com/ru/articles/574606/
Добавить комментарий