Текущий раздел:

Описания RDS

Описание пользователя

Глава 3. Использование стандартных модулей автокомпиляции

§3.6. Принципы создания автокомпилируемых моделей блоков

§3.6.3. Работа с динамическими переменными

§3.6.3.3. Динамические переменные сложных типов

# Описание пользователя

## Глава 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;
- закрыть окно редактирования структуры кнопкой «OK».

Рис. 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) нажмем кнопку со знаком «+»;
- в открывшемся окне добавления динамической переменной установим флажок «произвольная переменная»;
- в поле «имя переменной в RDS» выберем вариант «фиксированное имя» и введем имя создаваемой переменной – «Ambience»;
- при переходе в поле «имя переменной в программе» в нем появится то же самое имя, его можно оставить без изменения (в программе для обращения к нашей переменной мы тоже будем использовать имя Ambience);
- в выпадающем списке «блок-владелец» выберем «подсистема (RDS_DVPARENT)» – мы создаем переменную в одной подсистеме с блоком;
- в выпадающем списке «действие» выберем «создать»;
- в выпадающем списке «тип» выберем «Ambience» – наша переменная будет структурой этого типа (то, что имя типа структуры совпадает с именем переменной, не важно, имя типа структуры RDS не используется в программе и, поэтому, не вызовет конфликта идентификаторов);
- закроем окно добавления переменной кнопкой «OK».

На вкладке «модель» окна редактора введем следующий текст:

      // Запись входов в поля структуры
      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». Для этого:

- на вкладке «переменные» левой панели редактора модели в нижней ее части нажмем кнопку со знаком «+»;
- в открывшемся окне добавления динамической переменной установим флажок «произвольная переменная»;
- в поле «имя переменной в RDS» выберем вариант «фиксированное имя» и введем имя переменной «Ambience»;
- при переходе в поле «имя переменной в программе» в нем появится то же самое имя – его можно оставить без изменения;
- в выпадающем списке «блок-владелец» выберем «подсистема (RDS_DVPARENT)», чтобы поиск переменной начинался в родительской подсистеме блока;
- в выпадающем списке «действие» выберем «найти и подписаться», чтобы, если переменная будет отсутствовать в родительской подсистеме, поиск продолжился вверх по иерархии;
- в выпадающем списке «тип» выберем «Ambience» – мы подписываемся на структуру такого типа;
- закроем окно добавления переменной кнопкой «OK».

На вкладке «модель» редактора мы не будем ничего вводить – наша модель не выполняет вычислений в такте расчета. Вместо этого мы добавим в нее реакцию на изменение динамической переменной, в которую введем следующий текст программы:

      // Запись полей структуры в выходы
      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().