Описание пользователя
Глава 3. Использование стандартных модулей автокомпиляции
§3.6. Принципы создания автокомпилируемых моделей блоков
§3.6.3. Работа с динамическими переменными
§3.6.3.2. Создание динамических переменных
Описывается создание динамической переменной, к которой смогут обращаться другие блоки, и присвоение ей значений.
В §3.6.3.1 рассмотрена модель блока, считывающего значение из динамической переменной, за создание и присвоение значений которой отвечает другой блок – стандартный блок-планировщик динамического расчета. Создадим теперь модель, которая сама будет создавать динамическую переменную, к которой будут обращаться другие блоки.
Пусть в создаваемой схеме необходимо моделировать какие-либо физические процессы, зависящие от температуры окружающей среды. Что это за процессы и как они будут моделироваться, в данном случае не важно – общие принципы моделирования любых процессов, протекающих во времени, описаны в §3.6.4. В такой схеме, вероятно, будет очень много блоков, которым для расчета необходимо значение этой температуры. Передавать его по связям не очень удобно – таких связей будет слишком много, и они покроют собой всю схему. Гораздо лучше сделать температуру окружающей среды динамической переменной, к которой, при необходимости, смогут подключаться блоки – точно так же блоки, которым требуется текущее значение системного времени, подключаются к динамической переменной «DynTime».
Дадим переменной, в которой будет храниться температура окружающей среды, имя «AmbientTemperature», и создадим блок с автокомпилируемой моделью, которая будет создавать эту переменную и записывать в нее значение своего входа «t». Структура переменных этого блока будет очень простой:
| Имя | Тип | Вход/выход | Пуск | Начальное значение |
|---|---|---|---|---|
| Start | Сигнал | Вход | ✓ | 1 |
| Ready | Сигнал | Выход | 0 | |
| t | double | Вход | ✓ | 0 |
Модель блока будет запускаться при самом первом запуске расчета (у сигнала «Start» единичное начальное значение) и при поступлении нового значения на вход «t» (у этого входа установлен флажок «»). Создадим новый блок с автокомпилируемой моделью, зададим для него запуск по сигналу и введем в редакторе модели указанную выше структуру переменных.
Теперь прикажем модели создавать в подсистеме, в которой находится ее блок, вещественную динамическую переменную с именем «AmbientTemperature». Можно было бы создать эту переменную сразу в корневой подсистеме, чтобы ее видели все блоки схемы, однако, лучше использовать для этого подсистему блока-создателя – в этом случае переменная будет видна только в этой подсистеме и всех вложенных в нее (см. §1.5), и, поэтому, в схеме можно будет разместить несколько подсистем с разными температурами, если это понадобится. Чтобы добавить в модель создание динамической переменной, следует выполнить следующие шаги:
- на вкладке «» левой панели редактора модели в нижней ее части (см. рис. 337) нажать кнопку со знаком «»;
- в открывшемся окне добавления динамической переменной (рис. 394) установить флажок «»;
- в поле «» выбрать вариант «» и ввести имя создаваемой переменной (в данном случае – «AmbientTemperature»);
- при переходе в поле «» в нем появится то же самое имя – его можно оставить без изменения, в программе для обращения к нашей переменной мы будем использовать это же имя AmbientTemperature;
- в выпадающем списке «» выбрать «подсистема (RDS_DVPARENT)» – мы создаем переменную в одной подсистеме с блоком;
- в выпадающем списке «» выбрать «создать»;
- в выпадающем списке «» оставить уже находящийся там вариант «double» – наша переменная будет вещественной;
- закрыть окно добавления переменной кнопкой «».
Рис. 394. Добавление создания переменной «AmbientTemperature» в блок
После всех этих действий в списке на нижней части вкладки «» должна появиться переменная «AmbientTemperature» со значком «+» в левой колонке (этот значок указывает на то, что мы создаем переменную, см. §3.5.3).
На вкладке «» в правой части окна редактора введем следующий текст:
AmbientTemperature=t; AmbientTemperature.NotifySubscribers();
В первой строчке программы мы записываем в динамическую переменную AmbientTemperature значение входа t, во второй – уведомляем все подписавшиеся на нее блоки об изменении переменной вызовом у объекта, связанного с этой переменной в нашей программе, функции-члена NotifySubscribers. На этом следует остановиться подробнее.
Событие изменения динамической переменной, на которое могут реагировать модели подключившихся к ней блоков, не возникает автоматически при присвоении этой переменной нового значения. Динамическая переменная – это, фактически, общая область памяти, разделяемая несколькими блоками, и запись данных в эту память не влечет за собой никаких дополнительных последствий. Блок, записавший что-то в динамическую переменную, должен явно сообщить об этом RDS, когда запись полностью завершена. В данном случае наша переменная имеет тип double, и мы присваиваем ей значение единственным оператором, поэтому запись начинается и кончается в одном и том же операторе. Если бы переменная была структурой или массивом, модель должна была бы сообщить RDS об изменении ее значения только после того, как все поля структуры или все элементы массива записаны (пример работы с динамической переменной сложного типа приведен в §3.6.3.3). По этой причине уведомление RDS об изменении переменной не встроено в операторы присваивания объектов, через которые осуществляется доступ к этим переменным из автокомпилируемых моделей: когда запись нового значения окончена, у объекта динамической переменной нужно вручную вызвать функцию NotifySubscribers. В этот момент во всех блоках, подписавшихся на эту переменную, возникнет событие изменения динамической переменной RDS_BFM_DYNVARCHANGE: управление будет последовательно передано всем моделям этих блоков, которые смогут считать новое значение и как-то его использовать.
Если все описанные выше операции сделаны правильно, окно редактора модели созданного блока должно выглядеть примерно так, как на рис. 395.
Рис. 395. Редактор модели блока задания температуры
Теперь у нас есть блок, создающий вещественную динамическую переменную «AmbientTemperature» и записывающий в нее значение своего входа при его изменении. Переменная будет создаваться и удаляться вместе с самим блоком – если просмотреть полный исходный текст программы, формируемый модулем автокомпиляции для этой модели (пункт меню «»), можно будет увидеть команды создания и удаления переменной в конструкторе и деструкторе класса блока соответственно. Проверить работу блока мы пока не можем – у нас нет блоков, считывающих значение переменной. Можно, конечно, воспользоваться стандартными библиотечными блоками работы с динамическими переменными, настроив их на работу с нашей, но мы поступим иначе: создадим еще одну модель, которая будет выдавать значение «AmbientTemperature» на выход блока «t». Это поможет проиллюстрировать подписку на нестандартную динамическую переменную – в §3.6.3.1 мы подключались к стандартной переменной «DynTime», и нам не приходилось настраивать параметры подписки.
Структура переменных блока, читающего динамическую переменную, будет такой:
| Имя | Тип | Вход/выход | Пуск | Начальное значение |
|---|---|---|---|---|
| Start | Сигнал | Вход | ✓ | 1 |
| Ready | Сигнал | Выход | 0 | |
| t | double | Выход | 0 |
Создадим новый блок с автокомпилируемой моделью, зададим для него запуск по сигналу, введем в модель эту структуру переменных и добавим в нее подписку на переменную «AmbientTemperature». Для этого следует:
- на вкладке «» левой панели редактора модели в нижней ее части нажать кнопку со знаком «»;
- в открывшемся окне добавления динамической переменной (рис. 396) установить флажок «»;
- в поле «» выбрать вариант «» и ввести имя переменной, на которую мы подписываемся, то есть «AmbientTemperature» – оно должно точно совпадать с именем, которое мы вводили в предыдущем блоке при создании переменной;
- при переходе в поле «» в нем появится то же самое имя – его можно оставить без изменения;
- в выпадающем списке «» выбрать «подсистема (RDS_DVPARENT)», чтобы поиск переменной начинался в родительской подсистеме блока;
- в выпадающем списке «» выбрать «найти и подписаться», чтобы, если переменная будет отсутствовать в родительской подсистеме, поиск продолжился вверх по иерархии;
- в выпадающем списке «» оставить уже находящийся там вариант «double» – у нас вещественная переменная;
- закрыть окно добавления переменной кнопкой «».
Рис. 396. Добавление подписки на переменную «AmbientTemperature» в блок
Вкладку «» редактора мы оставим пустой – наша модель не будет ничего вычислять в такте расчета. Вместо этого мы добавим в нее реакцию на изменение динамической переменной. Для этого:
- на левой панели редактора выберем вкладку события (см. рис. 339), раскроем знаком «» группу «моделирование и режимы» и дважды щелкнем на ее последнем подпункте «изменение динамической переменной» – в правой части редактора появится новая вкладка «»;
- на этой вкладке введем следующий текст программы:
t=AmbientTemperature; Ready=1; // Выходные связи должны сработать
В этой реакции мы переписываем значение из AmbientTemperature в выход блока t и взводим сигнал Ready, чтобы выходные связи блока сработали в следующем такте расчета. Выход Ready, разрешающий передачу данных выходов блока по связям, автоматически взводится только перед вызовом реакции на такт расчета, поэтому в любых других реакциях, где мы изменяем выходы блока, мы должны вручную присвоить ему единицу (после передачи данных он автоматически сбрасывается обратно в ноль). На самом деле, в данном случае модель работала бы, даже если бы мы не взводили Ready – параметры созданной модели мы не меняли, поэтому при изменении любой динамической переменной, на которую подписан блок, будет взведен сигнал запуска Start, а это, в свою очередь, приведет к тому, что в ближайшем такте расчета наша модель будет запущена (то, что мы не вводили реакцию на такт расчета, не повлияет на запуск), а перед запуском RDS автоматически взведет Ready. Тем не менее, лучше взводить Ready вручную, а флаг «» (см. рис. 392) в параметрах модели при этом можно отключить.
Рис. 397. Проверка блоков, работающих
с «AmbientTemperature»
Теперь у нас есть блок, записывающий значение температуры в динамическую переменную, и блок, считывающий его оттуда. Для проверки этих моделей соберем схему, изображенную на рис. 397. В этой схеме слева расположен блок с моделью, записывающий вход в динамическую переменную «AmbientTemperature» (к его входу «t» присоединено поле ввода), а справа – два одинаковых блока с моделью, подающей значение этой переменной на выход (к их выходам «t» присоединены числовые индикаторы). «Размножить» созданный блок со второй моделью можно, копируя его в буфер обмена клавишами Ctrl + C и вставляя оттуда клавишами Ctrl + V, при этом на запрос модуля автокомпиляции о том, нужно ли создавать новую модель для копии блока, следует отвечать «». Запустив расчет и изменяя значение в поле ввода, можно увидеть, что значения на индикаторах изменяются синхронно: информация о температуре передается между блоками через динамическую переменную. Теперь мы можем, при желании, включать подписку на «AmbientTemperature» в модель любого блока, которому для расчетов нужна температура окружающей среды – точно так же, как мы подписывались на значение времени, формируемое блоком-планировщиком.
Следует обратить внимание на то, что в этом примере имя переменной «AmbientTemperature» жестко встроено в созданные нами модели, и, чтобы изменить его, придется изменить сами модели и скомпилировать их заново. Модуль автокомпиляции позволяет связать имя переменной с настроечным параметром блока, чтобы его мог изменять пользователь. Для этого необходимо при добавлении динамической переменной в редакторе модели в поле «» выбрать вместо варианта «» вариант «» (см. рис. 396) и ввести имя параметра, в котором будет храниться имя переменной. Подробнее этот вариант рассматривается в §3.6.7.