Описание пользователя
Глава 3. Использование стандартных модулей автокомпиляции
§3.6. Принципы создания автокомпилируемых моделей блоков
§3.6.3. Работа с динамическими переменными
§3.6.3.3. Динамические переменные сложных типов
Рассматривается работа с динамическими переменными сложных типов – структурами, матрицами и т.п.
В примерах в §3.6.3.1 и §3.6.3.2 модели блоков работали с простыми динамическими переменными вещественного типа double. Динамическая переменная может быть любого типа, допустимого в RDS: структурой, матрицей, матрицей структур и т.п. В автокомпилируемых моделях обращение к таким сложным переменным производится по стандартным для языка C правилам: индексы массивов записываются в квадратных скобках, имена полей структур отделяются от имен самих переменных точкой. Фактически, во фрагментах программ, вводимых пользователем в редактор модели, обращение к динамической переменной ничем не отличается от обращения к статической.
В §3.6.3.2 были рассмотрены блоки, обеспечивающие схему значением температуры окружающей среды, которая передавалась через вещественную динамическую переменную «AmbientTemperature». Пусть блокам в этой схеме нужна не только температура среды, но и влажность и атмосферное давление. Можно было бы завести еще пару вещественных динамических переменных и записывать эти значения в них, но при этом в блоках, присваивающих значения переменным, потребовалось бы три вызова функции NotifySubscribers для уведомления остальных блоков об изменении значения – по одному вызову для каждой переменной. Вероятнее всего, все три этих значения будут изменяться одновременно, в момент считывания параметров окружающей среды или расчета динамики их изменения каким-либо блоком. Удобнее будет создать структуру, полями которой будут температура, влажность и давление, и динамическую переменную такого типа. Блок, вычисливший или получивший новые параметры окружающей среды, будет записывать их в поля структуры и делать единственный вызов NotifySubscribers.
Назовем структуру, в которой буду храниться параметры среды, «Ambience», а ее поля для температуры, влажности и давления – «Temperature», «Humidity» и «Pressure» соответственно. Для добавления в RDS этой структуры нужно выполнить следующие шаги:
- в режиме редактирования (должна быть загружена какая-либо схема или создана новая) выбрать пункт главного меню «» – откроется окно со списком уже имеющихся в RDS структур;
- ввести в окне редактирования имя типа структуры «Ambience» и заполнить список полей согласно рис. 398;
- закрыть окно редактирования структуры кнопкой «».
Рис. 398. Структура «Ambience» в окне редактирования структуры
Как и в примере из §3.6.3.2, создадим блоки с автокомпилируемыми моделями, одна из которых будет создавать динамическую структуру типа «Ambience» и записывать в ее поля значения входов блока, а другая – считывать поля структуры и выдавать их на свои выходы. Динамическую переменную назовем точно так же, как и тип структуры – «Ambience».
Начнем с блока, записывающего свои входы в динамическую переменную. У него будет три входа: «H» – для влажности, «T» – для температуры, и «P» – для давления. Структура его переменных будет такой:
| Имя | Тип | Вход/выход | Пуск | Начальное значение |
|---|---|---|---|---|
| Start | Сигнал | Вход | ✓ | 1 |
| Ready | Сигнал | Выход | 0 | |
| H | double | Вход | ✓ | 0 |
| T | double | Вход | ✓ | 0 |
| P | double | Вход | ✓ | 0 |
Модель блока будет запускаться при самом первом запуске расчета (у сигнала «Start» единичное начальное значение) и при поступлении нового значения на входы «H», «T» и «P» (у них установлен флажок «»). Создадим новый блок с автокомпилируемой моделью, зададим для него запуск по сигналу и введем в редакторе модели его структуру переменных. Чтобы наш блок создавал динамическую структуру, выполним следующие шаги:
- на вкладке «» левой панели редактора модели в нижней ее части (см. рис. 337) нажмем кнопку со знаком «»;
- в открывшемся окне добавления динамической переменной установим флажок «»;
- в поле «» выберем вариант «» и введем имя создаваемой переменной – «Ambience»;
- при переходе в поле «» в нем появится то же самое имя, его можно оставить без изменения (в программе для обращения к нашей переменной мы тоже будем использовать имя Ambience);
- в выпадающем списке «» выберем «подсистема (RDS_DVPARENT)» – мы создаем переменную в одной подсистеме с блоком;
- в выпадающем списке «» выберем «создать»;
- в выпадающем списке «» выберем «Ambience» – наша переменная будет структурой этого типа (то, что имя типа структуры совпадает с именем переменной, не важно, имя типа структуры RDS не используется в программе и, поэтому, не вызовет конфликта идентификаторов);
- закроем окно добавления переменной кнопкой «».
На вкладке «» окна редактора введем следующий текст:
// Запись входов в поля структуры Ambience.Temperature=T; Ambience.Humidity=H; Ambience.Pressure=P; // Уведомление подписчиков об изменении данных Ambience.NotifySubscribers();
Здесь мы по очереди записываем в поля структуры входы блока, соответствующие этим полям по смыслу – имя поля (например, Humidity) отделяется от имени переменной (Ambience) точкой. В последней строчке программы мы, как и в предыдущих примерах, вызываем у динамической переменной функцию-член NotifySubscribers, которая уведомляет все блоки, подписавшиеся на эту переменную, о том, что мы записали в нее новые значения (при этом в моделях этих блоков вызывается реакция на изменение динамической переменной).
Теперь займемся блоком, который будет выдавать значения полей динамической структуры на выходы. Назовем выходы блока так же, как и поля структуры: «Temperature» (температура), «Humidity» (влажность) и «Pressure» (давление):
| Имя | Тип | Вход/выход | Пуск | Начальное значение |
|---|---|---|---|---|
| Start | Сигнал | Вход | ✓ | 1 |
| Ready | Сигнал | Выход | 0 | |
| Temperature | double | Выход | 0 | |
| Humidity | double | Выход | 0 | |
| Pressure | double | Выход | 0 |
Создадим новый блок с автокомпилируемой моделью, зададим для него запуск по сигналу, введем в модель приведенную выше структуру переменных и добавим подписку на переменную «Ambience». Для этого:
- на вкладке «» левой панели редактора модели в нижней ее части нажмем кнопку со знаком «»;
- в открывшемся окне добавления динамической переменной установим флажок «»;
- в поле «» выберем вариант «» и введем имя переменной «Ambience»;
- при переходе в поле «» в нем появится то же самое имя – его можно оставить без изменения;
- в выпадающем списке «» выберем «подсистема (RDS_DVPARENT)», чтобы поиск переменной начинался в родительской подсистеме блока;
- в выпадающем списке «» выберем «найти и подписаться», чтобы, если переменная будет отсутствовать в родительской подсистеме, поиск продолжился вверх по иерархии;
- в выпадающем списке «» выберем «Ambience» – мы подписываемся на структуру такого типа;
- закроем окно добавления переменной кнопкой «».
На вкладке «» редактора мы не будем ничего вводить – наша модель не выполняет вычислений в такте расчета. Вместо этого мы добавим в нее реакцию на изменение динамической переменной, в которую введем следующий текст программы:
// Запись полей структуры в выходы Temperature=Ambience.Temperature; Humidity=Ambience.Humidity; Pressure=Ambience.Pressure; Ready=1; // Выходные связи должны сработать
В этой реакции мы переписываем значения из полей динамической переменной Ambience в соответствующие этим полям выходы блока и взводим сигнал Ready, чтобы выходные связи блока сработали в следующем такте расчета.
Для проверки этих моделей соберем схему, изображенную на рис. 399. В этой схеме слева расположен блок с моделью, записывающий входы в динамическую структуру, а справа – блок, подающий поля этой структуры на выходы. Запустив расчет и изменяя значения в полях ввода левого блока, можно увидеть, что значения на индикаторах правого блока изменяются синхронно.
Рис. 399. Тестирование блоков, работающих с динамической структурой
В рассмотренном примере у нас было три отдельных вещественных входа, которые мы записывали в поля структуры, и три отдельных вещественных выхода, на которые мы подавали эти же поля в другом блоке. Это позволило показать, как в тексте программы осуществляется обращение к отдельным полям сложной динамической переменой, но, в данном простом примере, такое решение не оптимально. Если бы мы сделали у левого блока вход типа «Ambience», а у правого – выход того же типа, в каждой из моделей можно было бы обойтись одним единственным оператором присваивания. Пусть вход левого блока называется «X», а выход правого – «Y», оба они – структуры типа «Ambience». В этом случае модель левого блока выглядела бы так:
// Копирование структуры-входа в динамическую структуру Ambience=X; // Уведомление подписчиков об изменении данных Ambience.NotifySubscribers();
Модель правого блока содержала бы обратный оператор присваивания:
// Копирование динамической структуры в выход Y=Ambience; Ready=1; // Выходные связи должны сработать
В объектах, создаваемых модулем автокомпиляции для доступа к статическим и динамическим переменным, переопределен оператор присваивания, поэтому приведенная выше запись допустима. В схеме с новой моделью поля ввода и индикаторы нужно было бы подключать уже не к отдельным входам и выходам, а к полям переменных «X» и «Y» (рис. 400).
Рис. 400. Блоки, работающие с динамической структурой,
входы и выходы которых – тоже структуры
Работа с динамическими массивами, матрицами и строками производится аналогичным образом: все операторы, применяемые к статическим переменным этих типов, могут применяться и к динамическим. Например, если DynArray – динамический массив, то к его i-му элементу можно обратиться оператором «DynArray[i]». Функции NotifySubscribers, GetLink и CheckLink при этом всегда применяются к самой динамической переменной, а не к ее отдельным элементам: например, для динамического массива DynArray нужно записывать DynArray.NotifySubscribers().