Комплекс программ «Среда моделирования ORPHYS 2.0» (ORPHYS) предназначен для формирования многоуровневых компьютерных моделей технических объектов и систем управления, проведения численных экспериментов, анализа динамических процессов и визуализации результатов.
Пользовательское руководство
Назначение и возможности среды
Среда ORPHYS объединяет в едином графическом интерфейсе средства структурного схемотехнического моделирования, развитую библиотеку электротехнических, гидравлических и тепловых аппаратов, блоки алгоритмического управления и визуальные панели приборов.
Область применения: Инженерное проектирование, учебные и исследовательские экспериментыРежимы анализа: Установившийся режим (статика), переходные процессы (динамика), реальное время
Быстрая навигация
Руководство ориентировано на последовательное освоение среды: от размещения первых компонентов до построения замкнутых контуров управления и генерации собственных расчетных блоков.
Для быстрого поиска по тексту и библиотеке компонентов нажмите Ctrl+K.
Три слоя модели
В основу архитектуры ORPHYS положен принцип многослойного описания исследуемой системы. Расчетная схема разделяется на три функциональных уровня:
Информационная привязка к переменным схемы (binding) без вмешательства в физические уравнения.
Наглядное графическое представление результатов и ручной ввод управляющих воздействий.
Интерфейс пользователя и элементы рабочего пространства
Палитра компонентов (Библиотека)
Расположена в левой части экрана. Содержит структурированный каталог готовых моделей, сгруппированных по предметным разделам (электротехника, гидравлика, теплотехника, системы управления, индикация).
Холст схемы (Рабочее поле)
Центральная область для позиционирования компонентов и прокладки межкомпонентных связей. Переключатель слоев в верхней части холста позволяет независимо редактировать физическую, логическую и визуальную схемы.
Панель в верхней части окна. Содержит кнопки запуска («Старт»), приостановки и сброса моделирования, а также поля настройки времени расчета ($t_{\text{end}}$) и шага ($h$).
Раздел 2
Создание и редактирование схем
Сборка расчетной схемы заключается в размещении компонентов на холсте, их коммутации проводниками, параметризации и обязательной фиксации опорного узла.
Порядок сборки схемы
1
Выбор слоя и размещение компонентов
Перейдите на требуемый слой модели (вкладки «C-слой» или «L-слой» над холстом). Выберите компонент в палитре слева и перетащите его на рабочее поле. В панели свойств задайте компоненту понятную функциональную метку (параметр label).
2
Прокладка соединений (коммутация)
Наведите курсор на контактный вывод компонента, нажмите левую кнопку мыши и протяните линию связи к выводу смежного элемента. На логическом слое соединение допускается только от выхода (out) ко входу (in).
3
Установка узлов соединения (Junction)
При разветвлении линий на физическом слое используйте специальный компонент «Узел соединения» (Junction). Простое геометрическое пересечение линий без узла не образует контакта.
4
Задание опорного узла цепи
В обязательном порядке подключите к физической цепи элемент, фиксирующий базисный потенциал (компонент «Земля» для электротехники или «Источник среды / Сток» для гидравлики).
5
Параметризация элементов
Выделите каждый компонент и в панели свойств введите требуемые физические величины и начальные условия.
Направление произвольное. При объединении трех и более связей в одной точке обязательна установка блока Junction.
Информационная связь (L-слой)
Строго от выходного порта (out) ко входному порту (in).
Запрещено замыкать выходы на выходы или входы на входы. Сигнал передается направленно.
Беспроводная передача (Goto / From)
Блок Goto принимает сигнал на вход; блок From передает сигнал со своего выхода.
Связывание выполняется по совпадению текстового тега (tag). Действует исключительно в пределах одного и того же слоя.
Беспроводная передача сигналов блоками Goto и From
Для предотвращения нагромождения длинных линий связей на логическом слое используются парные блоки:
Блок Goto: подключается к источнику сигнала и публикует его в локальном пространстве схемы под символьным именем tag (например, PID_Output).
Блок From: настраивается на идентичное имя тега и передает значение на вход приемного компонента. Один блок Goto может обслуживать произвольное количество блоков From.
Раздел 3
Связь физического и логического уровней (Адаптеры и отводы)
Среда ORPHYS позволяет строить замкнутые системы автоматического управления, где регуляторы логического слоя воздействуют на аппараты физического слоя, а измерительные преобразователи считывают параметры процесса.
Объектный слой (C)Аппарат АВО
Метрика температуры T_prod_out Команда приводу fan_cmd
Логический слой (L)ПИД-регулятор
Уставка · Измерение → Сигнал управления u
Порты-отводы технологических аппаратов (Taps)
Для подключения физического аппарата к системе управления на его графическом корпусе формируются порты-отводы:
Выходной отвод (Телеметрия): Снимает вычисленную величину физического состояния аппарата (температуру среды, перепад давлений, массовый расход) для передачи в измерительные датчики или индикаторы.
Входной отвод (Управление): Принимает внешнее командное воздействие от регулятора (степень открытия регулирующего клапана opening_cmd, задание частоты вращения вентилятора АВО fan_cmd).
Порядок добавления порта-отвода:
1
Выделение аппарата
На объектном слое выделите курсором требуемый аппарат (например, аппарат воздушного охлаждения avo).
2
Формирование отвода
В панели свойств найдите секцию «Порты-отводы», нажмите кнопку «+ выход» (для измерения) или «+ вход» (для команды управления).
3
Выбор физической величины
В выпадающем списке выберите регистрируемую переменную (например, T_prod_out для температуры продукта или fan_cmd для привода). На корпусе блока появится контактный порт.
Согласующий компонент l_device
Для взаимодействия логического алгоритма с физическим оборудованием на логическом слое устанавливается блок «Адаптер объекта» (l_device). В его свойствах указываются:
target_device: метка (label) целевого физического аппарата на объектном слое (например, AVO_1).
variable: наименование переменной, совпадающее с именем сформированного отвода (например, T_prod_out при чтении или fan_cmd при записи).
Сквозной пример: контур стабилизации температуры АВО
Схема контура: ПИД-регулятор (L-слой) → аппарат воздушного охлаждения (C-слой) → измерение температуры
Раздел 4
Запуск расчетов и режимы моделирования
Среда ORPHYS поддерживает проведение расчетов установившегося состояния, динамических переходных процессов и интерактивное моделирование в реальном времени.
Режимы расчета
Режим
Обозначение
Назначение и особенности
Рабочая точка (Статика)
DC / Static
Мгновенный расчет статического равновесия системы при постоянных внешних воздействиях. Позволяет оценить начальное состояние до запуска динамики. Возвращает вектор установившихся узловых потенциалов и ветвевых токов (last, state).
Переходный процесс (Динамика)
Transient
Основной режим моделирования. Численно рассчитывает поведение всех переменных во времени от начала и до конца. Позволяет наблюдать пусковые режимы и переходные кривые. Возвращает массивы временных рядов (series), конечные состояния (state) и параметры сходимости.
Частотный анализ
AC / Боде
Линеаризация системы в рабочей точке и расчет амплитудно-фазовых частотных характеристик (АФЧХ). Возвращает массивы комплексных коэффициентов передачи, логарифмических АЧХ и ФЧХ по спектру частот.
Настройка параметров времени и шага интегрирования
В панели управления экспериментом задаются основные параметры расчета:
Время окончания расчета ($t_{\text{end}}$): Длительность исследуемого физического процесса в секундах (например, $100\text{ с}$).
Базовый шаг ($h$): Временной интервал между расчетными точками.
Автоматический реактивный пересчет
После того как схема была однократно успешно рассчитана нажатием кнопки «Старт», активируется реактивный режим: любое последующее изменение параметров компонентов в панели свойств либо перемещение проводников автоматически инициирует фоновый пересчет схемы. Графики и цифровые табло обновляются без дополнительных действий со стороны пользователя.
Раздел 5
Визуализация и анализ результатов
Для наблюдения за ходом технологического процесса и анализа результатов моделирования на визуальном слое (V) размещаются контрольно-измерительные приборы и органы управления.
Структуры данных: ряды (series) и текущие значения (last)
Вычислительное ядро среды возвращает результаты в двух форматах:
Временной ряд (series): Полный массив пар «время — значение» за весь период расчета. Предназначен для построения непрерывных кривых переходных процессов в компоненте «График» (Chart).
Конечное значение (last): Точечное скалярное значение переменной на последнем вычисленном шаге. Предназначено для отображения текущих показаний в компонентах «Числовое табло» (Digital Display), сигнальных индикаторах и мнемосхемах.
Настройка виртуальных приборов
Компонент «График» (Chart)
1. Перетащите блок графика на визуальный слой.
2. В панели свойств найдите поле Привязка (binding).
3. Выберите из выпадающего списка требуемый сигнал (например, выход регулятора PID1.out или температуру аппарата AVO.T_prod_out).
4. Включите опцию «Автомасштабирование» для автоматической подгонки границ осей.
Компонент «Числовое табло» (Digital Display)
1. Разместите табло на визуальном слое.
2. В поле привязки выберите источник данных.
3. В строке «Единица измерения» введите текстовую подпись (например, кПа, °C).
4. Настройте количество десятичных знаков после запятой (параметр format).
Интерактивные органы управления
Для ручного воздействия на систему в режиме реального времени (Live) используются элементы ввода:
Ползунковый задатчик (Slider): Обеспечивает плавное изменение численного параметра в заданных границах (минимум, максимум, шаг приращения).
Переключатель (Toggle Switch): Служит для дискретной подачи логических сигналов (0/1) и переключения технологических блокировок.
Раздел 6
Создание собственных компонентов (Генератор моделей)
Встроенный интерактивный мастер позволяет инженеру создать новый расчетный блок через визуальный интерфейс без программирования.
Пошаговый алгоритм создания компонента
1
Запуск редактора компонентов и задание метаданных
Откройте инструмент «Редактор компонентов» из панели инструментов среды. Укажите уникальное системное имя (латиницей без пробелов, например custom_valve), понятное наименование для палитры (например, «Клапан») и выберите целевой слой (физический или логический).
2
Конфигурация портов (внешних выводов)
Добавьте контакты компонента. Для логического блока выберите направление: in (вход) или out (выход). Для физического блока выберите домен (электрика, гидравлика) и сторону размещения на корпусе. Имена портов будут использоваться в формулах.
3
Объявление параметров
Сформируйте список настроек, которые пользователь сможет изменять через панель свойств: символьное обозначение (например, K_loss), текстовая подпись, единицы измерения и базовое значение по умолчанию.
4
Математическое описание: логика vs физика
Воспользуйтесь редактором формул для ввода уравнений поведения компонента. Важно учитывать принципиальное различие слоев:
• Для логического блока: Задается формула прямого расчета выхода:
$$\text{out} = K \cdot (\text{in}_1 - \text{in}_2)$$
• Для физического блока: Физический закон должен быть приведен к форме Невязки (все переносится в левую часть, чтобы справа остался ноль).
Пример (закон Ома): Вместо $U = I \cdot R$ в редактор вводится невязка:
$$(V_{\text{in}} - V_{\text{out}}) - I \cdot R = 0$$
5
Оформление условного графического обозначения (УГО)
На вкладке глифа задайте габариты блока и нарисуйте пиктограмму. Равномерно распределите порты по сторонам прямоугольника для обеспечения удобной коммутации на схеме.
6
Валидация и регистрация
Нажмите кнопку «Проверить» (Validate) для синтаксической проверки уравнений, затем нажмите кнопку «Зарегистрировать компонент» (Register Component). Новый блок автоматически появится в палитре компонентов.
Раздел 7
Интеграция пользовательских математических моделей в БМК
Настоящая инструкция устанавливает регламент разработки, конфигурации и внедрения внешних математических моделей в составе Библиотеки Моделей Компонентов (БМК) при использовании исполняемой (EXE) версии программного комплекса ORPHYS 2.0 в операционной системе Windows.
1. Расположение директории хранения пользовательских компонентов
В структуре исполняемой сборки ORPHYS 2.0 предусмотрена изолированная директория для хранения пользовательских компонентов. Данное хранилище обладает свойством персистентности: его содержимое не подвергается удалению или перезаписи при автоматическом обновлении программного обеспечения.
Локализация пользовательского хранилища: %APPDATA%\Mars EM Simulator\bmk\ (Абсолютный путь, как правило, имеет вид: C:\Users\<Имя_Пользователя>\AppData\Roaming\Mars EM Simulator\bmk\)
2. Архитектура каталога компонента
Каждый разрабатываемый компонент должен быть размещен в отдельной поддиректории. Наименование поддиректории должно состоять из символов латинского алфавита и строго соответствовать идентификатору компонента.
Структура исходного кода (язык Python):
%APPDATA%\Mars EM Simulator\bmk\
└── my_pump\
├── my_pump.py # Исходный код математической модели (язык Python)
├── catalog.json # Декларативное описание графического интерфейса (определение портов, параметров)
└── helper.py # (Опционально) Вспомогательные модули, содержащие дополнительную логику
Для интегрирования проприетарных (скомпилированных) компонентов вместо файла с расширением .py применяется бинарный модуль .pyd:
%APPDATA%\Mars EM Simulator\bmk\
└── my_pump\
├── my_pump.cp313-win_amd64.pyd # Бинарный модуль расширения (компиляция C++/Cython)
└── catalog.json
В случае одновременного присутствия файлов с расширениями .pyd и .py в одной директории, вычислительное ядро автоматически отдает приоритет загрузке модуля .pyd.
3. Среда исполнения (Интерпретатор Python)
Выполнение кода посредством встроенного интерпретатора: В состав исполняемой версии ORPHYS 2.0 интегрирован автономный интерпретатор CPython версии 3.13 (64-битная архитектура). Системный интерпретатор Python (установленный в операционной системе пользователя) не задействуется.
Ограничения стандартной библиотеки Python: Вследствие компиляции бэкенда ORPHYS, модули, не задействованные в базовом функционале, исключены из сборки с целью минимизации объема дискового пространства (например, отсутствуют модули tkinter, unittest, pytest).
Модули, доступные в базовой конфигурации:
Пакет разработки (SDK) симулятора: mars_models_sdk (включающий элементы @component, ComponentSpec, Port, Param).
Ключевые модули стандартной библиотеки: math, json, random, re, os, sys, dataclasses, time и прочие.
Библиотеки для проведения математических вычислений: numpy, scipy, sympy.
4. Порядок импорта библиотек и смежных модулей
4.1 Импорт вспомогательных модулей (например, helper.py)
Симулятор осуществляет загрузку компонентов напрямую, используя механизм importlib. Следует учитывать, что директория компонента не добавляется в системный путь sys.path автоматически. Попытка прямого или относительного импорта приведет к генерации исключения ModuleNotFoundError.
Корректный синтаксис импорта смежных файлов в коде компонента:
import sys
from pathlib import Path
# Обеспечение доступности директории текущего компонента для механизма импорта:
_COMP_DIR = str(Path(__file__).parent.resolve())
if _COMP_DIR not in sys.path:
sys.path.insert(0, _COMP_DIR)
# Выполнение импорта смежного модуля:
import helper
4.2 Использование внешних сторонних библиотек (pip)
Ввиду независимости от системного интерпретатора Python, пакеты, установленные глобально через менеджер pip, недоступны для автоматической загрузки.
Библиотека должна быть полностью совместима с Python 3.13 (AMD64 / ОС Windows).
Для библиотек, написанных исключительно на Python (pure-python), необходимо скопировать директорию библиотеки в каталог разрабатываемого компонента (или в поддиректорию libs/) и зарегистрировать путь в sys.path, аналогично пункту 4.1.
Бинарные C-расширения (файлы .pyd / .dll) должны быть строго скомпилированы под среду CPython 3.13 64-bit. Все динамически подключаемые DLL-библиотеки должны располагаться в той же директории.
5. Жизненный цикл и процедура регистрации компонентов
Автоматическое сканирование каталога: Симулятор производит сканирование директории %APPDATA%\Mars EM Simulator\bmkисключительно в момент инициализации (запуска) программы.
Отсутствие динамической перезагрузки (Hot-Reload): При внесении изменений в файлы во время работы программы симулятор не применяет модификации в реальном времени. Вычислительное ядро использует версию модуля, загруженную в память при старте.
Регламент обновления: После каждого сохранения изменений в файлах модели необходимо выполнить перезапуск среды моделирования. При последующей инициализации компонент будет повторно считан с диска и зарегистрирован.
6. ВАЖНО: Отсутствие двунаправленной синхронизации с утилитой "Генератор компонентов"
В состав ORPHYS входит утилита «Генератор компонентов» (визуальный конструктор). Необходимо учитывать критический принцип архитектуры:
Практические следствия:
Безусловная перезапись файлов: При активации функций «Сгенерировать» или «Сохранить» в интерфейсе Генератора компонентов, программа формирует исходный код на базе визуально заданных параметров и полностью перезаписывает файлы <name>.py и catalog.json в целевой директории.
Игнорирование ручных модификаций: Если вы модифицировали файл .py во внешнем редакторе, Генератор компонентов не выполнит импорт этих изменений. Повторное открытие компонента отобразит лишь состояние, зафиксированное в визуальных формах при последнем сохранении.
Риск утраты исходного кода: Если после ручного редактирования файла .py пользователь повторно нажмет «Сохранить» в Генераторе, файл будет сформирован заново, что приведет к безвозвратной утрате всех ручных модификаций кода.
Регламент организации рабочего процесса (Рекомендуемый для сложных моделей):
Создание каркаса компонента в Генераторе (декларация портов, параметров и УГО).
Генерация базовой структуры файлов.
Последующее прекращение использования Генератора для данного компонента (запрет на сохранение в конструкторе).
Дальнейшая разработка файла .py во внешней среде разработки (IDE).
Исходный код математической модели my_resistor.py:
import sys
from pathlib import Path
# 1. Интеграция директории компонента в системный путь
_COMP_DIR = str(Path(__file__).parent.resolve())
if _COMP_DIR not in sys.path:
sys.path.insert(0, _COMP_DIR)
# 2. Импорт SDK симулятора
from mars_models_sdk import component
# 3. Применение декоратора для регистрации функции
@component("my_resistor", inp="in_val", out="out_val")
def my_resistor_step(io):
# Извлечение значения из входного порта
u_in = io.read("in_val", 0.0)
# Считывание конфигурационного параметра
r = io.param("resistance", 100.0)
# Внедрение защиты от деления на ноль
if r == 0:
r = 1e-6
# Вычисление выходной величины
i_out = u_in / r
# Трансляция вычисленного значения в выходной порт
io.write("out_val", i_out)
Директория компонента размещена строго по пути %APPDATA%\Mars EM Simulator\bmk\<идентификатор>\.
✓
Именования
Наименование директории и основного исполняемого файла (.py или .pyd) полностью совпадают и состоят из латинских символов.
✓
Каталог интерфейса
В наличии синтаксически корректный файл catalog.json, содержащий определение интерфейсов (nodes) и параметров (attrs).
✓
Импорты
При использовании импорта смежных модулей реализована модификация sys.path в заголовочной части.
✓
Перезапуск
Процедура перезапуска среды ORPHYS выполнена после фиксации последних изменений в файлах.
✓
Защита кода
Файл исходного кода не подвергался перезаписи со стороны утилиты "Генератор компонентов" после внесения ручных модификаций.
Раздел 8
Диагностика частых ошибок (ЧаВо / FAQ)
Сводная таблица типовых нештатных ситуаций, возникающих при формировании и расчете схем, с указанием причин и способов устранения.
Проблема / Сообщение среды
Вероятная причина
Рекомендуемое решение
«Нет опоры: добавьте Землю / Источник / Приёмник»
В физической цепи отсутствует опорный узел, фиксирующий точку отсчета.
Добавьте в схему компонент «Земля» (Ground) для электрической цепи либо аппараты «Источник среды» (FEED) / «Сток» (SINK) для гидравлической сети. ВАЖНО: Данные компоненты связаны с соответствующими граничными условиями своего домена.
График остается пустым после пуска
1. Ошибка в имени переменной в поле привязки (binding). 2. Значения сигнала находятся за пределами видимого масштаба осей.
1. Выберите имя переменной заново из выпадающего списка, а не вводите вручную. 2. Активируйте в свойствах графика флажок «Автомасштабирование».
Схема не пересчитывается при изменении параметров
Среда не перешла в реактивный режим, так как схема не была рассчитана первично.
Выполните однократный ручной запуск расчета кнопкой «Старт». После этого автоматический фоновый пересчет будет активирован.
Проводники пересекаются, но сигнал не передается
Пересечение линий на чертеже не создает топологического контакта.
Установите в точке разветвления компонент «Узел соединения» (Junction) и подключите проводники непосредственно к нему.
Сигнал на логическом слое равен нулю или константе
Нарушена направленность связи (выход соединен с выходом либо вход со входом).
Проверьте ориентацию: на логическом слое соединение всегда выполняется строго от правого выходного порта (out) к левому входному порту (in).
Раздел 9
Создание компонента логического уровня
Практическое руководство по разработке функциональных компонентов логического слоя (L-слоя) в среде моделирования ORPHYS 2.0 с помощью визуального «Генератора компонентов».
Расширенное практическое руководство по разработке функциональных компонентов логического слоя (L-слоя) в среде моделирования ORPHYS 2.0 с помощью визуального «Генератора компонента».
1. Принцип работы логического компонента
В отличие от физического компонента, который формирует невязку F(X, dX/dt, t) = 0, логический компонент реализует один тик (шаг) вычислений — обычную чистую функциональную программу:
Исходный код / фрагмент конфигурации
выход = f(входы, параметры, состояние)
Ключевые особенности:
Вычисление явное, а не совместное с соседями. Логический блок не «договаривается» с ядром об общем решении — он просто получает значения входов и возвращает значения выходов.
Исполнение шаг за шагом по тикам временной сетки. Шаг dt фиксирован (по умолчанию согласован с шагом интегрирования объектного слоя, но может быть задан отдельно).
Состояние (io.state) живёт между тиками, обеспечивает храниеие и накопление значения переменной.
Связь направленная — out → in. В отличие от объектного слоя, нет акаузального объединения узлов; каждый провод отдает скаляр от одного выхода строго одному входу.
Реактивное исполнение. После успешного первичного расчёта ComponentBus реагирует на любое изменение параметра или связи в инспекторе мгновенно в фоновом режиме.
Эта особенность диктует три практических следствия для разработчика:
Тело компонента должно быть чистым: без побочных эффектов, без print, без мутаций глобальных переменных. Шина может вызывать компонент параллельно по разным веткам графа.
Персистентная память организуется через io.state, а не через глобальные переменные Python-модуля — иначе состояние «протекает» между экземплярами одного класса компонентов.
Если нужен явный интегратор с фиксированным шагом, всегда используется io.integrate(name, rate, x0) — не собственная реализация метода Эйлера.
Полный путь от определения модели до видимости блока в логической палитре состоит из тех же двух уровней регистрации, что и для объектного слоя.
Уровень
Назначение
Артефакт
Палитра/UI
Метаданные в палитре, инспекторе свойств, подсказках.
data/catalog.json + generated_catalog.js.
Шина/ядро
Исполняемый код шага, регистрируется декоратором @component или @registered(SPEC).
Скомпилированный файл в bmk/<lgroup>/<name>/....
2.1. Декораторы регистрации
Из архитектурного руководства (раздел «Выбор слоя и математической парадигмы»):
Слой
Декоратор
Сигнатура функции шага
Логический
@registered(SPEC) или @component (через mars_models_sdk.component)
def step(io): ...
Объектный
@physical(SPEC)
def residual(elem): ... (через Elem) или def f(c, V, I, dV, dI, t, lam): ... (напрямую)
В генераторе эквивалент декоратора «спрятан» в служебном коде, который формируется автоматически при нажатии «Зарегистрировать». Вручную править его не нужно.
2.2. Сервис исполнения
Шина компонентов — ComponentBusService.EvaluateGraph — топологически сортирует блоки логического графа и выполняет их в нужном порядке.
В одном проекте могут сосуществовать Python- и C++-реализации одного и того же компонента. Хост автоматически выбирает более быстрый бэкенд (C++), если он доступен, иначе выполняет Python-версию — при условии идентичности формул в обоих файлах.
2.3. Хранилище памяти: io.state
io.state — это словарь персистентной памяти компонента. Он сохраняется:
между тиками внутри одного запуска;
между повторными пересчётами той же схемы;
между сессиями в режиме реального времени (Live), пока не вызван явный сброс.
Поведение словаря описано в таблице IO (см. раздел 9.2 ниже):
Код (python)
io.state["acc"] = ... # запись
io.state.get("acc", 0.0) # безопасное чтение с дефолтом
io.state # прямой доступ к словарю
2.4. Интегрирование: io.integrate
Шина применяет явный метод Эйлера с фиксированным шагом io.dt. Метод io.integrate(name, rate, x0) извлекает значение из io.state, делает инкремент x_{n+1} = x_n + rate * dt и сохраняет результат обратно. Этот метод — единственный способ гарантированно сохранить состояние интегратора между тиками и не потерять пересчёты при изменении схемы.
2.5. Реактивность
Логический слой реактивен непрерывно: после первого расчёта любое изменение связей или параметров блока в инспекторе мгновенно пересчитывает функциональные ряды в фоновом режиме.
3. Сравнение с объектным слоем
Признак
Логический компонент (L-слой)
Физический компонент (C-слой)
Декоратор
@registered(SPEC) / @component
@physical(SPEC)
Математическая задача
Вычислить функциональный шаг: выход = f(входы, параметры)
Сформулировать невязки: F(X, dX/dt) = 0
Метод интегрирования
Локальный явный (метод Эйлера) через io.integrate
Глобальный совместный (метод Эйлера/BDF/Radau) внутри решателя
Внутренние состояния
Произвольный словарь io.state
Вектор `states=[(name, "diff"
Топологическая связь
Направленная: out → in
Акаузальная: полюса объединяются в узлы цепи по KCL
Главный критерий: если закон описывается как «преобразовать скаляр в скаляр» — это требует компонента L-слоя. Если как «связать давление и поток ветви физическим законом» — это требует компонента C-слоя. Если модель содержит уравнения непрерывности, баланса или нелинейной характеристики физической величины — это всегда C-слой.
4. Подготовка: что нужно знать до запуска генератора
Прежде чем нажимать «Запустить генератор», зафиксируйте на бумаге:
Машинное имя (bus id): латиница, без пробелов, уникальное в библиотеке. Используется в реестре и при сборке каталога.
Слой компонента: в генераторе выбирается переключателем «Логический» в правом верхнем углу генератора (см. п. 6).
Список входов (inp=) и выходов (out=) — направленные скалярные порты. У одного блока может быть несколько входов и несколько выходов.
Список параметров: имя, тип, значение по умолчанию, единица измерения, границы (min/max/step).
Алгоритм: формула шага выход = f(входы, параметры), или последовательность операций с использованием пресетов (read, write, integrate, state).
Состояния памяти (если есть): какие переменные нужно хранить между шагами расчета. Описываются как «дифференцируемые параметры» на вкладке «Параметры».
Строковые режимы (если есть): например, мультирежимный источник (const, ramp, sine, square, step).
Зависимости для кода Python: используются ли numpy, scipy, sympy, scikit-learn, pandas (встроены) или нужны сторонние пакеты (тогда потребуется .pyd).
5. Шаг 1. Запуск «Генератора компонента»
Запускаем
Запуск производится из меню «Сервис» основного интерфейса ORPHYS. После открытия генератора появляется окно с тем же набором вкладок, что и для объектного слоя, но с одним важным отличием: вкладка «Невязки» заменена на вкладку «Алгоритм», а на вкладке «Код» доступны специальные XML-теги <mars:user-*>.
Рекомендуемый порядок заполнения:
Исходный код / фрагмент конфигурации
Порты → Параметры → Алгоритм → Код → Внешний вид → Документация
Именно в таком порядке поля более поздних вкладок получают автозаполненные ссылки на ранние сущности.
6. Шаг 2. Вкладка «Порты»
Заполняем порты
Что здесь задаётся: интерфейс компонента — список направленных портов (in/out), которые будут видны на холсте логического слоя для подключения проводов. С точки зрения архитектуры это поля ports= дескриптора ComponentSpec с layer="logic".
6.1. Главный переключатель слоя
В верхней части окна генератора находится переключатель «Объектный»/«Логический». Для компонента логического уровня выбирается «Логический». После этого выбора:
во вкладке «Невязки» вкладка переименовывается в «Алгоритм»;
становятся доступны пресеты алгоритма (read, write, integrate, state, param, text, и т.п.);
в сгенерированном коде используется декоратор @component (а не @physical).
6.2. Минимальные поля одной записи порта
Поле
Назначение
Пример
name
Машинное имя порта. Используется в io.read("name", …) и io.write("name", …).
x, y, setpoint, T_prod_out
dir
Направление: in (вход) или out (выход). В отличие от объектного слоя, dir влияет не только на визуализацию, но и на логику исполнения графа.
in
side
Сторона блока: left, right, top, bottom.
left
description
Текстовое описание.
Например, «Измеренное значение температуры»
6.3. Количество портов и направление
Минимум для функционального блока — один вход или один выход. Генератор, источник сигнала или константа могут иметь только выход; индикатор или запись — только вход.
Компонент может иметь Несколько входов (ПИД-регулятор, например, имеет setpoint и meas, сумматор — a и b); а также может иметь несколько выходов (например, ПИД-регулятор выдаёт u и last_error, блок сравнения выдаёт gt, eq, lt).
Соединение только out → in: связь отдает значение переменной (объект) от одного выхода ко всем присоединённым связями входам.
6.4. Конфликт имён
Если два логических выхода случайно соединены с одним входом — это ошибка топологии, регистрируемая валидатором. Маркер «нет опоры» / «соединение запрещено» — именно то, что блокирует такую конфигурацию.
6.5. Расширенные поля
Поле
Назначение
unit
Единица измерения (влияет на отображение в инспекторе, не на вычисления).
default
Значение по умолчанию для входов без подключения.
publish
Флаг публикации значений из порта на визуальный слой (для графиков и табло).
7. Шаг 3. Вкладка «Параметры»
Заполняем параметры
Что здесь задаётся: коэффициенты, режимы, начальные условия и состояния памяти. В коде это поля params= дескриптора ComponentSpec и словарь io.state после регистрации.
7.1. Состав полей одной записи параметра
Поле
Назначение
name
Машинное имя. Читается в коде через io.param("name", default).
value
Значение по умолчанию.
unit
Единица измерения.
type
Тип данных (см. ниже).
description
Описание.
publish
Публикация на визуальный слой.
7.2. Поддерживаемые типы
type
Назначение
Пример
number
Вещественный скаляр.
Коэффициент усиления gain = 2.5974.
int
Целое число.
Индекс режима mode_id = 2.
string
Строковый режим (mode = "sine").
bool
Логический флаг (enabled = True).
combo
Выбор из фиксированного списка.
Режимы работы источника.
array
Массив коэффициентов.
Полином фильтра.
pair
Кортеж (min, max).
Диапазон допуска.
table
Табличная кусочно-линейная характеристика.
Внешняя Q-H насоса.
7.3. Состояния (stateful-параметры)
Для интеграторов, фильтров и ПИД-регуляторов добавляются записи состояний: это переменные, которые хранятся в io.state и запоминаются между шагами. На вкладке «Параметры» они имеют признак «Дифференцируемый» или просто маркируются как состояние.
состояния: integral = 0.0, prev_error = 0.0 (память интегратора и предыдущей ошибки).
7.4. Тепловая модель (не применимо)
В логическом слое секция «Тепловая модель» не появляется: это понятие физического уровня. Если логический блок участвует в тепловом контуре (например, ПИД управляет АВО), он работает только с числовыми значениями, а тепловое моделирование выполняется в объектном слое через блок АВО.
8. Шаг 4. Вкладка «Алгоритм» (главный шаг)
Заполняем уравнения
Центральный шаг разработки. Здесь формулируется функциональный алгоритм шага — тело будущей функции def step(io): .... Вкладка отличается от объектного слоя тем, что:
используются пресеты команд из боковой панели (чтение входа, запись выхода, доступ к состоянию и т.п.);
формула имеет вид присваивания (выход = …), а не невязки (F = 0);
проверка и сборка переводит алгоритм в питоновский скелет с заглушками для всех внутренних переменных.
8.1. Пресеты команд
В правой панели вкладки доступны кнопки-вставки готовых конструкций. Наиболее употребительные:
Пресет
Вставляемая строка
Семантика
read("x")
x = io.read("x", 0.0)
Считать значение входного порта x.
read (default)
… , 0.0)
С дефолтом, если провод не подключен.
param("K")
K = io.param("K", 1.0)
Считать числовой параметр.
text("mode")
mode = io.text("mode", "")
Считать строковый режим.
flag("on")
on = io.flag("on", False)
Считать логический флаг.
state.get("acc", 0)
acc = io.state.get("acc", 0.0)
Безопасное чтение памяти.
state["acc"] = …
io.state["acc"] = …
Запись в память.
integrate("x", dx_dt, x0)
x = io.integrate("x", dx_dt, x_prev)
Шаг явного Эйлера.
write("y", …)
io.write("y", value)
Записать значение выхода.
ts, dt
t = io.ts, dt = io.dt
Текущий такт и шаг по времени.
Пресеты избавляют от опечаток в строковых литералах и обеспечивают единообразие кода: генератор сам подставляет правильное имя порта/параметра из соответствующих вкладок.
8.2. Правила записи алгоритма
Форма — присваивание, а не невязка. Это y = gain * x + offset, а не y - gain * x - offset == 0.
Финальная строка должна быть io.write("выход", value) для каждого выходного порта. Если выходов несколько, делается несколько io.write (для каждого свой).
Все идентификаторы должны быть объявлены либо как порт (вкладка «Порты»), либо как параметр (вкладка «Параметры»). Свободные имена не допускаются.
Все состояния читаются через io.state.get(..., default) на каждом тике. При первом тике io.state пуст — и без default вылетит KeyError.
Допускается несколько строк и if/elif/else — алгоритм логический, не обязан укладываться в одну формулу.
Здесь io.integrate не нужен — это алгебраический фильтр, а не интегратор. Состояние запоминается через io.state явно.
Мультирежимный источник сигнала
Исходный код / фрагмент конфигурации
mode = io.text("mode", "")
base = io.param("base", 25.0)
amp = io.param("amplitude", 20.0)
freq = io.param("freq", 0.1)
if mode == "sine":
v = base + amp * math.sin(2 * math.pi * freq * io.ts)
elif mode == "step":
v = base + (amp if io.ts >= io.param("t0", 0.0) else 0.0)
elif mode == "const":
v = base
else:
v = base
io.write("value", v)
Логический автомат (гистерезис)
Исходный код / фрагмент конфигурации
x = io.read("x", 0.0)
hi = io.param("hi", 1.0)
lo = io.param("lo", 0.0)
state = io.state.get("tripped", False)
if state and x < lo:
state = False
elif (not state) and x > hi:
state = True
io.state["tripped"] = state
io.write("y", 1.0 if state else 0.0)
8.4. Проверка и сборка
После заполнения алгоритма нажмите «Проверить и собрать». Генератор:
Парсит текст алгоритма через встроенный парсер Python AST.
Проверяет, что все идентификаторы разрешены (объявлены в портах, параметрах или состояниях).
Подставляет default-значения и проверяет синтаксическую корректность.
Генерирует питоновский скелет компонента с заглушками для всех внутренних переменных.
Открывает доступ к редактированию сгенерированного кода на вкладке «Код».
Если хотя бы один шаг возвращает диагностику, файл не сохранится до устранения проблем.
9. Шаг 5. Вкладка «Код» — Python в тегах mars:user-*
Дописываем код
Вкладка «Код» для логического слоя устроена также как и для объектного. Здесь доступны три специальных XML-тега, в которые вставляется пользовательский Python-код (не доступен тег блока невязок):
Тег
Назначение
Когда использовать
<mars:user-imports>
Блок импортов сторонних пакетов.
Если используются numpy, scipy, sympy, pandas, scikit-learn, либо собственные модули.
Генератор сам формирует вокруг этих блоков всю обвязку:
Код (python)
# Автоматически сгенерированная шапка:
from mars_core.component_sdk import component
from mars_core.component_spec import ComponentSpec, Port, Param, AutomationSpec, ...
SPEC = ComponentSpec(
name="my_pid",
layer="logic",
folder="Управление",
ports=[Port("setpoint", dir="in"), Port("meas", dir="in"),
Port("u", dir="out")],
params=[Param("Kp", 0.8, "—"), Param("Ki", 0.05, "—"),
Param("Kd", 0.1, "—"), Param("dt_min", 0.0, "с")],
# ... и т.д. из вкладок Порты и Параметры
)
# <mars:user-imports>
import math # ← пользовательский импорт
# </mars:user-imports>
# <mars:user-helpers>
def _clamp(x, lo, hi):
return max(lo, min(hi, x)) # ← пользовательская функция
# </mars:user-helpers>
@component("my_pid", inp="meas", out="u", spec=SPEC)
def my_pid(io):
# <mars:user-compute>
sp = io.read("setpoint", 0.0)
meas = io.read("meas", 0.0)
e = sp - meas
Kp = io.param("Kp", 0.8)
Ki = io.param("Ki", 0.05)
Kd = io.param("Kd", 0.1)
integral = io.state.get("integral", 0.0)
de = (e - io.state.get("prev_error", 0.0))
integral += e * io.dt
u = Kp * e + Ki * integral + Kd * de / max(io.dt, 1e-9)
u = _clamp(u, -100.0, 100.0)
io.state["integral"] = integral
io.state["prev_error"] = e
io.write("u", u)
# </mars:user-compute>
9.1. Когда нужно дописывать код вручную
Подключение сторонних пакетов: numpy.linalg, scipy.signal, pandas.read_csv, модели scikit-learn — все они разрешены «из коробки», импорт делается в <mars:user-imports>.
Сложные многоступенчатые алгоритмы: если алгоритм содержит вложенные for, списковые включения, генераторы табличных коэффициентов — их удобнее оформить в виде вспомогательной функции в <mars:user-helpers>.
Использование .pyd/.so модулей — при необходимости подключения собственных скомпилированных библиотек их .pyd-файл размещается в одной папке с компонентом и импортируется обычным способом.
9.2. Таблица API io
Это полный контракт интерфейса, читаемый внутри функции шага.
Метод
Возврат
Семантика
io.read(port, default)
float
Считывает значение входного вывода. Сигнал с провода имеет приоритет над одноимённым параметром.
io.param(key, default)
float
Считывает числовой параметр. Нечисловые значения безопасно заменяются на default.
io.text(key, default)
str
Считывает строковый параметр, например mode="sine".
io.flag(key, default)
bool
Считывает логический флаг (true/false, 1/0, yes/no).
io.array(key, default)
list[float]
Считывает массив из JSON или CSV.
io.pair(key, default)
tuple[float, float]
Считывает двухэлементный кортеж (min, max).
io.table(key, default)
list[tuple[float, float]]
Считывает табличную кусочно-линейную характеристику (список пар точек).
io.write(port, value)
None
Записывает вычисленное значение в выходной порт (скаляр, вектор или словарь).
Словарь персистентной памяти, сохраняемый между тиками и пересчётами.
io.ts
int/float
Текущий индекс тика временной сетки (0, 1, 2, …).
io.dt
float
Величина шага дискретизации по времени.
9.3. Импорт сторонних модулей
Генератор автоматически разрешает импорты четырёх встроенных пакетов: scipy, numpy, sympy, scikit-learn, pandas. Все они доступны без дополнительной настройки. Иные пакеты требуют размещения скомпилированного .pyd-файла в папке компонента:
Исходный код / фрагмент конфигурации
bmk/<group>/my_pid/
├── my_pid.py # код компонента
├── my_pid.pyd # скомпилированный собственный модуль
└── tests/
После редактирования нажмите «Проверить код» — генератор перепарсит AST и убедится, что все импорты разрешены.
9.4. Ограничения
Тело функции должно быть чистым: без глобальных мутаций и без print. Шина может вызывать компонент параллельно.
Состояние хранится только в io.state. Глобальные переменные Python-модуля дают утечку между экземплярами.
Длинные табличные коэффициенты лучше выносить в отдельный файл .npz / .csv и читать через io.array или io.table — иначе def разрастается до десятков килобайт.
Запрещается явное использование requests, subprocess, socket — вычислительное ядро изолировано от внешних сервисов.
10. Шаг 6. Вкладка «Внешний вид»
Редактируем внешний вид
Здесь задаётся векторное обозначение компонента, отображаемое в логической палитре и на холсте логического слоя. Функциональность идентична объектному слою (см. соответствующий раздел guide_object.md), но с двумя особенностями:
Символ на теле блока. Для логических блоков принято использовать функциональные обозначения: треугольник для усилителей, прямоугольник с буквой S для сумматоров, прямоугольник с ∫ для интеграторов, прямоугольник с ∫ и pid для ПИД-регуляторов.
Стрелки направления. В отличие от объектного слоя, на логических блоках явно рисуются стрелки in / out, чтобы инженер не ошибся при подключении. Генератор рисует их автоматически, но внешний вид можно скорректировать вручную.
Рекомендации
Длина подписей портов — не более 4–6 символов (in, out, u, y, pid_in).
Символ тела — опознаваемый, в верхнем регистре: PID, FF, EMA, SRC.
Точки подключения должны точно совпадать со сторонами, указанными на вкладке «Порты».
11. Шаг 7. Вкладка «Документация»
Заполняем информацию
Что здесь задаётся: паспорт компонента. Функциональность идентична объектному слою (guide_object.md).
Минимальный набор полей
Поле "Краткое описание". Что можно писать:
Аспект
Описание
Назначение
Краткое (1–2 предложения) описание того, что моделирует компонент.
Область применения
Где уместно его использовать, с указанием типовых схем.
Поле "Внешние зависимости". Здесь необходимо указывать требуемые библиотеки для работы компонента.
Поле "Связанные компоненты". Указываются компоненты, связанные с описываемым, или рабоающие с ним в связке.
Поле "Замечания". Что можно писать:
Аспект
Описание
Алгоритм работы
Краткое описание принципа работы
Ограничения модели
Диапазоны применимости, критичные условия (Re, ΔP, T).
Версия и автор
Кто и когда создал компонент. Используется для отслеживания изменений.
Поле "Ссылки на источники". Указывется ссылка на литературный источник, детально описывающий компонент.
Что указать обязательно
Суть алгоритма — даже если она очевидна из кода. Формула нужна для рецензирования без запуска Python.
Требования к шагу dt — устойчивость явного Эйлера зависит от выбора dt. Если компонент содержит интегратор с большим коэффициентом усиления, укажите минимально допустимый шаг.
Безопасное значение safe_value — особенно для исполнительных механизмов (вентилятор, клапан). При остановке сессии шина переводит выход в safe_value (см. п. 14 «Частые сценарии»).
12. Шаг 8. Контроль готовности и место сохранения
Перед регистрацией выполните финальную проверку.
Чек-лист готовности
Машинное имя — латиница, без пробелов, уникальное.
Слой — переключатель стоит в положении «Логический».
Список портов соответствует логике алгоритма: каждый io.read("…") имеет одно объявление Port со стороной и направлением.
Список параметров покрывает все io.param(...) / io.text(...) / io.flag(...) / io.array(...) / io.pair(...) / io.table(...).
Состояния объявлены, если алгоритм обращается к io.state.
Алгоритм записан и проходит проверку.
Код проходит проверку синтаксиса и импортов.
Глиф не выходит за габариты портов.
Паспорт заполнен, ограничения указаны.
Выбор папки сохранения
Логические компоненты публикуются в пользовательскую папку bmk/:
Исходный код / фрагмент конфигурации
poc/bmk/<group>/<component_name>/
├── <component_name>.py # код компонента
├── <component_name>.cpp # опционально, для C++ версии
├── <component_name>.tex # документация (паспорт)
├── glyph.svg # внешний вид (опционально)
└── tests/
└── test_<component_name>.py
13. Шаг 9. Регистрация и проверка появления в БМК
Находим компонент в БМК
По нажатию кнопки «Зарегистрировать» генератор выполняет конвейер регистрации (идентичен объектному слою):
Сохранение исходников в папку bmk/<group>/<component>/. Формируются:
<name>.py — код с ComponentSpec (где layer="logic") и декоратором @component;
<name>.tex — паспорт;
glyph.svg — глиф;
test_<name>.py — заготовка юнит-теста.
Вызов регистратора — компилирует код, импортирует модуль и регистрирует блок в реестрах REGISTRY, _RESIDUALS, _PHYSICAL_SPECS. Это возможно без перезапуска сервера (исполняемого приложения ORPHYS).
Генерация записи catalog.json с метаданными для палитры.
Сборка обновлённого клиентского каталога.
Пересборка production-бандла (по необходимости).
Запуск автотестов.
Визуальная проверка: новый блок появляется в палитре логического слоя в указанной папке.
Как убедиться, что регистрация прошла успешно
В дереве палитры логического слоя отображается новая запись.
В инспекторе свойств видны параметры с правильными единицами.
При запуске минимальной пробной схемыКонстанта → мой_блок → Индикатор расчёт не падает, индикатор показывает значение.
14. Частые сценарии алгоритмов
Здесь приведены примеры логических компонентов.
14.1. Преобразователь вход → выход (датчик температуры)
Линейная функция $T = R \cdot \text{gain} + \text{offset}$:
Код (python)
@component("datchik_temperatury", inp="R_Ohm", out="T_C")
def datchik(io):
x = io.read("R_Ohm", 100.0)
g = io.param("gain", 2.5974)
off = io.param("offset", -259.74)
io.write("T_C", x * g + off)
14.2. Источник гармонического сигнала во времени
Без входа; выход строится на базе счётчика тиков io.ts:
Код (python)
import math
from mars_core.component_sdk import component
@component("istochnik_znacheniya", inp="p_in", out="value")
def src(io):
base = io.param("base", 25.0)
amp = io.param("amplitude", 20.0)
freq = io.param("freq", 0.1)
val = base + amp * math.sin(2.0 * math.pi * freq * io.ts)
io.write("value", val)
14.3. Мультирежимный источник с переключением во время выполнения
Строковый режим io.text("mode", "") с числовым резервом mode_id:
Код (python)
import math
from mars_core.component_sdk import component
@component("multimod_source", inp="p_in", out="value")
def multimod_source(io):
base = io.param("base", 25.0)
amp = io.param("amplitude", 20.0)
freq = io.param("freq", 0.1)
slope = io.param("slope", 1.0)
t0 = io.param("t0", 0.0)
modes = {"const": 0, "ramp": 1, "sine": 2, "square": 3, "step": 4}
m = modes.get(io.text("mode", ""), int(io.param("mode_id", 2.0)))
if m == 0: v = base
elif m == 1: v = base + slope * io.ts
elif m == 3: v = base + amp * (1.0 if math.sin(2*math.pi*freq*io.ts) >= 0 else -1.0)
elif m == 4: v = base + (amp if io.ts >= t0 else 0.0)
else: v = base + amp * math.sin(2 * math.pi * freq * io.ts)
io.write("value", v)
14.4. Линейный ограничитель (Limiter)
Надёжная параметризация с безопасными дефолтами:
Код (python)
from mars_core.component_sdk import component
@component("limiter", inp="x", out="y")
def limiter(io):
x = io.read("x", 0.0)
k = io.param("k", 1.0)
lo = io.param("min", 0.0)
hi = io.param("max", 100.0)
y = max(lo, min(hi, x * k))
io.write("y", y)
Полиномиальный фильтр с кусочно-линейной характеристикой:
Код (python)
from mars_core.component_sdk import component
@component("poly_filter", inp="x", out="y")
def poly_filter(io):
x = io.read("x", 0.0)
coeffs = io.array("coeffs", [0.0])
lo, hi = io.pair("range", (-100.0, 100.0))
table = io.table("curve", [])
y = 0.0
p = 1.0
for c in coeffs:
y += c * p
p *= x
y = max(lo, min(hi, y))
io.write("y", y)
при meas = setpoint выход u стабилизируется около 0 (или значения, которое даёт интегральная составляющая);
при ступенчатом изменении meas выход реагирует с характерной ПИД-кривой (бросок → затухание → стабилизация);
состояние ПИД не сбрасывается при изменении связей в инспекторе (проверка bumpless transfer).
16.4. Регрессионное тестирование в pytest
Поместите тесты в tests/test_<имя_компонента>.py. Минимальный набор:
Регистрация:assert "<name>" in REGISTRY.
Аналитический баланс: при известных значениях выход равен расчётному.
Память: интегратор и фильтр сохраняют io.state между тиками.
Типовая ошибка топологии: попытка соединить два выхода должна приводить к ошибке валидатора (если хочется автоматизировать этот контроль).
17. Управление жизненным циклом
Обновление дефолтов параметров
Изменение значений по умолчанию безопасно: влияет только на вновь размещаемые блоки. Уже размещённые экземпляры хранят свои значения в attrs каждого блока.
Переименование машинного имени порта
Изменение алгоритма
Переписывание тела функции допустимо после публикации — внутренняя логика изолирована от топологии. Однако:
если вы изменяете список читаемых параметров — синхронно обновите вкладку «Параметры» в ComponentSpec;
если вы добавляете новое состояние — опишите его на вкладке «Параметры» как дифференцируемый параметр;
сохраните обратную совместимость: инспектор уже размещённых блоков не должен показывать незнакомые поля (для этого используются дефолты).
Удаление компонента
Удалите файлы из bmk/<group>/<component>/.
Запустите среду моделирования.
Убедитесь, что активные проекты не содержат экземпляров компонента (иначе — ошибка валидатора при загрузке).
Конкурентная запись параметров в реальном времени
Один и тот же параметр исполнительного механизма (например, cmd) не должен одновременно перезаписываться регулятором, сценарием ИСУЛ и ручным вводом из инспектора. Для разрешения конфликта используются приоритетные классы управления (priorityClass в AutomationCommand) и политики сценария в ИСУЛ.
18. Краткая шпаргалка
18.1. Минимальный обязательный набор полей в генераторе
Исходный код / фрагмент конфигурации
Порты — минимум один вход или один выход
Параметры — минимум один числовой параметр (или пусто)
Алгоритм — строки с read/param/state/integrate/write
Код — пусто (генератор сам подставит декоратор и SPEC)
Внешний вид — пусто (стандартный прямоугольник)
Документация — хотя бы краткое описание назначения
Практическое руководство по разработке физических компонентов объектного слоя (C-слоя) в среде моделирования ORPHYS 2.0 с помощью визуального «Генератора компонентов».
Расширенное практическое руководство по разработке физических компонентов объектного слоя (C-слоя) в среде моделирования ORPHYS 2.0 с помощью визуального «Генератора компонента».
1. Принцип работы объектного компонента
В отличие от логического блока, который «вычисляет выход из входа», физический компонент объектного слоя формирует уравнение физического закона в форме невязки:
Исходный код / фрагмент конфигурации
F(t, X, dX/dt) = 0
Здесь:
X = [V(узлы), I(ветви)] — общий вектор состояния, формируемый численным ядром, где V - потенциальная переменная (ток, расход, сила), I - потенциальная (напряжение, давление, скорость);
dX/dt — производные по времени для динамических систем;
t — текущее физическое время интегрирования.
Ядро решателя, а не компонент, вычисляет токи и потенциалы. Компонент лишь сообщает ядру, какое физическое соотношение связывает потенциалы его полюсов и поток в его ветви. Решатель синхронно находит узловые потенциалы и ветвевые потоки всей схемы методом Ньютона с LU-факторизацией разреженной матрицы Якоби (SuperLU). Поэтому вклад компонента — это одно уравнение невязки ветви для двухполюсника (плюс дополнительные уравнения для внутренних состояний и многопортовых аппаратов).
Эта особенность диктует три практических следствия:
Каждый физический закон записывается в инженерной форме «должно быть равно нулю», а не в форме присваивания.
Уравнения непрерывности потока (KCL) в узлах уже заложены в модель — их записывать не нужно, иначе система окажется переопределённой.
Динамика объявляется явно: при написании кода компонента для dP/dt или dU/dt указывается diff="nodes", для dG/dt или dI/dt — diff="branch". Без этого флага решатель не выделит производную. При разработке модели в генераторе это деалется автоматически.
2. Архитектурный контракт и общая схема регистрации
Полный путь от определения модели до видимости компонента в палитре библиотеки модели компонентов (БМК) состоит из двух уровней регистрации.
Уровень
Назначение
Артефакт
Палитра/UI
Содержит метаданные, видимые в левой панели, инспекторе свойств и подсказках.
Содержит исполняемый код невязки, регистрируется декоратором @physical.
Скомпилированный файл в bmk/....
Цепочка регистрации выглядит так:
Исходный код / фрагмент конфигурации
Генератор модели компонента
↓ Спецификация компонента + код вычисления невязки
Модуль регистрации
↓ авторегистрация в момент импорта
Реестры ядра (_RESIDUALS, _PHYSICAL_SPECS)
↓
Перезапуск клиента среды
↓
Сборка и размещение в палитре БМК
В генераторе весь этот конвейер свёрнут в одну пользовательскую операцию — кнопку «Зарегистрировать». Далее в документе описано, что именно происходит на каждой вкладке генератора.
3. Домены физики: что и почему
Объектный слой ORPHYS — акаузальный: один и тот же решатель обслуживает несколько физических доменов. Для каждого домена закреплена пара потенциальная / потоковая переменные (across/through).
Домен (domain)
Across (потенциальная)
Through (потоковая)
Типичные аппараты
electrical (по умолчанию)
Напряжение V, В
Ток I, А
Резистор, конденсатор, индуктивность, источник ЭДС, диод
Сепаратор, ректификационная колонна, теплообмен с фазовым переходом
mechanical
Скорость v, м/с
Сила F, Н
Одномерная поступательная система
mechanical_2d
Координаты (x, y, θ)
Силы и момент (F_x, F_y, M)
Плоская кинематика, манипуляторы
kinematic_3d
Пространственные (X, Y, Z)
Внутренние реакции
Пространственные шарнирные механизмы
Кроме того, домены oilgas и thermal дополнительно требуют тепловую модель (см. п. 8.4) — это профили flow_through или accumulation, которые автоматически генерируют уравнения переноса тепла/состава. Домен electrical и hydraulic обычно обходятся одной невязкой ветви без расширений.
4. Подготовка: что нужно знать до запуска генератора
Прежде чем нажимать «Запустить генератор», целесообразно зафиксировать на бумаге следующие позиции. Это сокращает число возвратов к редактированию вкладок и снижает риск переименования идентификаторов (см. п. 15).
Машинное имя (bus id): латиница, без пробелов, уникальное в пределах библиотеки. Используется решателем для сопоставления блока с функцией невязки. Не должно меняться после публикации.
Читаемое имя и обозначение на теле блока (sym) — то, что увидит пользователь в палитре и на корпусе компонента.
Список портов с указанием:
имени (машинное);
направления (in/out);
стороны (left, right, top, bottom);
физического домена.
Список параметров: имя, тип, значение по умолчанию, единица измерения, границы (для int/number).
Физический закон в инженерной форме — уравнение связи across и through для выбранного домена. Закон записывается как «разность должна быть равна нулю».
Признаки динамики: содержит ли модель производные по времени, и если да — к какой переменной они относятся (потенциалу узлов или потоку ветви).
Признак нелинейности: квадратичные потери, экспоненты, произведения неизвестных — всё это потребует nonlinear=True.
Признак многопортовости: только если на портах должны быть независимые through-переменные (тройник, многообмоточный трансформатор, общий коллектор).
Признак накоплнения среды: для нефтегазовых аппаратов потребуется выбор пресета flow_through / accumulation и входной порт для StreamProfile.
Признак опции V-слоя: какие из параметров нужно открыть как пользовательские настройки визуального слоя.
Если хотя бы один из пунктов остался неясным, см. раздел 14 «Частые сценарии» — там приведены эталонные шаблоны для типовых аппаратов.
5. Шаг 1. Запуск «Генератора компонента»
Запускаем
Запуск производится из меню «Сервис» - «Генератор компонента» основного интерфейса ORPHYS (см. архитектурное руководство, «Инженерный инструментарий» → «визуальный конструктор компонентов»).
После запуска откроется окно с набором вкладок:
Порты;
Параметры;
Невязки;
Код;
Внешний вид;
Документация.
Заполнять вкладки рекомендуется в порядке Порты → Параметры → Невязки → Код → Внешний вид → Документация — так поля более поздних вкладок получают корректные ссылки на ранние сущности.
6. Шаг 2. Вкладка «Порты»
Заполняем порты
Что здесь задаётся: интерфейс компонента, который будет виден на холсте для подключения проводов и валидации при сборке схемы. С точки зрения архитектуры это поля ports= дескриптора ComponentSpec.
Минимальные поля одной записи порта
Поле
Назначение
Пример
name
Машинное имя — уникальный идентификатор в пределах компонента. Используется в формулах невязок.
inlet, outlet, cmd, T_prod_out
dir
Направление сигнала относительно компонента: in (вход) или out (выход). Влияет только на визуализацию — на физическом уровне акаузальная модель соединяет все полюса по общему узлу.
in
side
Сторона блока, на которой рисуется вывод: left, right, top, bottom. Правильное расположение критично для читаемости схем.
left
description
Человеческое описание, отображается в инспекторе и подсказке.
«Входной патрубок, сторона продукта»
Практические замечания
Количество портов определяется физикой процесса. Для двухполюсной ветви (труба, клапан, резистор) порты два: вход и выход. Для ёмкости между двумя узлами давления — также два, для спепаратора - три. Тройник — три и так далее.
Сторону подключения к сети имеет смысл выбирать так, чтобы поток среды на схеме шёл слева направо (inlet → left, outlet → right), это согласуется с автоматическим алгоритмом расчёта размера блока.
Переименование name после публикации компонента приведёт к потере привязок в ранее сохранённых проектах, сценариях ИСУЛ и алгоритмах СГМС — это миграционно-чувствительная операция.
Если компонент реализует наполнение материи по потоковой переменной (сепаратор с удержанием массы, ректификационная колонна, теплообменник с аккумуляцией), отметьте галочки:
«Независимые расходы портов» — для многопортового аппарата, у которого потоки на портах не равны (накопитель имеет отдельный вход и отдельный выход).
«Накопитель среды» — для аппаратов с гидродинамическим удержанием массы; разрешает генерацию дифференциального уравнения накопления. Эта опция автоматически расширяет размерность DAE на одно состояние.
Расширенный сценарий: «внешние переменные»
Для аппаратов, которые будут управляться из логического слоя или читаться им (например, для АВО нужны fan_speed и T_product_out для получения от регулятора целевого значения скорости вращения и передачи текущего значения температуры продукта на выходе). Таки переменные задаются как параметры с отметкой о публикации для V-слоя. Передача данных между L- и C- уровнями осуществляется на схеме с помощью компонента "Связь с аппаратом". То есть для передачи значения параметра / переменной на V- или L- уровень не требуется заводить специальный порт, достаточно завести параметр, публикуемый для передачи данных.
7. Шаг 3. Вкладка «Параметры»
Заполняем параметры
Что здесь задаётся: коэффициенты, настройки и граничные условия компонента — поля params= дескриптора ComponentSpec и атрибуты блока attrs= в сериализации схемы.
Состав полей одной записи параметра
Поле
Назначение
name
Машинное имя атрибута, по которому параметр читается внутри невязки через c["attrs"].get("name", default).
value (default)
Значение по умолчанию. Должно быть валидным для типа.
unit
Единица измерения в свободной строковой форме: «Па/(кг/с)», «м», «об/мин». Влияет на отображение в инспекторе, на расчёт не влияет.
type
Тип данных (см. ниже).
description
Текстово описание параметра.
publish
Флаг «публиковать параметр для V-слоя». Если включён, значение выводится в визуальные виджеты (табло, графики) без дополнительных адаптеров.
Поддерживаемые типы параметров
type
Назначение
Пример
number
Вещественный скаляр (по умолчанию).
Сопротивление R = 1000.0.
int
Целое число.
Число секций теплообменника N = 12.
string
Строковый режим работы, метка или путь.
Режим АВО "ventilation".
bool
Логический флаг.
enabled = True.
combo
Выбор из фиксированного списка.
Тип рабочей жидкости (вода, нефть, газ).
array
Массив коэффициентов.
Таблично заданная характеристика насоса.
pair
Кортеж (min, max) для отображения диапазона.
Допустимые пределы давления (0, 10 МПа).
table
Таблица пар (x, y) для кусочно-линейной интерполяции.
Реализация внешней Q-H характеристики насоса.
Дифференцируемые параметры (внутренние состояния)
Для моделей с памятью (ёмкость с инерцией давления, термоаккумулятор, гистерезисный клапан) на этой же вкладке добавляются состояния (states):
name — имя состояния, доступное в формулах невязок;
default — начальное условие x(t=0);
unit, description — для инспектора;
publish — публикация состояния как метрики на V-слой.
Тепловая модель
Для компонентов теплогидравлического и нефтегазового доменов в нижней части вкладки присутствует секция «Тепловая модель» с пресетами геометрии: кожухотрубный, пластинчатый, спиральный, произвольный.
Это центральный шаг разработки компонента. Здесь формулируется математический закон, на основании которого ядро будет включать компонент в совместно решаемую DAE-систему. Ошибки в этой вкладке дают трудно диагностируемые расходимости численного решателя.
8.1. Базовая форма записи уравнения
В генераторе формула вводится как обычное математическое выражение в правой части уравнения F = 0, то есть в инженерной форме «разность, которая должна обратиться в нуль». Например, для гидравлического сопротивления:
Исходный код / фрагмент конфигурации
P_in - P_out - R * G = 0
В генераторе используется математический движок MathLive / SymPy, что позволяет:
вводить формулы визуально (WYSIWYG), в том числе с автозаменой Vdot → $\dot{V}$;
использовать автоматическое символьное дифференцирование для построения якобиана (см. п. 8.6);
проверять размерности в символьном виде (при наличии описаний единиц).
8.2. Доступные идентификаторы в формулах
В формулах допустимо использовать:
Имена портов в виде P_in, P_out, V1, V2 — те читают potential соответствующего полюса;
Имена параметров, объявленных во вкладке «Параметры»: R, tau, mu, и т.п.;
Глобальный поток ветвиG (для гидравлики/нефтегаза) или I (для электрики);
Производные: dP_dt, dG_dt — в зависимости от установленного флага diff;
Внутренние состояния (если объявлены): Pf, alarm — текущие значения; dPf_dt, dalarm_dt — их производные.
Идентификаторы портов, параметров и состояний подставляются генератором автоматически из соответствующих вкладок. Допускается также свободный ввод (объявленных, но не новых) имён.
8.3. Конститутивные уравнения для типовых доменов
В таблице ниже приведены канонические формы невязки для типовых компонентов.
$(P_{\text{in}} - P_{\text{out}}) - R_h \cdot \dot m = 0$
Гидравлическое
Регулирующий клапан
$(P_{\text{in}} - P_{\text{out}}) - \dfrac{R_{h,\text{min}}}{\text{opening}^2}\dot m = 0$
Нелинейное параметрическое
8.4. Включение динамики: флаг «дифф. переменная»
В нижней части пресетов переменных вкладки «Невязки» находится пресеты по потоковым переменным (например, dG или dP для нефтегазового домена).
Если модель содержит собственные внутренние состояния, не сводящиеся к потенциалам полюсов или сквозному потоку (см. вкладку «Параметры», секция «Дифференцируемые параметры»), их уравнения дописываются отдельной строкой в таблицу невязок.
8.5. Включение нелинейности: флаг «Нелинейная модель»
Любой компонент, чей закон сохранения содержит квадратичные потери, модули, экспоненты или произведения неизвестных (диод, клапан с квадратичным сопротивлением, насос с кубической характеристикой), должен иметь установленный флаг Нелинейная модель. Это эквивалентно nonlinear=True в декораторе и сообщает ядру о необходимости полного пересчёта матрицы Якоби и включения адаптивного демпфирования шага Ньютона.
Если установлен флаг «Аналитический якобиан», генератор с помощью SymPy выполняет символьное дифференцирование формулы по каждой неизвестной (dF/dV_in, dF/dG, dF/dt и т.п.) и встраивает полученные выражения прямо в код невязки.
Когда это помогает: жёсткие нелинейные модели и большие схемы, где численное дифференцирование по раскраске столбцов становится узким местом. Символьный якобиан сокращает количество обращений к уравнениям в 10–30 раз.
Когда это не помогает (или вредит): модели с большим числом условных переходов (if/else, разные режимы работы в зависимости от значений переменных); в этом случае аналитический якобиан придётся дописывать вручную на вкладке «Код».
8.7. Проверка и сборка
После заполнения формулы рекомендуется нажать кнопку «Проверить и собрать». Генератор в этом режиме:
Парсит выражение через SymPy и строит абстрактное синтаксическое дерево.
Проверяет, что все идентификаторы разрешены (объявлены в портах или параметрах).
Подставляет символьные значения по умолчанию и проверяет отсутствие деления на ноль в формуле.
При включённом аналитическом якобиане — выполняет символьное дифференцирование.
Генерирует код Python-функции невязки и помещает его в черновик компонента.
Если хотя бы один шаг возвращает диагностику, формула не сохранится до устранения проблем.
9. Шаг 5. Вкладка «Код» — пользовательская логика на Python
Дописываем код
На этой вкладке формируется тело функции шага на языке Python — исполняемая часть компонента, которая будет зарегистрирована через @physical(SPEC) в реестре _RESIDUALS ядра.
Здесь доступны 4 специальных XML-тега, в которые вставляется пользовательский Python-код:
Тег
Назначение
Когда использовать
<mars:user-imports>
Блок импортов сторонних пакетов.
Если используются numpy, scipy, sympy, pandas, scikit-learn, либо собственные модули.
Код для расчета невязок из вкладки "Невязки" (подставляется автоматически)
9.1. Что именно генерирует вкладка «Невязки»
По нажатию «Зарегистрировать» генератор формирует файл следующей приблизительной структуры:
Код (python)
from mars_core.acausal import physical
from mars_core.component_spec import ComponentSpec, Port, Param
SPEC = ComponentSpec(
name="hydraulic_resistor",
kind="Гидравлическое сопротивление",
layer="object",
folder="Гидравлика",
domain="hydraulic",
ports=[
Port("inlet", dir="in", side="left", domain="hydraulic"),
Port("outlet", dir="out", side="right", domain="hydraulic"),
],
params=[Param("R", 1000.0, unit="Па/(кг/с)", type="number")],
)
@physical(SPEC)
def hydraulic_resistor(c, V, I, dV, dI, t, lam):
a, b = c["nodes"]
G = I[c["id"]]
R = float(c["attrs"].get("R", 1000.0))
return (V[a] - V[b]) - R * G
Пользовательский код на вкладке «Код» — это тело функции между строкой def hydraulic_resistor(c, V, I, dV, dI, t, lam): и return .... Если специальной логики не требуется, генератор сам подставит сгенерированное return из вкладки «Невязки», и вкладку «Код» можно пропустить.
9.2. Когда нужно дописывать код вручную
Сложные многоступенчатые алгоритмы (например, итерационный расчёт тепловой характеристики АВО как функции от оборотов и температуры);
Модели с условными переходами: if P > P_critical: ...; такие модели плохо выражаются одной формулой невязки;
Вспомогательные публикации метрик: можно дополнить словарь publish_metrics (см. ниже);
Импорт специализированных численных функций (например, термодинамика библиотеки теплофизических свойств).
9.3. Расширенные сценарии кода
Публикация метрик на V-слой
Для возможности публикации значений переменных на V-слой необходимо на вкладке "Параметры" отметить галочкой чекбокс "Публикуемый". Это генерирует следующий код:
Код (python)
def publish_metrics(c, V, I, t, S):
a, b = c["nodes"]
return {
"flow_kgs": float(I[c["id"]]),
"dp_pa": float(V[a] - V[b]),
"T_prod_out_c": float(S.get("T_out", 0.0)) - 273.15,
}
@physical(SPEC, publish=publish_metrics)
def hydraulic_resistor(c, V, I, dV, dI, t, lam):
a, b = c["nodes"]
G = I[c["id"]]
R = float(c["attrs"].get("R", 1000.0))
return (V[a] - V[b]) - R * G
Использование объектного API через Elem
Для моделей с большим числом портов удобно читать потенциалы и потоки через класс Elem:
Тело функции должно быть чистым: без глобальных мутаций и без побочных эффектов. Ядро вычисляет невязки параллельно по цветам столбцов якобиана.
Запрещается print/stdout в горячем цикле (снижает производительность).
Любые пользовательские import должны находиться в шапке файла.
10. Шаг 6. Вкладка «Внешний вид» — глиф блока
Редактируем внешний вид
Здесь задаётся векторное обозначение компонента, которое будет отображаться в палитре и на холсте. Редактор глифов позволяет:
загрузить готовый SVG-файл (например, из ГОСТ-обозначений);
нарисовать блок вручную из готовых примитивов (прямоугольник, треугольник, линии, текст, точки подключения);
установить символ на теле блока (например, R, AVO, PUMP1);
привязать подписи портов к их сторонам.
Рекомендации по оформлению
Длина подписей портов — не более 8 символов (например, in, out, cmd, fan). Иначе блок придётся расширять, что нарушит читаемость схемы.
Символ на теле блока — уникальный и опознаваемый. Лучше использовать ANSI-стандартизованные обозначения для электрических компонентов (R, L, C) и единообразные сокращения для технологических (AVO, PUMP, SEP).
Точки подключения должны точно совпадать со сторонами, указанными на вкладке «Порты». Алгоритм canvas.jsx распределяет порты по вертикали с шагом 22 px, начиная с HEAD = 22 px смещения от шапки.
Что здесь задаётся: карточка-паспорт компонента, видимая в палитре, в инспекторе свойств и в режиме просмотра документации. Эти данные не влияют на расчёт, но критичны для повторного использования компонента в проектах, ИСУЛ-сценариях и при коллективной разработке.
Минимальный набор полей
Поле "Краткое описание". Что можно писать:
Аспект
Описание
Назначение
Краткое (1–2 предложения) описание того, что моделирует компонент.
Область применения
Где уместно его использовать, с указанием типовых схем.
Поле "Внешние зависимости". Здесь необходимо указывать требуемые библиотеки для работы компонента.
Поле "Связанные компоненты". Указываются компоненты, связанные с описываемым, или рабоающие с ним в связке.
Поле "Замечания". Что можно писать:
Аспект
Описание
Физические допущения
Например, «ламинарный режим течения», «несжимаемая среда», «пренебрегаем теплотой трения».
Ограничения модели
Диапазоны применимости, критичные условия (Re, ΔP, T).
Версия и автор
Кто и когда создал компонент. Используется для отслеживания изменений.
Поле "Ссылки на источники". Указывется ссылка на литературный источник, детально описывающий компонент.
Советы
Заполняйте все ограничения модели — это поможет будущим пользователям избежать ошибочных применений.
В графе «Источники» указывайте не только ГОСТ, но и конкретные формулы (см. раздел про шпаргалку нелинейных моделей в архитектурном руководстве — там приведены классические соотношения, на которые можно ссылаться).
Длинные описания допустимо выносить в отдельный PDF/Markdown и прикладывать как адрес в интернете как ссылку на источник.
12. Шаг 8. Контроль готовности и место сохранения
Перед регистрацией выполните финальную проверку:
Машинное имя компонента — латиница, без пробелов, уникальное в пределах вашей библиотеки.
Список портов соответствует физической топологии.
Список параметров содержит все необходимые для формулы идентификаторы.
Невязка записана в форме F = 0 (а не присваивания).
Флаги установлены корректно: динамика, нелинейность, материальный поток.
Глиф не выходит за рамки портов.
Паспорт заполнен, ограничения модели указаны.
Выбор папки сохранения
Компоненты публикуются в вашу пользовательскую папку, обычно:
Исходный код / фрагмент конфигурации
bmk/<domain>/<component_name>/
├── <component_name>.py # код невязки и ComponentSpec
├── <component_name>.tex # документация (паспорт)
├── glyph.svg # внешний вид (опционально)
└── tests/
└── test_<component_name>.py # юнит-тесты (опционально)
13. Шаг 9. Регистрация и проверка появления в БМК
Находим компонент в БМК
По нажатию кнопки «Зарегистрировать» генератор выполняет последовательность операций, описанных в архитектурном руководстве (раздел «Генератор компонентов», шаги 7–11):
Сохранение исходников в папку, выбранную на предыдущем шаге. Генерируются:
<name>.py — код компонента с ComponentSpec и декоратором @physical;
<name>.tex — документация паспорта;
glyph.svg — глиф (если был задан);
test_<name>.py — заготовка юнит-теста.
Вызов регистратора — компилирует код, импортирует модуль и регистрирует блок в реестрах REGISTRY, _RESIDUALS, _PHYSICAL_SPECS. Это возможно без перезапуска сервера (исполняемого приложения ORPHYS).
Генерация записи catalog.json с метаданными для палитры.
Сборка обновлённого клиентского каталога:
Пересборка production-бандла (по необходимости):
Запуск автотестов:
Визуальная проверка в браузере (ручная): компонент должен появиться в папке палитры, указанной при создании, и перетаскиваться на холст соответствующего слоя.
Как убедиться, что регистрация прошла успешно
В дереве палитры отображается новая папка/иконка с указанным обозначением.
В инспекторе свойств все параметры видны с правильными единицами.
При запуске минимальной пробной схемы с этим компонентом (источник → компонент → сток) расчёт не падает с ошибкой размерности или сингулярности.
14. Частые сценарии настройки невязок
Здесь приведены примеры кода компонентов объектного уровня.
14.1. Простое гидравлическое сопротивление
Линейная потеря давления. Один скаляр невязки ветви.
Код (python)
SPEC = ComponentSpec(
name="hydraulic_resistor",
kind="Гидравлическое сопротивление",
sym="RES",
body="RES",
render="block",
layer="object",
folder="Гидравлика",
domain="hydraulic",
ports=[
Port("inlet", dir="in", side="left", domain="hydraulic"),
Port("outlet", dir="out", side="right", domain="hydraulic"),
],
params=[Param("R", 1000.0, unit="Па/(кг/с)")],
)
@physical(SPEC)
def hydraulic_resistor(c, V, I, dV, dI, t, lam):
a, b = c["nodes"]
G = I[c["id"]]
R = float(c["attrs"].get("R", 1000.0))
return (V[a] - V[b]) - R * G
Поле «Невязки» генератора: P_in - P_out - R * G. Флаги: динамика «нет», нелинейность «нет».
14.2. Гидравлический трубопровод по Хагену — Пуазёйлю
Ламинарный режим:
$$ \Delta P = \frac{128 \mu L G}{\pi \rho d^4} $$
Код (python)
SPEC = ComponentSpec(
name="laminar_pipe",
kind="Трубопровод ламинарный",
layer="object", folder="Гидравлика", domain="hydraulic",
ports=[
Port("inlet", dir="in", side="left"),
Port("outlet", dir="out", side="right"),
],
params=[
Param("L", 100.0, unit="м"),
Param("d", 0.015, unit="м"),
Param("rho", 998.0, unit="кг/м³"),
Param("mu", 1.0e-3, unit="Па·с"),
],
)
@physical(SPEC)
def laminar_pipe(c, V, I, dV, dI, t, lam):
a, b = c["nodes"]
attrs = c["attrs"]
G = float(I[c["id"]])
L = float(attrs.get("L", 100.0))
d = float(attrs.get("d", 0.015))
rho = float(attrs.get("rho", 998.0))
mu = float(attrs.get("mu", 1.0e-3))
dp = 128.0 * mu * L * G / (pi * rho * (d ** 4))
return (V[a] - V[b]) - dp
Поле «Невязки»: P_in - P_out - 128 * mu * L * G / (pi * rho * d**4). Флаги: динамика «нет», нелинейность «нет».
14.3. Гидравлическая ёмкость (diff="nodes")
Ёмкость с накоплением среды; поток ветви выражается через производную давления.
Код (python)
SPEC_CAPACITY = ComponentSpec(
name="hydraulic_capacity",
kind="Гидравлическая емкость",
layer="object", folder="Гидравлика", domain="hydraulic",
ports=[
Port("a", dir="in", side="left"),
Port("b", dir="out", side="right"),
],
params=[Param("C_h", 1.0e-5, unit="кг·с²/м⁵")],
)
@physical(SPEC_CAPACITY, diff="nodes")
def hydraulic_capacity(c, V, I, dV, dI, t, lam):
a, b = c["nodes"]
G = I[c["id"]]
C_h = float(c["attrs"].get("C_h", 1.0e-5))
return G - C_h * (dV[a] - dV[b])
Поле «Невязки»: G - C_h * (dP_in_dt - dP_out_dt). Флаг: дифф. переменная «по узлам».
Поле «Невязки» генератора содержит три строки; количество уравнений = числу портов. Галочка «Независимые расходы портов» установлена.
15. Типичные ошибки и их диагностика
Симптом
Вероятная причина
Решение
TypeError: takes 1 positional argument but 7 were given
Тело функции записано как @physical(SPEC) def body(elem): ... напрямую.
Реализовать функцию _body(elem) и вызвать её через согласующий адаптер с сигнатурой (c, V, I, dV, dI, t, lam).
Компонент гидравлики ведёт себя как электрический
Не указан domain="hydraulic" в ComponentSpec. По умолчанию действует domain="electrical".
Явно задать domain="hydraulic" и тот же домен в портах Port(..., domain="hydraulic").
Для двух портов возвращается вектор из 2 уравнений и расчёт падает
Ошибочное отождествление количества графических контактов с параметром ports=2.
Возвращать одиночный скаляр; ports=M указывать только при M независимых потоках.
Попытка записать G_in - G_out = 0 в невязку ветви
Уравнение непрерывности уже заложено в MNA.
Записывать только собственное конститутивное уравнение связи потенциала и потока.
Использование расхода в м³/с без учёта плотности
В домене hydraulic через G передаётся массовый расход в кг/с.
Вводить формулу преобразования $Q_v = G / \rho$.
Нелинейное сопротивление не сходится
Забыт флаг nonlinear=True (или «Нелинейная модель» в генераторе).
Всегда устанавливать «Нелинейная модель» при наличии нелинейностей.
Мутация внутренних словарей внутри невязки вызывает сбои
Побочные эффекты нарушают параллелизм по раскраске столбцов.
Функция невязки обязана быть чистой: только чтение входов и возврат скаляра/списка.
Сообщение «Нет опоры: добавьте Землю / Источник / Приёмник»
В схеме отсутствует элемент с фиксированным потенциалом $V_0=0$.
В электрической цепи добавить блок «Земля»; в гидравлике — блоки «Источник» (FEED) или «Приёмник» (SINK).
Решатель дробит шаг до минимума и расчёт не идёт
Аналитическая характеристика крутая, решатель не успевает сходиться.
Уменьшить шаг интегрирования h или включить автоматический метод (solve_adaptive); включить гомотопию λ.
Компонент не появляется в палитре
Код не зарегистрирован ни в _PHYSICAL_SPECS, ни в REGISTRY.
Запустить Python с MARS_DEBUG_LOAD=1 для подробного журнала сканирования библиотеки; убедиться, что файл лежит в models_and_tests/models_library/ или импортирован явно.
Конфликт имён с уже существующим компонентом
Машинное имя не уникально.
Переименовать компонент (новое имя должно быть уникальным во всём реестре).
После переименования порта старые проекты перестали открываться
Машинные имена интерфейса — неизменяемый контракт API.
Не переименовывать name у Port и Param после публикации; при необходимости миграции — добавлять новые порты, оставляя старые для обратной совместимости.
16. Приёмочные испытания после регистрации
После того как компонент зарегистрирован, до передачи его другим пользователям имеет смысл выполнить серию проверок. Это требование совпадает с «Методикой проверки и изолированного тестирования» из архитектурного руководства.
16.1. Проверка автоматической регистрации в реестрах ядра
Код (python)
import mars_core.component_host
from mars_core.acausal import _PHYSICAL_SPECS, _RESIDUALS
assert "hydraulic_resistor" in _PHYSICAL_SPECS
assert "hydraulic_resistor" in _RESIDUALS
Если одно из утверждений падает, декоратор @physical не сработал. Самая частая причина — синтаксическая ошибка в сгенерированном .py файле или отсутствие импорта модуля.
16.2. Численное базовое тестирование невязки
Подставьте искусственные словари V и I, при которых уравнение аналитически выполняется, и проверьте близость невязки к нулю:
Код (python)
c = {"id": "p1", "nodes": [1, 2],
"attrs": {"L": 100.0, "d": 0.015, "rho": 998.0, "mu": 1e-3}}
V = {1: 150000.0, 2: 100000.0} # ΔP = 50 000 Па
# Аналитическое решение для ламинарного течения:
G_exact = 50000.0 * pi * 998.0 * (0.015 ** 4) / (128 * 1e-3 * 100.0)
res = laminar_pipe(c, V, {"p1": G_exact}, {}, {}, 0.0, 1.0)
assert abs(res) < 1e-9, f"Невязка должна быть ≈ 0, получено {res}"
16.3. Интеграционный тест на схеме
Соберите минимальную проверочную схему (по образцу из архитектурного руководства):
Исходный код / фрагмент конфигурации
Источник FEED → [Ваш компонент] → Приёмник SINK
Запустите расчёт в статике (DC) и убедитесь:
расчёт завершается без ошибок;
баланс расходов сходится с точностью не хуже относительной погрешности Ньютона (tol ≈ 1e-9 по умолчанию);
на графике метрик отображается физически адекватная траектория (без скачков, монотонная там, где ожидается).
Затем запустите расчёт в переходном режиме (Transient) и убедитесь в отсутствии осцилляций, вызванных численной неустойчивостью.
16.4. Регрессионное тестирование в pytest
Поместите тесты в tests/test_<имя_компонента>.py для запуска в CI/CD. Тесты должны покрывать:
успешную регистрацию (_PHYSICAL_SPECS);
аналитический баланс при известных значениях;
реакцию на переключение режимов (diff, nonlinear).
17. Управление жизненным циклом: обновление и удаление
Обновление значений параметров по умолчанию
Изменения значений по умолчанию безопасны: они влияют только на вновь размещаемые блоки. Уже размещённые блоки хранят свои значения в attrs каждого экземпляра.
Переименование машинного имени порта или параметра
Если переименование неизбежно:
Добавьте новое имя как алиас, оставив старое в ComponentSpec (через «совместимое имя» — поддерживается в новых версиях SDK);
Обновите все проекты через миграционный скрипт;
Только после этого удаляйте старое имя.
Изменение количества портов
Добавление нового порта — относительно безопасная операция, если:
новый порт опционален и совместим со старой топологией;
существующие подключения продолжают работать без правки формулы.
Удаление существующего порта ломает все схемы, в которых он использовался. Требуется миграция.
Удаление компонента из библиотеки
Удалите файлы из bmk/<component>/.
Запустите среду моделирования.
Убедитесь, что все активные проекты больше не содержат экземпляров компонента (иначе — ошибка валидатора при загрузке).
При наличии опубликованных проектов выполните миграцию на заменяющий компонент.
18. Краткая шпаргалка
18.1. Минимальный обязательный набор полей в генераторе
Исходный код / фрагмент конфигурации
Порты — минимум 1 порт (in / out)
Параметры — минимум один числовой параметр (или без них)
Невязки — формула в форме F = 0
Код — пусто (генератор сам подставит return)
Внешний вид — пусто (стандартный прямоугольник)
Документация — хотя бы краткое описание назначения
Шаг 5 (код) → «Высокопроизводительный C++ SDK» (при необходимости расширения на C++).
Шаги 8–9 (контроль и регистрация) → «Двухуровневая природа регистрации».
Шаг 16 (приёмочные испытания) → «Методика проверки и изолированного тестирования» и «Сводная матрица типичных ошибок».
Раздел 11
Справочник компонентов библиотеки
Полный каталог паспортов компонентов среды моделирования ORPHYS с описанием назначения, портов, параметров, математической модели и алгоритма работы. Поиск работает по Ctrl+K (глобальный) и по полю «Поиск компонента» (локально).
Поиск компонента
Слой модели
Тип
Категория
Найдено компонентов:0
Вращ. пара OX
kpbx
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Вращательная кинематическая пара: поворот вокруг оси $OX$ на
угол $\alpha$ (переменный). Действует на плоскость $(X, Z)$:
$Y_2 = Y_1$, $X_2 = X_1$, $Z_2, X_2$ — преобразуются
матрицей поворота вокруг $X$ на угол $\alpha$. Используется
в кинематических цепях как «сочленение» (revolute joint),
базовый элемент манипуляторов и механических рук.
SPEC.folderkinematic3d/
Папкаkinematic3d/
Типфизический
Уровеньobject
Доменkinematic\_3d
body$\circlearrowright\mathrm{X
Связи компонента (порты)
p_out
out
kinematic_3d
Выходное сочленение
Не применимо.
Параметры и состояние
Состояния и интегрирование
Собственных состояний нет.
Математическая модель
Невязки (Таблица 1, буквально: действует на плоскость
$(X, Z)$; $Y_2 = Y_1$):
\[
\begin{aligned}
F_0 &= X_{\text{out}} - X_{\text{in}}, \\
F_1 &= Y_{\text{out}} - Y_{\text{in}}, \\
F_2 &= Z_{\text{out}} - (Z_{\text{in}} \cos\alpha + X_{\text{in}} \sin\alpha).
\end{aligned}
\]
(Полная матрица поворота в 3D даёт дополнительные
нелинейные члены; placeholder chain-режима возвращает
[0.0, 0.0] — реальное преобразование
выполняется в kinematic_chain.)
Алгоритм работы
См. zvx; отличие — фабрика
make_rotational_spec("kpbx", ..., "x").
Связанные компоненты
kpby, kpbz — вращательные пары
вокруг OY/OZ;
zv*, kpc* — звенья и
поступательные пары.
Вращ. пара OY
kpby
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Вращательная кинематическая пара: поворот вокруг оси $OY$ на
угол $\alpha$ (переменный). Действует на плоскость $(Y, Z)$:
$X_2 = X_1$, $Y_2 = Y_1$, $Y_2, Z_2$ — преобразуются
матрицей поворота вокруг $Y$ на угол $\alpha$. Аналог
kpbx с заменой оси.
См. kpbx; отличие — фабрика
make_rotational_spec("kpby", ..., "y").
Связанные компоненты
См. kpbx, kpbz.
Вращ. пара OZ
kpbz
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Вращательная кинематическая пара: поворот вокруг оси $OZ$ на
угол $\alpha$ (переменный). Действует на плоскость $(X, Y)$:
$Z_2 = Z_1$, $X_2, Y_2$ — преобразуются матрицей
поворота вокруг $Z$ на угол $\alpha$. Аналог kpbx с
заменой оси.
См. kpbx; отличие — фабрика
make_rotational_spec("kpbz", ..., "z").
Связанные компоненты
См. kpbx, kpby.
Звено OX
zvx
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Звено постоянной длины $L$, направленное вдоль оси $OX$ —
ограничение: $X_1 = X_2 + L$, $Y_1 = Y_2$, $Z_1 = Z_2$. Часть
кинематической 3D-библиотеки (домен kinematic_3d,
топология chain). Используется для сборки
трёхмерных кинематических цепей (рука робота, манипулятор,
платформа Стюарта) из типовых элементов. Реальное вычисление
позиций — в mars_core.kinematic_chain.evaluate_
kinematic_chain, чистая прямая кинематика; этот компонент
регистрирует только каталожный дескриптор (ComponentSpec) и
placeholder-невязки (топология chain исключает их
из обычного Newton-цикла).
SPEC.folderkinematic3d/
Папкаkinematic3d/
Типфизический
Уровеньobject
Доменkinematic\_3d
body$\mathrm{L\,(X)
Связи компонента (порты)
p_out
out
kinematic_3d
Выходное сочленение
Не применимо.
Параметры и состояние
Состояния и интегрирование
Собственных состояний нет.
Математическая модель
Невязки (в MultibodySolver):
\[
\begin{aligned}
F_0 &= X_{\text{out}} - (X_{\text{in}} + L), \\
F_1 &= Y_{\text{out}} - Y_{\text{in}}, \\
F_2 &= Z_{\text{out}} - Z_{\text{in}}.
\end{aligned}
\]
В режиме placeholder (chain-топология) возвращается
[0.0, 0.0, 0.0] — реальная кинематика считается
вне этого блока.
Алгоритм работы
Спецификация собирается фабрикой
make_link_spec("zvx", ..., "x").
Регистрация placeholder через
register_chain_component(SPEC) — всегда
возвращает [0.0, 0.0].
Связанные компоненты
zvy, zvz — аналоги вдоль OY/OZ;
kpcy, kpcz — поступательные пары
вдоль OY/OZ (для переменной длины);
kpby, kpbz — вращательные пары
вокруг OY/OZ.
Звено OY
zvy
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Звено постоянной длины $L$, направленное вдоль оси $OY$ —
ограничение: $Y_1 = Y_2 + L$, $X_1 = X_2$, $Z_1 = Z_2$. Полный
аналог zvx с заменой оси. Используется в тех же
сценариях (рука робота, манипулятор), но с направлением
звена по Y.
См. zvx; отличие — в фабрике
make_link_spec("zvy", ..., "y") и в
соответствующих невязках.
Связанные компоненты
zvx, zvz — аналоги вдоль OX/OZ;
kpcx, kpcz, kpbx,
kpbz — пары.
Звено OZ
zvz
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Звено постоянной длины $L$, направленное вдоль оси $OZ$ —
ограничение: $Z_1 = Z_2 + L$, $X_1 = X_2$, $Y_1 = Y_2$. Полный
аналог zvx с заменой оси на OZ.
См. zvx; отличие — в фабрике
make_link_spec("zvz", ..., "z").
Связанные компоненты
См. zvx, zvy.
Пост. пара OX
kpcx
Объектный
физическийkinematic\_3dkinematic3dkinematic3d/
Поступательная кинематическая пара: сдвиг вдоль оси $OX$ с
переменной величиной $L$. Ограничения: $Y_1 = Y_2$,
$Z_1 = Z_2$; $X_1 = X_2 + L$ ($L$ — переменная, может
меняться во времени). Используется в кинематических цепях
как «слайдер» (линейный привод без вращения), обычно в
паре со звеньями zv* и вращательными парами
kpb*.
См. kpcx; отличие — фабрика
make_translational_spec("kpcz", ..., "z").
Связанные компоненты
См. kpcx, kpcy.
Демпфер
damper
Объектный
физическийmechanicalМеханика 2Dmechanical/
Физическая (acausal) модель линейного вязкого демпфера:
$F = c v$, где $F$ — сила сопротивления, $v$ — скорость.
Используется в системах с потерями (масса-пружина-демпфер —
классическая колебательная система с затуханием) и как
элемент трения между двумя телами.
SPEC.folderМеханика 2D
Папкаmechanical/
Типфизический
Уровеньobject
Доменmechanical
bodyc
Связи компонента (порты)
Не применимо.
Параметры и состояние
Состояния и интегрирование
Собственных states=[...] нет.
Математическая модель
Невязка ветви:
\[
F = I[\texttt{id}] - c \cdot V[p]
\]
(при $F = 0$: $F = c v$ — линейное вязкое трение).
Алгоритм работы
p, _ = c["nodes"]; c_damp из
attrs.
F = I[c["id"]], v = V[p].
Вернуть $F - c_{\text{damp}} \cdot v$.
Связанные компоненты
См. mass, spring.
Масса
mass
Объектный
физическийmechanicalМеханика 2Dmechanical/
Физическая (acausal) модель инерционной массы — сосредоточенного
тела, к которому приложена внешняя сила. Реализует 2-й закон
Ньютона в форме $m \cdot dv/dt = F$ для узла $p$ (скорость)
и тока компонента (сила). Используется как базовый элемент
сосредоточенных механических моделей (масса на пружине,
масса-демпфер), а также в системах с одной степенью свободы
(модель маятника без жёсткости).
Невязка ветви:
\[
F = m \cdot \dot V[p] - I[\texttt{id}]
\]
(при $F = 0$: $m \cdot dv/dt = F$ — 2-й закон Ньютона).
Алгоритм работы
p, _ = c["nodes"]; m из
attrs.
F = I[c["id"]] (сила, действующая на массу).
Вернуть невязку
$m \cdot dV[p] - F$.
Связанные компоненты
spring, damper — базовые
механические элементы, соединяемые с массой;
multibody/body_2d — 2D-обобщение массы.
Ползун
slider
Объектный
физическийmechanical\_2dМеханика 2Dmultibody/
Физическая связь «ползун»: фиксирует одну координату тела
($\mathrm{axis} \in \{x, y, \theta\}$) на заданном значении
$\mathrm{value}$. Невязка — линейная: $\mathrm{coord} - \mathrm{value} = 0$. Используется для «заземления» тел
(фиксация одной координаты), для направляющих (ползун
движется только по $x$ или только по $y$), для ограничения
ориентации ($\theta = \mathrm{const}$). Демонстрация
паттерна «двойная» функция (см. hinge,
rod).
SPEC.folderМеханика 2D
Папкаmultibody/
Типфизический
Уровеньobject
Доменmechanical\_2d
bodyaxis,\;value
Связи компонента (порты)
Не применимо.
Параметры и состояние
Входные параметры
value
$0.0$
м/рад
number
Целевое значение координаты
body
«»
—
text
Имя тела
Состояния и интегрирование
Собственных состояний нет.
Математическая модель
Невязка:
\[
F = \mathrm{coord}_{\text{axis}}(\mathrm{body}) - \mathrm{value}
\]
где $\mathrm{coord}_{\text{axis}}$ —
соответствующая координата из
S["<axis>_<body>"].
Алгоритм работы
Считать axis, value, body
из c["attrs"].
key = f"\{axis\}_\{body\}";
coord = S[key].
return [coord - value].
return [0.0] (MultibodySolver делает
реальное вычисление).
Связанные компоненты
См. hinge, rod, body_2d.
Пружина
spring
Объектный
физическийmechanicalМеханика 2Dmechanical/
Физическая (acausal) модель линейной пружины (закон Гука) с
внутренним состоянием — координатой $x$. Реализует две
связанные невязки: $F = k x$ (сила упругости) и
$\dot x = v$ (связь координаты и скорости). Используется в
сосредоточенных механических системах (масса-пружина-демпфер,
пружинный маятник) и как элемент «упругого звена» между
двумя телами.
SPEC.folderМеханика 2D
Папкаmechanical/
Типфизический
Уровеньobject
Доменmechanical
bodyk
Связи компонента (порты)
Не применимо.
Параметры и состояние
Состояния и интегрирование
Внутренние состояния:
x (diff) — координата пружины
(удлинение/сжатие), м.
Также дифференцируются узловые переменные ($V[p]$).
Математическая модель
Возвращаемый вектор невязок:
\[
\begin{aligned}
F_0 &= I[\texttt{id}] - k \cdot x, \\
F_1 &= \dot x - V[p].
\end{aligned}
\]
(при $F_0 = F_1 = 0$: $F = k x$, $\dot x = v$).
Алгоритм работы
p, _ = c["nodes"]; k из attrs.
F = I[c["id"]], v = V[p].
Вернуть список
$[F - k \cdot S[\texttt{"x"}],\; dS[\texttt{"x"}] - v]$.
Связанные компоненты
mass, damper — другие
сосредоточенные механические элементы;
Стержень
rod
Объектный
физическийmechanical\_2dМеханика 2Dmultibody/
Физическая связь «жёсткий стержень» между двумя 2D-телами:
расстояние между ними фиксировано и равно $L$. Невязка —
нелинейная: $\sqrt{(x_B - x_A)^2 + (y_B - y_A)^2} - L = 0$. Используется в рычажных механизмах, маятниках с жёсткой
связью, в «сочленённых» механизмах. Демонстрация паттерна
«двойная» функция (rod_residual(S, c) +
rod_residual_physical), как у hinge.
SPEC.folderМеханика 2D
Папкаmultibody/
Типфизический
Уровеньobject
Доменmechanical\_2d
bodyL
Связи компонента (порты)
Не применимо.
Параметры и состояние
Входные параметры
body_a
«»
—
text
Имя тела A
body_b
«»
—
text
Имя тела B
Состояния и интегрирование
Собственных состояний нет.
Математическая модель
Невязка (длина, нелинейная):
\[
F = \sqrt{(x_B - x_A)^2 + (y_B - y_A)^2} - L
\]
В MultibodySolver это даёт алгебраическую переменную
$R$ — силу реакции стержня (вдоль оси $A B$).
Алгоритм работы
Считать $L$, body_a, body_b из
c["attrs"].
Считать позиции из
S["x_<body>"], S["y_<body>"].
return [sqrt(dx² + dy²) - L].
L из c["attrs"];
return [0.0] (MultibodySolver делает
реальное вычисление).
Связанные компоненты
См. hinge, slider, body_2d.
Тело 2D
body_2d
Объектный
физическийmechanical\_2dМеханика 2Dmultibody/
Физическое 2D-тело (точечная масса с моментом инерции) в
плоскости: 3 степени свободы ($x, y, \theta$), 3 скорости
($v_x, v_y, \omega$), 3 ускорения. Реализует уравнения
Даламбера в форме: $m \dot v_x = F_x$, $m \dot v_y = F_y$,
$I \dot \omega = M$. Используется как базовое тело в
2D-механизмах (манипуляторы, рычажные системы, многозвенники)
с MultibodySolver.
Вернуть список
$[d\dot v_x - F_x/m,\; \dot v_y - F_y/m,\; \dot \omega - M/I]$.
Связанные компоненты
hinge, rod, slider —
2D-связи между телами;
mass — 1D-аналог (одна степень свободы).
Шарнир
hinge
Объектный
физическийmechanical\_2dМеханика 2Dmultibody/
Физическая связь между двумя 2D-телами в одной точке: позиции
(со смещениями offset_a и offset_b) и
ориентации тел совпадают. Три линейных невязки:
\[
\begin{aligned}
x_B + \mathrm{off}_{B,x} - (x_A + \mathrm{off}_{A,x}) &= 0, \\
y_B + \mathrm{off}_{B,y} - (y_A + \mathrm{off}_{A,y}) &= 0, \\
\theta_B - \theta_A &= 0.
\end{aligned}
\]
Используется как универсальное соединение двух тел
(эквивалент ball-joint в 2D, без вращательной свободы).
Демонстрация паттерна «двойная» функция: чистый
hinge_residual(S, c) для прямого тестирования и
hinge_residual_physical как placeholder для
интеграции в MultibodySolver.
SPEC.folderМеханика 2D
Папкаmultibody/
Типфизический
Уровеньobject
Доменmechanical\_2d
Связи компонента (порты)
Не применимо.
Параметры и состояние
Входные параметры
body_b
«»
—
text
Имя тела B
offset_a
$(0, 0)$
м
tuple
Смещение точки шарнира на теле A
offset_b
$(0, 0)$
м
tuple
Смещение точки шарнира на теле B
Состояния и интегрирование
Собственных состояний нет — это связь-constraint, не
динамический элемент.
Считать body_a, body_b, offset_a, offset_b
из c["attrs"].
Считать позиции тел из
S["x_<body>"], S["y_<body>"], S["theta_<body>"].
Вернуть список из 3 невязок.
Вернуть [0.0, 0.0, 0.0] (MultibodySolver
обрабатывает реальное вычисление).
Связанные компоненты
body_2d — 2D-тела, соединяемые
шарниром;
rod, slider — другие
2D-связи.
Тестовый насос
pump_test
Объектный
физический, сгенерированныйoilgasМои компоненты
Тестовый компонент на примере модели насоса со стабильным дифференциальным давлением
SPEC.folderМои компоненты
Типфизический, сгенерированный
Уровеньobject
Доменoilgas
symТест
Связи компонента (порты)
outlet
out
oilgas
Не применимо.
Параметры и состояние
Состояния и интегрирование
Внутренние состояния не зарегистрированы (states=[]).
Связанные компоненты
Не указаны.
Drum
drum
Объектный
физическийoilgasНефтегазовые аппаратыoilgas/drum/
Трёхпортовый нефтегазовый барабан-ёмкость с полной
термодинамикой (жидкость+газ, многокомпонентная смесь),
построенный на mars_core.thermoprop (CoolProp или
другой backend). Поддерживает геометрию (плоскодонный
цилиндр), штуцеры (inlet, drain, vent) с учётом уровня
жидкости, инициализацию по $P_{\text{init}}, T_{\text{init}}$,
доле заполнения и составу; публикует результат флэша в
attrs["_pub"] для downstream-клапанов и UI. Внутри
компонент выделен в класс Drum с фазами
(DrumPhases) и кэшем флэша (LRU по
(P, T, trial)). Используется как типовая ёмкость
для нефтегазовых цепей (сепараторы, барабаны-аккумуляторы,
сборники).
SPEC.folderНефтегазовые аппараты
Папкаoilgas/drum/
Типфизический
Уровеньobject
Доменoilgas
symD
bodyD
Связи компонента (порты)
drain
out
bottom
Штуцер дренажа (низ ёмкости)
vent
out
top
Штуцер сдувки (верх ёмкости)
Across — давление (Па), through — массовый поток (кг/с).
KCL на каждом штуцере связывает ток компонента с расходом
клапана, стоящего на этом штуцере.
Не применимо.
Параметры и состояние
Входные параметры
H
$1.0$
м
number
Высота корпуса
nozzle_radius
$0.1$
м
number
Радиус штуцеров
drain_elevation
$0.0$
м
number
Отметка дренажного штуцера
vent_elevation
$1.0$
м
number
Отметка штуцера сдувки
fill
$0.10$
доля
number
Начальный налив (доля объёма)
P_init
$101325$
Па
number
Начальное давление
T_init
$293.15$
К
number
Начальная температура
components
«Water:1.0»
—
composition
Состав жидкой фазы
gas_components
«Nitrogen:1.0»
—
composition
Состав газовой фазы
backend
«auto»
—
string
thermoprop backend
eos
«HEOS»
—
string
Модель уравнения состояния
heater_power_W
$0.0$
Вт
number
Мощность нагревателя
heater_off_t
$0.0$
с
number
Момент отключения нагревателя
Состояния и интегрирование
Внутренние состояния:
N_liq (diff) — отклонение
количества жидкости от init (моль).
N_gas (diff) — отклонение
количества газа от init (моль).
U (diff) — отклонение
внутренней энергии от init (Дж).
T (alg) — алгебраическая
температура (К, определяется из флэша).
Узловые дифф. переменные (diff="nodes"): давление
в штуцере inlet. Метод интегрирования — неявный Эйлер /
Ньютон, выполняемый ядром.
Математическая модель
Возвращаемый вектор невязок (в порядке индексов):
\[
\begin{aligned}
F_0 &=
\mathrm{pressure\_closure}(P_{\text{abs}}, S), \\
F_1 &=
\frac{V[\texttt{drain}] - (P_{\text{abs}} + \rho g h_{\text{drain}})}
{\max(|P_{\text{abs}}| V_{\text{tank}}, 1)}, \\
F_2 &=
\frac{V[\texttt{vent}] - (P_{\text{abs}} + \rho g h_{\text{vent}})}
{\max(|P_{\text{abs}}| V_{\text{tank}}, 1)}, \\
F_3 &= \dot N_{\text{liq}} - \mathrm{liq\_net}, \\
F_4 &= \dot N_{\text{gas}} - \mathrm{gas\_net}, \\
F_5 &= \dot U - (\mathrm{energy\_net} + Q_{\text{heater}}), \\
F_6 &= \frac{S[\texttt{"U"}] - U_{\text{calc}}}
{\max(|U_{\text{calc}}|, 1)}.
\end{aligned}
\]
$h_{\text{drain}} = \max(\mathrm{level} - \mathrm{drain\_elevation}, 0)$, аналогично для vent;
$\mathrm{liq\_net}/\mathrm{gas\_net}$ складываются из
вкладов штуцеров с учётом фазы и состава; $Q_{\text{heater}} = \mathrm{heater\_power\_W}$, пока $t < \mathrm{heater\_off\_t}$.
Внимание: для Ньютона $F_0$ нормализуется
$\frac{V_{\text{gas}} - m_{\text{gas}}/\rho_{\text{gas}}} {V_{\text{tank}}}$, что эквивалентно газовому закону
с поправкой на уровень; при превышении объёма жидкости
$V_{\text{liq}}^{\text{ideal}} > V_{\text{tank}}$ используется
линейный отклик давления
$P_{\text{expected}} = 101325 + K_{\text{bulk}} (V_{\text{liq}}^{\text{ideal}} - V_{\text{tank}})/V_{\text{tank}}$ с $K_{\text{bulk}} = 5 \cdot 10^7$.
ctx = attrs["_ctx"] (lazy init при первом
вызове: создаёт FlatBottomCylinder,
NozzleFitting-и для drain/vent,
MediumWrapper, инициализирует
$N^{\text{init}}, U^{\text{init}}$).
P_abs = V[n_in].
T = S["T"] (из алгебраического состояния,
warm-start: $T_{\text{init}}$).
state = self.state_from_solver(P_abs, S,
trial=True): флэш по $(P_{\text{abs}}, T)$ через
ctx._make_medium, phase_state
(с LRU-кэшем); state содержит уровень,
$V_{\text{liq}}^{\text{ideal}}$, фазы штуцеров,
гидростатический напор.
_publication_from_state(state) →
attrs["_pub"] для downstream и UI.
Аппарат воздушного охлаждения (АВО) — двухполюсник
acausal-цепи: гидравлика ($\Delta P = R_h \cdot \dot m$) +
термобаланс с воздухом (NTU/LMTD, рециркуляция воздуха
через жалюзи). Термосвойства продукта ($\rho$, $h$, $c_p$,
$\mu$, $\lambda$) берутся ИЗ ПОРТА product_in.medium
(НЕ из атрибутов — без silent fallbacks). Воздушная
сторона — граничные скаляры ($T_{\text{air}}$,
$G_{\text{air}}$, $P_{\text{air}}$, влажность), как и
c_motor у насоса: не acausal-порт, а параметры.
Использует новый стрим-стек (MaterialStream,
MixPort). Внутри компонент выделен в класс
AirCooler с геометрией (geo: трубный пучок +
оребрение), гидравликой и внутренним fsolve-балансом
для двух уравнений (теплосъём, расход воздуха).
Примечание: для промышленной модели RericTubeBundle
(C++ GPA) используется отдельный тип avo_reric;
данный компонент не использует её.
SPEC.folderНефтегазовые аппараты
Папкаoilgas/air_cooler/
Типфизический
Уровеньobject
Доменoilgas
symАВО
bodyАВО
Связи компонента (порты)
product_out
out
right
Выход охлаждённого продукта
Across — давление (Па), through — массовый поток
(кг/с). $I > 0$ — поток в естественном направлении.
Не применимо. Воздушная сторона — граничные
скаляры (T_air_in, G_air_in_h, P_air,
air_humidity, natural_convection), а не порты.
Параметры и состояние
Входные параметры
T_air_in
$299.15$
К
number
Температура воздуха на входе
G_air_in_h
$144224$
кг/ч
number
Номинальный расход воздуха
P_air
$101325$
Па
number
Атмосферное давление
air_humidity
$0.8$
—
number
Влажность (доля, 0..1)
natural_convection
$0.03$
—
number
Коэф. естественной конвекции
n_bays
$2.0$
—
number
Количество аппаратов
n_bundles
$2.0$
—
number
Пучков на аппарат
n_fans
$2.0$
—
number
Вентиляторов на аппарат
n_tubes
$344$
—
number
Труб в одном пучке
L
$9.0$
м
number
Длина трубы
d_in
$0.02118$
м
number
Внутренний диаметр трубы
d_out
$0.0254$
м
number
Наружный диаметр трубы
n_strokes
$4$
—
int
Число ходов труб
n_rows
$8$
—
number
Количество рядов
fin_d
$0.05715$
м
number
Диаметр ребра
fin_thickness
$0.0004$
м
number
Толщина ребра
fins_per_m
$393$
1/м
number
Число рёбер на метр
fouling_factor
$0.0007$
м²·К/Вт
number
Сопротивление загрязнений
temp_head_correction
$1.0$
—
number
Коррекция температурного напора
thermal_efficiency
$1.0$
—
number
Коэф. тепловой эффективности
wall_conductivity
$500$
Вт/(м·К)
number
Теплопроводность стенки
air_nu_c
$0.15$
—
number
Коэф. геометрии пучка C
air_re_exp
$0.5$
—
number
Показатель Рейнольдса m
air_area
$45.89$
м²
number
Площадь сечения воздуха
narrow_coef
$0.453$
—
number
Коэф. загромождения
product_viscosity_fallback
$1.2\!\cdot\!10^{-4}$
Па·с
number
Вязкость (резерв)
product_conductivity_fallback
$0.02$
Вт/(м·К)
number
Теплопроводность (резерв)
fan_power
$1.0$
—
number
Коэф. мощности вентиляторов
fan_nominal_rpm
$1500$
об/мин
number
Номинал оборотов
fan_time_to_nominal
$5.0$
с
number
Время выхода на номинал
fan_initial_rpm
$1500$
об/мин
number
Начальные обороты
fan_cmd
None
—
number
Управляющий вход (мост L $\to$ C)
Состояния и интегрирование
Внутренние состояния:
h (alg) — алгебраическое
состояние энтальпии продукта на выходе
(h_out_target = h_in - Q/$\dot{m}$).
Математическая модель
Невязки (2 значения):
\[
\begin{aligned}
F_0 &= (V[\texttt{product\_out}] - V[\texttt{product\_in}]) + R_h \cdot \dot m, \\
F_1 &= S[\texttt{"h"}] - h_{\text{out\_target}},
\qquad h_{\text{out\_target}} = h_{\text{in}} - \frac{Q}{\dot m}.
\end{aligned}
\]
Здесь $Q$ — теплосъём, который определяется
внутренним fsolve по двум уравнениям
термобаланса:
$Q_{\text{prod}} = Q_{\text{air}} = U A \cdot \mathrm{LMTD}(T_{\text{prod\_in}}, T_{\text{prod\_out}}, T_{\text{air\_mix}}, T_{\text{air\_out}}) \cdot F_t$ — равенство тепловых потоков через стенку.
$U$ — коэффициент теплопередачи; $A$ — общая
площадь теплопередачи; $F_t$ — поправка на
температурный напор; LMTD — средне-логарифмический
температурный напор. Корреляции: внутритрубная Nu
$= 0.021 \cdot \mathrm{Re}^{0.8} \cdot \mathrm{Pr}^{0.43}$
(legacy MTB), наружная — Briggs–Young для пучка
с оребрением. $G_{\text{air\_mix}} = G_{\text{forced}} + G_{\text{natural}} + G_{\text{recirc}}$ (рециркуляция
через жалюзи; Phase 4 упрощение: 90° открыты, $G_{\text{recirc}} = 0$).
Свойства воздуха ($c_{p,\text{air}}, \mu_{\text{air}}, \lambda_{\text{air}}$) — из таблицы AIR_PROPS с
поправкой на влажность. Свойства продукта ($c_p$, $\mu$,
$\lambda$) — из product_in.medium через
snapshot; если их там нет — фолбэк
product_viscosity_fallback /
product_conductivity_fallback.
Скорость вентилятора (разгон):
\[
k_{\text{fan}}(t) = k_{\text{cmd}} + (k_{\text{initial}} - k_{\text{cmd}})
\cdot \exp(-6.75\, t / \mathrm{fan\_time\_to\_nominal}),
\]
где $k_{\text{cmd}} = \mathrm{fan\_cmd}$, если задан;
иначе — $\mathrm{fan\_power}$. $k_{\text{initial}} = \mathrm{fan\_initial\_rpm} / \mathrm{fan\_nominal\_rpm}$.
Алгоритм работы
a, b = c["nodes"];
attrs = c["attrs"];
m_dot = I[c["id"]].
Получить/создать AirCooler(attrs) через
_get_avo(attrs) (кэш в
attrs["__avo"]).
product_in = self._port(c,
"product_in").
Из residual_ctx.snapshot(...) получить
$\rho, h_{\text{in}}, c_p, \mu, \lambda$ (или
через product_in.medium с фолбэком
product_viscosity_fallback /
product_conductivity_fallback).
Если $c_p$ или $\rho$ не положительны —
ValueError("inlet.medium не привязан;
используйте bind_boundary_streams").
Boundary Feed — граничный источник сети: фиксирует
одно из двух граничных условий на outlet-узле.
В режиме pressure задаёт давление
$P_{\text{outlet}} = P_{\text{set}}$ (Па), и сеть сама
подбирает расход через источник из баланса на узле. В
режиме flow задаёт массовый расход
$\dot m = G_{\text{set}}$ (кг/с; положительный — подача
В сеть). Термодинамика (T, состав) фиксирована
атрибутами и публикуется в
attrs["__port_outlet"].stream через
MaterialStream, чтобы downstream-компоненты
(насос, АВО, drum) читали согласованное состояние.
Является first-class DAE-компонентом, заменившим legacy
feed/mixturesource из
mars_core.acausal.
SPEC.folderНефтегазовые аппараты
Папкаoilgas/boundary_feed/
Типфизический
Уровеньobject
Доменoilgas
symFEED
bodyFEED
Связи компонента (порты)
Across — давление (Па), through — массовый поток
(кг/с). По KCL: $I > 0$ означает подачу ИЗ земли В
outlet-узел (т. е. В сеть).
Не применимо.
Параметры и состояние
Входные параметры
P_Pa
$10^5$
Па
number
Уставка давления (для mode=pressure)
m_dot_kgs
$1.0$
кг/с
number
Уставка расхода (для mode=flow)
T_K
$293.15$
К
number
Температура потока
components
«Water:1.0»
—
composition
Состав потока
Состояния и интегрирование
Собственных дифф. состояний нет — feed статeless. Все
параметры читаются из attrs на каждой итерации
(это устраняет баг устаревшего состояния при live-патче).
Математическая модель
Невязка (классический двухполюсник, 1 значение):
\[
F =
\begin{cases}
V[\texttt{outlet}] - \lambda \cdot P_{\text{set}}, & \texttt{mode = pressure}, \\
I - \lambda \cdot G_{\text{set}}, & \texttt{mode = flow}.
\end{cases}
\]
Множитель $\lambda$ — параметр гомотопии
решателя ($\lambda = 1$ на решении, $0 \to 1$ в процессе
итераций для улучшения сходимости при сильно
нелинейных цепях). В коде residual виден как lam.
Термодинамика outlet-порта — из attrs["__port
_outlet"].stream (MaterialStream с
medium, заполненным при биндинге стримов через
bind_boundary_streams; см.
_bind_boundary_feed_streams ниже).
Создать/взять из attrs инстанс
BoundaryFeed(attrs): режим, $P_{\text{set}}$,
$G_{\text{set}}$, $T_K$.
Считать V[out_node] и I_branch.
Сформировать невязку по формуле выше.
Опубликовать attrs["_pub"] для UI.
Вернуть невязку.
BoundaryFeed(attrs) — класс-обёртка с
полями mode, P_set, G_set, T_K и методом
residuals(c, V, I, dV, dI, t, lam).
BoundaryFeed._port(c) — ленивая
фабрика MixPort (тот же паттерн, что в
centrifugal_pump).
_publish_boundary_feed(c, V, I, t, S) —
функция публикации, передаваемая в
@physical(... publish=...).
_bind_boundary_feed_streams(circuit) —
серверный биндер (@register_circuit_binder):
вызывает bind_boundary_streams(circuit)
для привязки MaterialStream к портам
boundary_feed до первого residual.
Соглашение о знаках: $I > 0$ означает
подачу В outlet-узел (поток из земли в сеть). Это
естественно для feed.
В режиме flow feed задаёт расход
жёстко; сеть подстраивает давление на
outlet-узле из баланса.
В режиме pressure feed задаёт давление
жёстко; сеть подстраивает расход через
feed из баланса на outlet-узле.
AutomationSpec определяет команды
(pressure_setpoint, flow_setpoint,
temperature_setpoint) и телеметрию
(pressure_actual_pa, flow_actual_kgs) для
GUI/SCADA.
Поддержка legacy-ключей: P_Pa / P /
value для $P_{\text{set}}$; m_dot_kgs /
mdot / value для $G_{\text{set}}$ —
для совместимости со старыми circuit.json.
Stream-aware нефтегазовый клапан с обратимым потоком через
состав. Реализует гидравлическую невязку $\Delta P = \rho \cdot (k_v \cdot \mathrm{opening})^2 \cdot \dot m / \sqrt{\rho}$ (с
гладкой сшивкой при $|\Delta P| < \Delta P_{\mathrm{smooth}}$).
Свойства среды (плотность) берутся из trial-snapshot через
ctx.snapshot() и donor — НЕ из атрибутов
компонента. Совместим со stream-стеком: StreamProfile
.flow_through(...) и thermo_ports добавляют к
невязкам уравнения переноса состава и энтальпии
(h_out = h_in). В файл mixing_valve.py
также экспортируется legacy-обёртка valve_mix для
совместимости со старыми цепями (Rh_min-схемы):
она активируется, если в attrs есть Rh_min
или Rh, и добавляет 3 алгебраических состояния
(x0, x1, h).
SPEC.folderНефтегазовые аппараты
Папкаvalves/mixing_valve/
Типфизический
Уровеньobject
Доменoilgas
symMV
bodyMV
Связи компонента (порты)
outlet
out
right
Выход (давление, Па)
Across-переменная — давление (Па), through-переменная —
массовый поток (кг/с). Поток через клапан может быть
обратимым (allow_reverse=True в
StreamProfile.flow_through).
Не применимо.
Параметры и состояние
Входные параметры
opening
$1.0$
0..1
number
Степень открытия
eps_opening
$10^{-3}$
0..1
number
Мин. открытие (защита от 0)
opening_slew
$0.0$
1/с
number
Макс. скорость открытия
dp_smooth_Pa
$10.0$
Па
number
Зона гладкой сшивки при $|\Delta P| < \mathrm{dp\_smooth}$
Rh_min
$10^3$
Па$\cdot$с/кг
number
Сопротивление при полном открытии
x_in
$[0.7, 0.3]$
—
array
Состав на входе (мольные доли)
h_in
$0.0$
Дж/кг
number
Энтальпия на входе
Состояния и интегрирование
В новом стеке собственных состояний нет — гидравлика
однозначно вычисляется по opening и плотности. Состав
и энтальпия идут как алгебраические невязки пресета
flow_through. В legacy-режиме (при наличии
Rh_min) — 3 алгебраических состояния
(x0, x1, h).
Математическая модель
Невязка гидравлики (классический двухполюсник, 1 значение):
\[
F = I - \dot m, \qquad
\dot m = k_v \cdot \mathrm{opening} \cdot \sqrt{\rho}
\cdot
\begin{cases}
\dfrac{\Delta P}{\sqrt{\mathrm{dp\_smooth}}},
& |\Delta P| < \mathrm{dp\_smooth}, \\
\sqrt{|\Delta P|}\,\mathrm{sign}(\Delta P),
& \text{иначе},
\end{cases}
\]
где $\Delta P = V[\texttt{a}] - V[\texttt{b}]$.
При $|\Delta P| \to 0$ остаётся ненулевая производная
$\partial \dot m / \partial \Delta P = k_v \cdot \mathrm{opening} \cdot \sqrt{\rho / \mathrm{dp\_smooth}}$ — это даёт
несингулярный Якобиан в нуле (Newton сходится).
Плотность $\rho$ берётся через
_donor_density(attrs, c["id"], "inlet"):
snapshot = ctx.snapshot(c["id"], "inlet");
если snapshot доступен —
$\rho$ = snapshot.rho_kgm3;
иначе — rho_fallback;
если оба не дали положительного значения —
ValueError("SNAPSHOT_MISSING").
Пресет stream=flow_through + thermo_ports
добавляет невязки переноса состава и энтальпии (живут в
mars_core.streams, не дублируются здесь):
\[
\begin{aligned}
x_{\mathrm{out},i} - x_{\mathrm{in},i} &= 0, \quad i = 0, \ldots, n_{\mathrm{comp}} - 1, \\
h_{\mathrm{out}} - h_{\mathrm{in}} &= 0.
\end{aligned}
\]
Алгоритм работы
a, b = c["nodes"];
attrs = c["attrs"].
$\Delta P = V[a] - V[b]$.
rho = _donor_density(attrs, c["id"], "inlet").
k_v и opening из attrs
(opening_cmd имеет приоритет над
opening).
Boundary Sink — граничный сток сети: фиксирует одно из
двух граничных условий на inlet-узле. В режиме
pressure задаёт давление
$P_{\text{inlet}} = P_{\text{set}}$ (Па), сеть подбирает
расход через приёмник из баланса. В режиме flow
задаёт отбор $\dot m = G_{\text{set}}$ (кг/с; положительный
— отбор ИЗ сети). Термодинамику (T, состав) Sink
НЕ диктует: он принимает то, что пришло через порт
из upstream-цепи. Является парой к boundary_feed:
feed — источник (создаёт поток), sink — сток (забирает
поток). First-class DAE-компонент, заменивший legacy
sink/outlet из mars_core.acausal.
SPEC.folderНефтегазовые аппараты
Папкаoilgas/boundary_sink/
Типфизический
Уровеньobject
Доменoilgas
symSINK
bodySINK
Связи компонента (порты)
Across — давление (Па), through — массовый поток
(кг/с). По KCL: $I > 0$ означает отбор ИЗ inlet-узла В
землю.
Не применимо.
Параметры и состояние
Входные параметры
P_Pa
$10^5$
Па
number
Уставка давления (для mode=pressure)
m_dot_kgs
$0.0$
кг/с
number
Уставка отбора (для mode=flow)
Состояния и интегрирование
Собственных состояний нет. Параметры читаются из
attrs на каждой итерации (stateless — устраняет
баг устаревшего состояния при live-патче).
Математическая модель
Невязка (классический двухполюсник, 1 значение):
\[
F =
\begin{cases}
V[\texttt{inlet}] - \lambda \cdot P_{\text{set}}, & \texttt{mode = pressure}, \\
I - \lambda \cdot G_{\text{set}}, & \texttt{mode = flow}.
\end{cases}
\]
Sink НЕ обновляет термодинамику стрима (в отличие от
boundary_feed, который задаёт $(T, \text{состав})$):
он принимает $(P, T, \text{состав})$ из upstream-компонента
(насоса, барабана, АВО) — эти величины определяются
решением общей DAE.
Соглашение о знаках: $I > 0$ означает
отбор ИЗ inlet-узла (поток из сети в землю). Это
естественно для sink.
Sink не задаёт термодинамику
($(T, \text{состав})$) — в отличие от
boundary_feed. Это правильно: сток не
определяет, что забирает, только сколько.
В режиме flow sink задаёт отбор
жёстко; сеть подстраивает давление на
inlet-узле из баланса.
В режиме pressure sink задаёт давление
жёстко; сеть подстраивает отбор через
sink из баланса на inlet-узле.
AutomationSpec определяет команды
(pressure_setpoint, flow_setpoint)
и телеметрию (pressure_actual_pa,
flow_actual_kgs) для GUI/SCADA.
Поддержка legacy-ключей: P_Pa / P /
value для $P_{\text{set}}$; m_dot_kgs /
mdot / value для $G_{\text{set}}$ —
для совместимости со старыми circuit.json.
Универсальный динамически-управляемый потокорегулирующий
клапан (oilgas) с приводом: задаётся opening_cmd
(0..1), реальное открытие opening_actual
(состояние, diff) подтягивается к команде с
ограниченной скоростью ($\pm 1/\texttt{stroke\_time\_s}$).
Закон расхода: $\dot m = k_v \cdot \mathrm{eff} \cdot \sqrt{\rho} \cdot f(\Delta P)$, где
$\mathrm{eff} = \mathrm{leak\_fraction} + (1 - \mathrm{leak\_fraction}) \cdot \mathrm{opening\_actual}$.
Поддерживает fault-режимы: fault_mode = none /
fail_close / fail_open / fail_hold и общий
available=False. Используется как типовая
регулирующая арматура в цепях регулирования
(давление, расход, температура).
SPEC.folderНефтегазовые аппараты
Папкаvalves/actuated_valve/
Типфизический
Уровеньobject
Доменoilgas
symAV
bodyAV
Связи компонента (порты)
outlet
out
right
Выход (давление, Па)
Across — давление, through — массовый поток
(allow_reverse=True).
Не применимо.
Параметры и состояние
Входные параметры
opening_cmd
$1.0$
0..1
number
Команда открытия
opening_initial
$1.0$
0..1
number
Начальное opening_actual
stroke_time_s
$2.0$
с
number
Полный ход привода
fail_action
«close»
—
combo
Аварийное поведение: close/open/hold
fault_mode
«none»
—
combo
Fault: none/fail_close/fail_open/fail_hold
available
True
—
bool
Привод в работе
dp_smooth_Pa
$10.0$
Па
number
Зона гладкой сшивки при $|\Delta P| < \mathrm{dp\_smooth}$
leak_fraction
$10^{-6}$
0..1
number
Доля утечки (закрыт не до конца)
Состояния и интегрирование
Внутреннее состояние:
opening_actual (diff) —
текущее открытие (0..1, динамика привода).
$\rho \leftarrow \mathrm{\_density}(c)$ (через
snapshot; при отсутствии — fallback на
rho_fallback; если оба невалидны —
ValueError("inlet density missing")).
Расширение базового centrifugal_pump —
добавляет команду run_cmd (bool),
speed_setpoint (0..1.2), динамику разгона/торможения
(first-order, разные постоянные start_tau_s и
stop_tau_s), fault-инжекцию
(fault_mode: none / trip / electrical_trip /
dry_run / mechanical_seizure), latched-trip
(trip_latched c защёлкой через
trip_latch_tau_s, сбрасывается через
reset_trip_cmd), конечное сопротивление в
остановленном состоянии (off_resistance,
$\sim 10^8$ Па/(кг/с) — не «идеальная» стенка при
speed = 0, чтобы Якоби не вырождался). Свойства
среды через ctx.snapshot("inlet") —
без silent fallback: при отсутствии —
ValueError("inlet medium is not bound").
$\Delta P$ — из _operating_values:
квадратичный экстраполятор каталога с
flow_smoothing и forward_q
($\ge 0$) для forward_only-политики;
знаковый $\mathrm{copysign} \cdot head(\cdot)$ для
bidirectional.
$W = \Delta P \cdot q/3600 / \mathrm{eff}$ —
мощность на валу через изотермический гидравлический
баланс (N_hydraulic = eff $\cdot$
N_shaft); не использует независимый
power_poly, иначе нарушается
согласование при изменении $\rho$ или типа среды.
Центробежный насос как гидравлическая ветвь acausal-цепи.
Реализует напорную характеристику по каталожным точкам
(аппроксимация полиномом 2-й степени), аффинное подобие
по оборотам двигателя, разгон двигателя (аналитика по t),
и энергобаланс через энтальпию на выкиде. Свойства среды
($\rho$, $h$, $c_p$, $\mu$, $\lambda$, состав) берутся из
порта inlet.medium через trial-snapshot —
НЕ из атрибутов компонента. Использует новый
стрим-стек (MaterialStream, MixPort).
Внутри компонент выделен в класс CentrifugalPump с
полиномами head_poly, eff_poly,
power_poly и об/мин двигателя; инстанс
кэшируется в attrs["__pump"] по сигнатуре
параметров.
SPEC.folderНефтегазовые аппараты
Папкаoilgas/centrifugal_pump/
Типфизический
Уровеньobject
Доменoilgas
symP
bodyP
Связи компонента (порты)
outlet
out
right
Нагнетание (давление, Па)
Across — давление (Па), through — массовый поток
(кг/с). $I > 0$ — поток в естественном направлении
через насос.
Не применимо.
Параметры и состояние
Входные параметры
head_data
$[124, 118, 95, 110]$
м
array
Напор в каталожных точках
eff_data
$[0.63, 0.77, 0.75, 0.80]$
—
array
КПД (допустимо в \%)
power_data
$[298, 359, 527, 440.2]$
кВт
array
Мощность на валу
c_motor
$1.0$
—
number
Коэффициент скорости (множитель)
time_to_nominal
$2.0$
с
number
Время выхода на номинал
nominal_rpm
$1489$
об/мин
number
Номинальные обороты
flow_policy
«forward_only_infeasible»
—
combo
Политика обратного потока
eps_flow
$10^{-3}$
кг/с
number
Защита от деления на ноль по потоку
Состояния и интегрирование
Внутренние состояния:
h (alg) — алгебраическое
состояние энтальпии на выкиде (Дж/кг). Решатель
подбирает S["h"] так, чтобы невязка
S["h"] - (h_in + W/$\dot{m}$) = 0.
Математическая модель
Невязки (2 значения):
\[
\begin{aligned}
F_0 &= (V[\texttt{b}] - V[\texttt{a}]) - \Delta P(\dot m, t), \\
F_1 &= \frac{\dot m^2}{\dot m^2 + \varepsilon_{\dot m}^2}
\cdot \frac{|\dot m| (S[\texttt{"h"}] - h_{\text{in}}) - W}{300 \cdot 4 \cdot 10^6} \\
&\quad + \left(1 - \frac{\dot m^2}{\dot m^2 + \varepsilon_{\dot m}^2}\right)
\cdot \frac{S[\texttt{"h"}] - h_{\text{in}}}{4 \cdot 10^6}.
\end{aligned}
\]
$\Delta P(\dot m, t)$: в режиме
bidirectional —
$\Delta P = \mathrm{sign}(\dot m) \cdot \mathrm{head}(|\dot m| / \rho \cdot 3600,\, k) \cdot g \cdot \rho$; иначе —
$\Delta P = \mathrm{head}(\max(\dot m / \rho \cdot 3600,\, 0),\, k) \cdot g \cdot \rho$. Здесь $k = \mathrm{coef\_velocity}(t)$ —
аналитический разгон двигателя:
\[
k(t) = c_{\text{motor}} \cdot
\begin{cases}
1, & \mathrm{time\_to\_nominal} \le 0, \\
1 - \exp(-6.75\, t / \mathrm{time\_to\_nominal}), & \text{иначе}.
\end{cases}
\]
$\mathrm{head}(q, k)$ и $\mathrm{power\_w}(q, k)$ —
полиномы по $q$ (м³/ч), домноженные на $k^2$ и $k^3$
соответственно; защита от отрицательных значений
(max(..., 0)). КПД: $\mathrm{eff}(q)$ —
полином, обрезанный в $[0, 1]$.
Алгоритм работы
a, b = c["nodes"];
attrs = c["attrs"];
m_dot_in = I[c["id"]] (скаляр).
Получить/создать CentrifugalPump(attrs)
через _get_pump(attrs) (кэш в
attrs["__pump"]).
Через residual_ctx.snapshot(c["id"],
"inlet") получить $\rho$, h_in (trial
snapshot — иначе inlet.density,
inlet.enthalpy_mass). Если оба не
определены — ValueError("inlet medium is
not bound").
energy_res по нормированной формуле выше;
spec_energy = shaft_w / |$\dot{m}$|
(или 0 при $|\dot m| < \varepsilon_{\dot m}$);
h_out_target = h_in + spec_energy.
Опубликовать attrs["_pub"].
Вернуть [branch, energy_res].
Связанные компоненты
valves/mixing_valve — клапаны на
штуцерах downstream.
oilgas/air_cooler — типичный
потребитель на нагнетании.
oilgas/drum — барабан-приёмник.
oilgas/boundary_feed,
oilgas/boundary_sink — граничные
условия цепи.
Обратный клапан
check_valve
Объектный
физическийoilgasНефтегазовые аппараты/Арматура и сопротивленияvalves/check_valve/
Пассивный обратный клапан: пропускает поток только в
прямом направлении (inlet $\to$ outlet), когда
$\Delta P = P_{\text{inlet}} - P_{\text{outlet}}$ превышает
давление открытия (cracking_pressure_Pa); при
обратном направлении — утечка с $\mathrm{k\_v}_{\text{reverse}}$
(обычно на 6 порядков меньше прямого). Гладкая (C$^\infty$)
аппроксимация замыкания: $\sqrt{\Delta P} \cdot \exp(-\mathrm{dp\_smooth}/\Delta P)$ — ноль при
$\Delta P \le 0$, квадратичный рост при $\Delta P > \mathrm{cracking}$ без сингулярности Якобиана в нуле.
Поддержка старого синтаксиса: k_v /
cracking_pressure_Pa (одна буква),
k_v_forward / cracking_pressure_pa
(предпочтительно). Используется как типовой обратный
клапан между секциями трубопровода, на нагнетании
насоса и т. п.
SPEC.folderНефтегазовые аппараты/Арматура и сопротивления
Папкаvalves/check_valve/
Типфизический
Уровеньobject
Доменoilgas
symCV
bodyCV
Связи компонента (порты)
outlet
out
right
Выход (давление, Па)
Across — давление, through — массовый поток
(allow_reverse=True, но $\dot m < 0$ сильно
подавлено).
Не применимо.
При $\Delta P \le 0$: $\mathrm{root} = 0$ —
идеальный «закрыт».
При $0 < \Delta P < p_{\text{crack}}$:
$\sqrt{\Delta P} \cdot \exp(-\sigma / \Delta P) \to 0$
экспоненциально быстро.
При $\Delta P \gg p_{\text{crack}}$:
$\exp(-\sigma/\Delta P) \to 1$, $\mathrm{root} \approx \sqrt{\Delta P}$ — как обычный клапан.
Гладкая (C$^\infty$) стыковка без разрыва
$\to$ Якоби не имеет «ударной» особенности в
$\Delta P = 0$ — Ньютон сходится.
Параметр dp_smooth_Pa:
dp_smooth = max(пользовательское,
$0.05 \cdot p_{\text{crack}}$); при $p_{\text{crack}} = 0$
остаётся floor $10$ Па.
Полоса «сшивки» масштабируется с $p_{\text{crack}}$
— при больших $p_{\text{crack}}$ (килоПаскаль) полоса
автоматически тоже большая; «dead-headed pump start»
(насос против закрытого нагнетания) не «прыгает»
на мегаПаскаль за итерацию.
Алгоритм работы
$a, b \leftarrow \texttt{c["nodes"]}$,
$attrs \leftarrow \texttt{c["attrs"]}$.
$\Delta P \leftarrow V[a] - V[b]$.
Считать настройки через _settings(attrs):
k_v = k_v_forward или k_v,
$p_{\text{crack}}$,
reverse_leak_k_v,
dp_smooth.
$\rho \leftarrow$ через _density(c)
(snapshot или rho_fallback; защита от
нуля max($\rho$, $10^{-12}$)).
Вычислить forward, reverse по
формуле.
$\dot m \leftarrow \mathrm{forward} - \mathrm{reverse}$.
Вернуть $I[\texttt{c["id"]}] - \dot m$.
Опубликовать attrs["_pub"].
Связанные компоненты
valves/actuated_valve,
valves/mixing_valve — регулирующая
арматура (обычно ставится параллельно или после
обратного клапана).
oilgas/centrifugal_pump — на
нагнетании обычно ставится обратный клапан для
защиты от обратного тока при остановке.
физическийoilgasНефтегазовые аппараты/Арматура и сопротивленияoilgas/process_resistance/
Универсальное пассивное гидравлическое сопротивление
для oilgas-цепей: задаёт линейный $\Delta P$ с
необязательным квадратичным членом
($R_{\text{linear}} \dot m$ и $K_{\text{quad}} \dot m^2$),
всемирным коэф. загрязнения (fouling_factor),
ручным множителем (resistance_multiplier) и
флагом «забит/отключён» (blocked, увеличивает
сопротивление на blocked_multiplier). Поддерживает
обратимость через allow_reverse=True и знаковый
flow_policy (bidirectional,
check_valve, forward_only_infeasible).
Используется как типовое технологическое сопротивление
(трубопроводы, фильтры, диафрагмы, теплообменники,
погружные насосы в стеснённых условиях и т. п.).
SPEC.folderНефтегазовые аппараты/Арматура и сопротивления
Папкаoilgas/process_resistance/
Типфизический
Уровеньobject
Доменoilgas
symR
bodyR
Связи компонента (порты)
outlet
out
right
Выход (давление, Па)
Across — давление, through — массовый поток.
allow_reverse=True.
Не применимо.
Параметры и состояние
Входные параметры
resistance_pa_per_kgs
$10^3$
Па/(кг/с)
number
Линейный коэф.
resistance_multiplier
$1.0$
—
number
Множитель (ручной)
K_quad
$0.0$
Па/(кг/с)$^2$
number
Квадратичный коэф.
fouling_factor
$0.0$
—
number
Множитель загрязнения
blocked
False
—
bool
Заслонка (резко \$\uparrow R\$)
blocked_multiplier
$10^6$
—
number
Множитель при blocked
flow_policy
«forward_only_infeasible»
—
combo
Политика обратного потока
eps_flow
$10^{-3}$
кг/с
number
Защита от деления на ноль
Состояния и интегрирование
Собственных состояний нет — чистая алгебраическая
модель (статика на каждом тике).
Математическая модель
Невязка (1 значение):
\[
F = \frac{V[\texttt{inlet}] - V[\texttt{outlet}] -
\Delta P_{\text{loss}}}{\mathrm{scale}}.
\]
Значение $\Delta P_{\text{loss}}$ (см. функцию
pressure_loss(c, m_dot)):
\[
\begin{aligned}
m_{\text{clamp}} &= \frac{m_{\text{dot}}}{\sqrt{m_{\text{dot}}^2 +
\varepsilon_{\dot m}^2}}, \\
\Delta P_{\text{loss}} &= m_{\text{clamp}} \cdot
\bigl(R_{\text{linear}} + K_{\text{quad}} |m_{\text{dot}}|\bigr)
\cdot \text{mult} \cdot (1 + f) \cdot b, \\
\text{mult} &= \text{resistance\_multiplier}, \\
f &= \text{fouling\_factor}, \\
b &= \text{blocked\_multiplier}, \quad \text{если
\texttt{blocked=True}, \quad \text{иначе } 1.
\end{aligned}
\]
Знак несёт $m_{\text{clamp}}$: пассивное
сопротивление сохраняет знак входа.
Нормализация невязки (для устойчивости):
\[
\mathrm{scale} = \max\bigl(R_{\text{linear}} + 2 K_{\text{quad}}
|\dot m| \bigr) \cdot \text{mult} \cdot (1 + f) \cdot b
\]
(при $|K_{\text{quad}}| \cdot |\dot m|$ << $R_{\text{linear}}$
невязка ~ Па / (Па/(кг/с)) = безразмерный; при больших
$K_{\text{quad}}$ нормализация удерживает масштаб).
Сложность $\Delta P$:
Линейный член доминирует при малых $\dot m$ —
типично для длинных трубопроводов, шероховатых стенок.
Квадратичный член при больших $\dot m$ —
типично для диафрагм, поворотов, клапанов
(турбулентная потеря).
blocked=True увеличивает $R$ в
blocked_multiplier раз (~$10^6$) —
фактически закрытый канал, остаточный «поток»
только из eps_flow.
Алгоритм работы
Считать параметры через _settings(attrs).
$\dot m \leftarrow I[\texttt{c["id"]}]$.
Если $|\dot m|$ не конечно — взять
$\pm$sys.float_info.max (или 0, если
None).
$m_{\text{clamp}}, \Delta P_{\text{loss}}$ —
через pressure_loss.
Четырёхполюсник — мост Гретца на четырёх диодах
Шокли. Вход — переменное напряжение (ac1,
ac2), выход — выпрямленное (dc_p,
dc_n). Внутри: $D_1$: ac1 → dc_p;
$D_2$: ac2 → dc_p; $D_3$: dc_n → ac1;
$D_4$: dc_n → ac2. ВАХ диода — стандартная
модель Шокли: $i = I_s (\exp(U / (n V_t)) - 1)$ с
ограничительной экспонентой limexp (pnjlim) для
устойчивости Ньютона и параллельной проводимостью
$G_{\min}$ (как в SPICE). Параметр Ud (прямое
падение) задаёт рабочую точку: $I_s$ подбирается так,
чтобы при токе 1 мА падение было $\approx$ Ud
(кремний $\sim 0.7$ В, Шоттки $\sim 0.3$ В).
Используется как типовая модель выпрямителя (вместо
упрощённой rectifier, где диод — идеальная
«защёлка»).
SPEC.folderПолупроводники
Папкаpower/diode_bridge/
Типфизический
Уровеньobject
Доменelectrical
symVDB
bodyVDB
Связи компонента (порты)
ac2
in
right
electrical
Переменный вход 2
dc_p
out
top
electrical
Постоянный выход «+»
dc_n
out
bottom
electrical
Постоянный выход «-»
Across — потенциал (В), through — ток (А).
Не применимо.
Параметры и состояние
Входные параметры
Также поддерживаются legacy-ключи: Прямое падение
(для Ud). Скрытые параметры: Is,
Vt (по умолчанию $0.02585$ В), n (по
умолчанию $1.0$), Gmin (по умолчанию $10^{-9}$ См).
Состояния и интегрирование
Собственных состояний нет. Неявная алгебраическая
система (токи — мгновенные функции напряжений через
ВАХ диодов).
Математическая модель
ВАХ каждого диода (с защитой от переполнения через
limexp и параллельной проводимостью $G_{\min}$):
\[
i_d(u) = I_s \cdot (\mathrm{limexp}(u / (n V_t)) - 1) + G_{\min} \cdot u
\]
Распределение диодов в мосте:
\[
\begin{aligned}
i_{D_1} &= i_d(V_{\text{ac1}} - V_{\text{dc\_p}}), \\
i_{D_2} &= i_d(V_{\text{ac2}} - V_{\text{dc\_p}}), \\
i_{D_3} &= i_d(V_{\text{dc\_n}} - V_{\text{ac1}}), \\
i_{D_4} &= i_d(V_{\text{dc\_n}} - V_{\text{ac2}}).
\end{aligned}
\]
Возвращаемый вектор невязок (4 значения):
\[
\begin{aligned}
F_0 &= I[\texttt{ac1}] - (i_{D_1} - i_{D_3}), \\
F_1 &= I[\texttt{ac2}] - (i_{D_2} - i_{D_4}), \\
F_2 &= I[\texttt{dc\_p}] - (-(i_{D_1} + i_{D_2})), \\
F_3 &= I[\texttt{dc\_n}] - (i_{D_3} + i_{D_4}).
\end{aligned}
\]
Калибровка $I_s$ по Ud (при токе
$I_{\text{ref}} = 1$ мА падение $\approx$ Ud):
\[
I_s = \frac{I_{\text{ref}}}{\exp(\texttt{Ud} / V_t) - 1}
\]
Защита: Ud ограничен снизу $0.05$ В (иначе
$I_s$ взрывается при Ud $\to 0$).
Ud = max(float(attrs.get("Ud",
attrs.get("Прямое падение", 0.7))), 0.05).
Is = float(attrs.get("Is", 0.0)) or
_Is_from_Ud(Ud).
Vt = float(attrs.get("Vt", 0.02585));
n = float(attrs.get("n", 1.0));
gmin = float(attrs.get("Gmin",
attrs.get("gmin", 1e-9))).
Вычислить токи $i_{D_1} \ldots i_{D_4}$ через
_diode_i.
Сформировать 4 невязки.
@physical-обёртка через Elem(...
_PORTS, _DIRS, True) (4 порта, multi).
Связанные компоненты
power/transformer — на вторичной
обмотке трансформатора.
power/dc_dc_buck — типовая
нагрузка после моста.
power/rectifier — упрощённая
функциональная модель (без ВАХ).
DC/DC buck-преобразователь
dc_dc_buck
Логический
логическийistochnikiistochniki/dc_dc_buck/
Усреднённая модель понижающего (buck) DC/DC-преобразователя с
ШИМ-управлением: выходное напряжение $U_{\text{out}} = D \cdot U_{\text{in}} \cdot \eta$ (стационар), с LC-фильтром
($L$ — индуктивность дросселя, $C$ — ёмкость выходного
конденсатора) и нагрузкой $R_{\text{load}}$. Усреднение за
период ШИМ снимает высокочастотную пульсацию ключа и даёт
гладкую динамику, пригодную для исследования переходных
процессов во вторичных цепях питания. Внутреннее состояние —
токи/напряжения LC-фильтра; шаг — неявный Эйлер
(для устойчивости при больших dt).
SPEC.folderistochniki/dc_dc_buck/
Папкаistochniki/dc_dc_buck/
Типлогический
Уровеньlogic
Связи компонента (порты)
U_out
out
right
Выходное напряжение, В
Не применимо.
Параметры и состояние
Входные параметры
L
$100\!\cdot\!10^{-6}$
Гн
number
Индуктивность дросселя
C
$100\!\cdot\!10^{-6}$
Ф
number
Ёмкость выходного конденсатора
R_load
$10.0$
Ом
number
Сопротивление нагрузки (или R)
eta
$0.9$
—
number
КПД
Состояния и интегрирование
Внутренние состояния:
io.state["i_L"] — ток дросселя;
io.state["u_out"] — напряжение выхода
(сглаженное, до применения $\eta$).
Упрощённая функциональная модель мостового выпрямителя (мост
Гретца) для лабораторной работы № 1 по ИВЭП. Вход —
мгновенное напряжение переменного тока, выход —
двухполупериодное выпрямленное напряжение с учётом падения на
двух последовательных диодах ($2 \cdot U_d$). Используется в
составе ИВЭП: сеть $\to$ трансформатор $\to$ rectifier
$\to$ LC-фильтр $\to$ стабилизатор $\to$ нагрузка. Без
состояния.
источник переменного напряжения (например, сеть)
на входе.
Датчик температуры
temperature_sensor
Логический
логическийdatchikidatchiki/datchik_temperatury/
Линейное преобразование сопротивления терморезистора (Ом) в
температуру (°C): $T = \mathrm{gain} \cdot R + \mathrm{offset}$.
Коэффициенты gain и offset задаются
пользователем и по умолчанию соответствуют характеристике
типового платинового ТС (PT100 в районе 0 °C). Простой
безынерционный преобразователь. Файл помечен как
«Сгенерировано ORPHYS Component Generator»; правки делаются
через редактор компонентов, не вручную.
SPEC.folderdatchiki/datchik_temperatury/
Папкаdatchiki/datchik_temperatury/
Типлогический
Уровеньlogic
Связи компонента (порты)
T_C
out
right
Температура, °C
Не применимо.
Параметры и состояние
Входные параметры
offset
$-259.7402597$
°C
number
Смещение характеристики
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
T = \mathrm{gain} \cdot R + \mathrm{offset}
\]
x = io.read("R_Ohm").
gain = io.param("gain", 2.5974025974),
offset = io.param("offset", -259.7402597).
sensor_lag — модель с инерцией (фильтр
первого порядка);
thermal_tank — источник температуры
продукта.
Драйвер L293D
l293d_driver
Логический
логическийdvigatelidvigateli/drayver_l293d/
Логическая модель H-моста L293D. Три входа (IN1,
IN2, ENA), где IN1 — сигнальный
вход, IN2 и ENA — параметры (у L293D
три входа, но в библиотечной шине для простоты один сигнальный
порт). Выход OUT1 — основной, плюс публикация
внутренних OUT2 и I_out в io.state
для тестов и других компонентов. Используется как типовая
силовая часть для DC-двигателей и шаговых двигателей.
SPEC.folderdvigateli/drayver_l293d/
Папкаdvigateli/drayver_l293d/
Типлогический
Уровеньlogic
Связи компонента (порты)
OUT1
out
right
Выход 1 (на нагрузку)
Не применимо.
Параметры и состояние
Входные параметры
ENA
$1.0$
—
number
Разрешение (или en)
Vs
$12.0$
В
number
Напряжение питания
Uce_sat
$1.8$
В
number
Напряжение насыщения ключа
R_load
$10.0$
Ом
number
Сопротивление нагрузки (или R)
Состояния и интегрирование
Состояние используется только как «опубликованное хранилище»
выходов, не как интегратор.
Универсальный источник тестового сигнала. Поддерживает пять
форм: const, ramp (линейный рост), sine
(синус), square (меандр), step (ступенька).
Форма выбирается параметром mode (строка) или
mode_id (число). Используется как стандартное
воздействие при тестировании САУ. Без состояния; модельное
время берётся из io.ts. Файл помечен <<Сгенерировано
ORPHYS Component Generator>>; правки делаются через редактор
компонентов, не вручную.
SPEC.folderistochniki/istochnik_znacheniya/
Папкаistochniki/istochnik_znacheniya/
Типлогический
Уровеньlogic
Связи компонента (порты)
value
out
right
Текущее значение сигнала
Не применимо.
Параметры и состояние
Входные параметры
amplitude
$20.0$
ед.
number
Амплитуда $A$
freq
$0.1$
Гц
number
Частота (для sine/square)
slope
$1.0$
ед./с
number
Наклон (для ramp)
t0
$0.0$
с
number
Момент включения (для step)
mode
«»
—
text
Имя формы: const / ramp / sine / square / step
mode_id
$2$
—
int
Код формы (если mode пуст): 0/1/2/3/4
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
\mathrm{value} = \mathrm{signal}(\mathrm{mode},\, t)
\]
где signal одна из:
\[
\begin{aligned}
\mathrm{const:} & \;\; b \\
\mathrm{ramp:} & \;\; \mathrm{slope} \cdot t + b \\
\mathrm{sine:} & \;\; b + A \sin(2\pi f t) \\
\mathrm{square:} & \;\; b + A \cdot \mathrm{sign}\bigl(\sin(2\pi f t)\bigr) \\
\mathrm{step:} & \;\; b + A \cdot [t \ge t_0]
\end{aligned}
\]
Универсальный источник; совместим с любым приёмником. Для
узкоспециализированных форм лучше использовать
sau_step, sau_sine, sau_pulse.
Партнёрский резистор
(тест)
partner_test_resistor
Логический
логическийpartnerpartner/partner_test_resistor/
Партнёрская модель резистора с ограничением тока. Используется
как пример подключения «внешнего» компонента и как
демонстрация clamp-логики через параметры (без io.state
— лимит на ток задаётся входным параметром I_max).
В реальной модели – линейный резистор с «идеальным»
токовым ограничителем, что позволяет безопасно коммутировать
напряжение на нагрузке. Без состояния.
SPEC.folderpartner/partner_test_resistor/
Папкаpartner/partner_test_resistor/
Типлогический
Уровеньlogic
Связи компонента (порты)
I
out
right
Ток, А
Не применимо.
Параметры и состояние
Входные параметры
I_max
$10.0$
А
number
Максимально допустимый ток
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
I = \mathrm{clamp}\!\left(\frac{U}{R},\; -I_{\max},\; +I_{\max}\right)
\]
с защитой от деления на ноль.
U = io.read("U"), R = io.param("R", 1.0),
I_max = io.param("I_max", 10.0).
Если $R = 0$: io.write("I", 0.0); выйти.
I = clamp(U / R, -I_max, +I_max);
io.write("I", I).
Связанные компоненты
vypryamitel — типовая питающая сторона;
dc_dc_buck — согласование уровней.
ПИД-регулятор
pid
Логический
логическийregulyatoryregulyatory/pid/
Дискретный ПИД-регулятор с анти-windup (clamp интеграла при
насыщении выхода). На вход — измеренная величина
(например, температура продукта с датчика), на выходе —
управляющий сигнал $u \in [u_{\min}, u_{\max}]$, который
мост L $\to$ C (терминал term) подаёт на
управляющий вход физблока (обороты вентиляторов, открытие
клапана). Применяется как стандартный регулятор в
замкнутых контурах (например, контур стабилизации температуры
АВО). Состояние: $I$ (накопленный интеграл), $e_{\text{prev}}$
(предыдущая ошибка). Позиционная форма.
e_prev — предыдущая ошибка (для
дифференциальной части).
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
Позиционная форма (с анти-windup):
\[
\begin{aligned}
e &= T_{\text{meas}} - T_{\text{set}} \quad \text{(если reverse)} \\
I &= I_{\text{prev}} + e \cdot dt \\
D &= (e - e_{\text{prev}}) / dt \\
u_{\text{raw}} &= K_p e + K_i I + K_d D \\
u_{\text{clamped}} &= \mathrm{clamp}(u_{\text{raw}},\, u_{\min},\, u_{\max}) \\
I &=
\begin{cases}
I, & u_{\text{clamped}} = u_{\text{raw}} \\
I_{\text{prev}}, & \text{иначе} \quad \text{(анти-windup)}
\end{cases} \\
e_{\text{prev}} &= e \\
u &= u_{\text{clamped}}
\end{aligned}
\]
Считать sp, Kp, Ki, Kd, u_min, u_max, dt, reverse
через io.param / io.flag.
meas = io.read("T_meas");
e = (meas - sp) if reverse else (sp - meas).
I = io.state.get("I", 0.0),
e_prev = io.state.get("e_prev", e).
I = I + e*dt, D = (e - e_prev)/dt.
u = Kp*e + Ki*I + Kd*D,
u = clamp(u, u_min, u_max).
Анти-windup: I = I if u не насыщен else I_prev.
Сохранить io.state["I"] = I, io.state["e_prev"] = e;
io.write("u", u).
Связанные компоненты
sau_sum — для формирования ошибки
($T_{\text{set}} - T_{\text{meas}}$);
sau_saturation — внешний ограничитель
выхода;
term — мост L $\to$ C для подачи $u$ на
физблок (вентилятор, клапан);
optimizer — оптимизация $K_p, K_i, K_d$.
Терминал
terminal
Логический
логическийterminalyterminaly/term/
Кросс-слойный терминал для «прыжка» сигнала между слоями
(L-уровень) без рисования длинного провода через всю схему.
Поведение — аффинный проводник: $y = x \cdot \mathrm{scale} + \mathrm{offset}$ (для приёмника с пересчётом 0..1 $\to$
физическая величина). Пара терминалов с общим
tag образует одну «логическую связь»; реальная
маршрутизация по тегу — забота диспетчера/редактора
(модель Simulink Goto/From). Визуально рисуется на каждом
слое нативно (провод, входящий в goto / исходящий
из from).
SPEC.folderterminaly/term/
Папкаterminaly/term/
Типлогический
Уровеньlogic
Связи компонента (порты)
y
out
right
Выходное значение
Не применимо.
Тег (одинаковый у пары goto $\leftrightarrow$
from): задаётся в редакторе как атрибут
терминала, не параметр компонента.
Режим (__PX0__): goto (источник)
или from (приёмник).
Параметры и состояние
Входные параметры
offset
$0.0$
—
number
Смещение
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = \mathrm{scale} \cdot x + \mathrm{offset}
\]
Маршрутизация по тегу и проверка наличия пары выполняются
вне компонента (в диспетчере).
Связанные компоненты
Любой источник/приёмник сигнала.
Термосопротивление
thermoresistor
Логический
логическийdatchikidatchiki/termosoprotivlenie/
Линейное преобразование температуры (°C) в сопротивление
(Ом): $R = \mathrm{gain} \cdot T + \mathrm{offset}$. По
умолчанию коэффициенты подобраны для платинового ТС вблизи
0 °C. Простой безынерционный преобразователь; для учёта
инерции используйте sensor_lag. Файл помечен
«Сгенерировано ORPHYS Component Generator»; правки делаются
через редактор компонентов, не вручную.
SPEC.folderdatchiki/termosoprotivlenie/
Папкаdatchiki/termosoprotivlenie/
Типлогический
Уровеньlogic
Связи компонента (порты)
R_Ohm
out
right
Сопротивление, Ом
Не применимо.
Параметры и состояние
Входные параметры
offset
$100.0$
Ом
number
Смещение характеристики
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
R = \mathrm{gain} \cdot T + \mathrm{offset}
\]
x = io.read("T_in").
gain = io.param("gain", 0.385),
offset = io.param("offset", 100.0).
Кинематическая модель шагового двигателя (NEMA 17, 200 шагов
на оборот, 1.8°/шаг) с поддержкой режимов full и
half step. На каждый входной импульс step
вал поворачивается на $\theta_{\text{step}} = 2\pi / (\mathrm{steps\_per\_rev} \cdot k)$, где $k = 1$ (full) или
$k = 2$ (half). Направление задаётся параметром dir.
Состояние: $\theta$ (накапливается через io.integrate).
SPEC.folderdvigateli/shagovyy_unipolar/
Папкаdvigateli/shagovyy_unipolar/
Типлогический
Уровеньlogic
Связи компонента (порты)
theta
out
right
Текущий угол вала, рад
Не применимо.
Параметры и состояние
Входные параметры
steps_per_rev
$200.0$
—
number
Число шагов на оборот (full)
step_mode
«full»
—
text
Режим: full / half
theta0
$0.0$
рад
number
Начальный угол
Состояния и интегрирование
Внутреннее состояние —
io.state["theta"]: накопленный угол (обновляется
через io.integrate).
drayver_l293d — силовая часть
(формирует импульсы на обмотки);
encoder — датчик обратной связи
(по углу $\theta$).
Энкодер инкрементальный
encoder
Логический
логическийdvigatelidvigateli/encoder/
Преобразование абсолютного угла вала $\theta$ (рад) в
накопленный счётчик импульсов и текущую частоту вращения
(об/мин). Используется как датчик обратной связи в контурах
управления двигателями. На каждом тике вычисляется приращение
угла, по нему — число импульсов (с округлением); счётчик
накапливается. Состояние: angle_prev, count.
Детерминированный автомат A/B duty/standby для двух
взаимозаменяемых агрегатов (например, два насоса, два
компрессора, две линии резервирования). Состояния:
STOPPED $\to$ STARTING_A/B $\to$ RUNNING_A/B $\to$
(TRANSFER/overlap) $\to$ STARTING_B/A. Поддерживает
предпочтение (duty_select), таймаут пуска
(start_timeout_s), задержку передачи
(transfer_delay_s) и допустимое перекрытие
(overlap_s). Входы: статусы available,
trip, running для A и B; выходы:
команды пуска a_run_cmd, b_run_cmd,
флаги transfer_active, no_unit_available.
Состояние автомата и таймер — в io.state
(state, timer_s). Используется как
типовой A/B-контроллер резервирования в непрерывных
процессах.
SPEC.folderControllers
Папкаcontrollers/two_unit_standby/
Типлогический
Уровеньlogic
Доменlogic
symA/B
bodyDUTY/STBY
Связи компонента (порты)
b_available
in
left
Доступность агрегата B
a_trip
in
left
Авария агрегата A
b_trip
in
left
Авария агрегата B
a_running
in
left
Факт пуска A (от привода)
b_running
in
left
Факт пуска B (от привода)
a_run_cmd
out
right
Команда пуска A
b_run_cmd
out
right
Команда пуска B
transfer_active
out
right
Идёт передача (1)
no_unit_available
out
right
Ни один не доступен (1)
Не применимо.
Параметры и состояние
Входные параметры
duty_select
«A»
—
combo
Предпочтение: A / B
start_timeout_s
$10.0$
с
number
Таймаут пуска
transfer_delay_s
$0.0$
с
number
Задержка передачи (0 = мгновенно)
overlap_s
$0.0$
с
number
Допустимое перекрытие (взаимный пуск)
Состояния и интегрирование
Внутреннее состояние: state, timer_s.
Метод интегрирования не используется (логика).
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
Если enable = False:
state = STOPPED;
a_run_cmd = b_run_cmd = 0;
transfer_active = no_unit_available = 0;
выйти.
Определить preferred = duty_select
(значение A/B; по умолчанию A).
Конечный автомат с переходами (см. файл). В
каждом переходе обновляются
a_run_cmd, b_run_cmd,
transfer_active,
no_unit_available.
Таймер timer_s тикает на dt только
в STARTING_... и TRANSFER_... /
OVERLAP_....
При недостижимом/повреждённом state
— детерминированный recovery в STOPPED.
Связанные компоненты
controllers/pid — регулятор
(обычно ведущий).
stands/... — runtime для
фактического пуска/останова (a_running,
b_running).
любой привод (motors/...,
valves/actuated_valve и т. п.) —
принимает a_run_cmd/b_run_cmd.
Оптимизатор
optimizer
Логический
метаАнализ и оптимизацияanaliz/optimizer/
Мета-блок для визуального представления оптимизатора параметров
на схеме. Хранит конфигурацию оптимизации (имена целевых
параметров, начальные значения, пределы, шаги, критерии,
метод, режим) в своих параметрах. НЕ исполняется
тик-за-тиком: шаг-заглушка просто отдаёт на выход текущее
значение вектора параметров params (dict по именам
из target_params) — для осциллограммы. Реальная
оптимизация запускается отдельно через
OptimizerService.Optimize по сокету (фаза C).
SPEC.folderАнализ и оптимизация
Папкаanaliz/optimizer/
Типмета
Уровеньlogic
symOPT
bodyOPT
Связи компонента (порты)
meas
in
left
Отклик $y(t)$ (для визуализации)
params
out
right
Вектор параметров (после оптимизации)
Не применимо.
Параметры и состояние
Входные параметры
target_params
«Kp,Ki,Kd»
—
text
Имена оптимизируемых параметров
p_init
«0.6,0.08,0.0»
—
text
Начальные значения
p_min
«0,0,0»
—
text
Нижние пределы
p_max
«5,2,1»
—
text
Верхние пределы
p_step
«0.1,0.02,0.01»
—
text
Шаги дискретизации
criteria
«IAE,overshoot,settling,steady»
—
text
Список критериев
c_weights
«1.0,0.5,0.3,0.5»
—
text
Веса критериев
c_limits
«,0.1,30,0.5»
—
text
Пределы критериев
combine
«quadratic»
—
combo
Способ свёртки: additive/quadratic/minimax/multiplicative
Разобрать target_params по запятой
(имена параметров).
Считать p_init как массив чисел.
Собрать vec = \{name: p_init[i]\}.
io.write("params", vec) — значения
текущей рабочей точки, без модификации.
Реальная оптимизация (поиск оптимальных значений) запускается
отдельно через сервис
OptimizerService.Optimize / online_optimizer;
найденные значения фронт записывает в p_init, и они
становятся видны на выходе params.
Связанные компоненты
pid — типичный целевой блок
(оптимизация $K_p, K_i, K_d$);
регуляторы из regulyatory/.
Датчик с инерцией
sensor_lag
Логический
логическийИзмерителиdatchiki/sensor_lag/
Модель реального датчика: «истинная» измеряемая величина
$T_{\text{in}}$ сначала проходит через инерционный фильтр
первого порядка (постоянная $\tau$), затем — линейная
калибровка в выходную физическую величину (например, в Ом).
Используется для моделирования термопар и термосопротивлений
в сборках: отдельно — термодинамика объекта, отдельно —
инерция датчика. Демонстрирует паттерн «смешанного»
компонента: один дифур + одна алгебра в одном шаге.
SPEC.folderИзмерители
Папкаdatchiki/sensor_lag/
Типлогический
Уровеньlogic
body$\tau$
Связи компонента (порты)
R
out
right
Откалиброванное показание, Ом
Не применимо.
Параметры и состояние
Входные параметры
gain
$0.385$
Ом/°C
number
Коэффициент калибровки (алгебра)
offset
$100.0$
Ом
number
Смещение калибровки (алгебра)
T0
$20.0$
°C
number
Начальная температура датчика
dt
$1.0$
с
number
Шаг интегрирования
Состояния и интегрирование
Внутреннее состояние —
io.state["Tf"]: фильтрованная (инерционная)
температура датчика.
Апериодическое (инерционное) звено первого порядка с
передаточной функцией $W(s) = K / (T s + 1)$ — базовое
динамическое звено ТАУ, описывающее бесчисленное множество
реальных объектов: термопару, RC-фильтр, ёмкость с притоком и
стоком, мотор с инерцией. Переходная характеристика —
экспонента с постоянной времени $T$, установившееся значение
$K \cdot x_{\text{const}}$. При $T = 0$ вырождается в чистый
усилитель ($y = K \cdot x$).
SPEC.folderСАУ / Динамические звенья
Папкаsau/first_order/
Типлогический
Уровеньlogic
sym1/(Ts+1)
bodyPT1
Связи компонента (порты)
out
out
right
Выходной сигнал $y$
Не применимо.
Параметры и состояние
Входные параметры
T
$1.0$
с
number
Постоянная времени
initial
$0.0$
ед.
number
Начальное условие $y(0)$
dt
$1.0$
с
number
Шаг интегрирования
Состояния и интегрирование
Внутреннее состояние — io.state["y"].
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
\begin{aligned}
T \dot{y} + y &= K x, \\
W(s) &= \frac{K}{T s + 1}
\end{aligned}
\]
На каждом тике применяется формула неявного Эйлера
(безусловно устойчива при $T / dt > 0$):
\[
y_{\text{new}} = \frac{K x + (T/dt) y_{\text{old}}}{1 + T/dt}
\]
При $T = 0$ — вырождение в y = K * x (прямое
прохождение).
x = io.read("in").
Считать $K, T, dt, y_0$ через io.param.
Получить $y = $ io.state.get("y", y0).
Если T > 0 и dt > 0: применить
формулу (\ref{eq:sau-first-order}).
Иначе: y = K * x.
Реальный (физически реализуемый) дифференциатор: $W(s) = s / (\tau s + 1)$. Чистое дифференцирование $W(s) = s$
нереализуемо (требует бесконечной полосы пропускания),
поэтому применяется дифференцирование с ФНЧ-фильтром первого
порядка с постоянной $\tau$. Используется в ПД-составляющей
ПИД-регулятора, для оценки скорости изменения измеряемой
величины (дифференцирование показаний датчика). Пара $\tau$
регулирует компромисс между точностью дифференцирования и
шумом: меньше $\tau$ — точнее, но шумнее.
SPEC.folderСАУ / Динамические звенья
Папкаsau/derivative/
Типлогический
Уровеньlogic
sym$d/dt$
body$d/dt$
Связи компонента (порты)
out
out
right
Оценка производной $\dot x(t)$
Не применимо.
Параметры и состояние
Входные параметры
initial
$0.0$
ед.
number
Начальное значение фильтрованной производной
dt
$1.0$
с
number
Шаг интегрирования
Состояния и интегрирование
Внутренние состояния:
io.state["x_prev"] — предыдущее значение
входа;
io.state["y_filt"] — фильтрованная
производная.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
\begin{aligned}
W(s) &= \frac{s}{\tau s + 1}, \\
\tau \dot{y} + y &= \dot{x}
\end{aligned}
\]
Реализация:
x = io.read("in"), tau, dt,
initial.
Восстановить x_prev = io.state.get("x_prev", x),
y_filt = io.state.get("y_filt", initial).
Сохранить x_prev = x, y_filt;
io.write("out", y_filt).
Связанные компоненты
pid — D-составляющая ПИД-регулятора
использует ту же идею;
sau_step — подача ступеньки даёт
импульсный выброс на выходе, что не является ошибкой
алгоритма — это следствие разрыва входного сигнала.
Запаздывание
sau_delay
Логический
логическийСАУ / Динамические звеньяsau/delay/
Звено чистого (транспортного) запаздывания: выход равен
входу, взятому с задержкой $\tau$ секунд. Используется для
моделирования запаздывающих каналов регулирования (трубопроводы,
камеры сгорания, ленточные конвейеры) и при исследовании
систем с большим временем чистого запаздывания
(критерий устойчивости — запас по фазе «на глаз» падает
как $\omega \cdot \tau$). Реализация через кольцевой буфер
(collections.deque); состояние инициализируется
начальным значением initial.
SPEC.folderСАУ / Динамические звенья
Папкаsau/delay/
Типлогический
Уровеньlogic
sym$e^{-sT
body$\tau$
Связи компонента (порты)
out
out
right
Задержанный сигнал $y(t)=x(t-\tau)$
Не применимо.
Параметры и состояние
Входные параметры
initial
$0.0$
ед.
number
Начальное значение (заполняет буфер при инициализации)
dt
$1.0$
с
number
Шг модельного времени
buffer_size
$10000$
—
int
Верхняя граница длины буфера (защита от переполнения памяти)
Состояния и интегрирование
Внутреннее состояние — io.state["buf"]:
кольцевой буфер (collections.deque) длины
$\max(1,\;n_{\text{delay}})$, где
$n_{\text{delay}} = \mathrm{round}(\tau / dt)$.
Идеальный интегратор: выход равен интегралу входа по времени
плюс начальное условие. Используется как составная часть
ПИ/ПИД-регулятора (интегральная компонента $I$), для
получения текущего количества вещества по заданному расходу,
выходящего сигнала по скорости изменения и т. п. Внутреннее
состояние — единственная переменная $y$ в io.state,
обновляется через единый шаг io.integrate среды
(явный/неявный метод выбирается средой).
SPEC.folderСАУ / Динамические звенья
Папкаsau/integrator/
Типлогический
Уровеньlogic
sym$\int$
body$\int$
Связи компонента (порты)
out
out
right
Текущее значение интеграла $y$
Не применимо.
Параметры и состояние
Входные параметры
dt
$1.0$
с
number
Шаг интегрирования
Состояния и интегрирование
Внутреннее состояние — io.state["y"], обновляется
через io.integrate("y", x, x0=initial).
Обобщённое линейное динамическое звено с заданной
передаточной функцией
$W(s) = N(s)/D(s) = (b_m s^m + \ldots + b_0)/(a_n s^n + \ldots + a_0)$. Используется для представления линеаризованных
участков САУ, для импорта коэффициентов, рассчитанных
внешними инструментами (Matlab, идентификация), а также
как удобный способ собрать сложную динамику из одной
передаточной функции. Реализация — каноническая
форма наблюдаемых состояний (observer canonical form); шаг
по времени — явный Эйлер с заданным dt.
SPEC.folderСАУ / Динамические звенья
Папкаsau/transfer_fcn/
Типлогический
Уровеньlogic
sym$W(s)$
body$W(s)$
Связи компонента (порты)
out
out
right
Выход $y$
Не применимо.
Параметры и состояние
Входные параметры
denominator
$[1, 1]$
—
array
Коэффициенты знаменателя (по убыванию степени $s$, $a_n \ne 0$)
initial
$0.0$
ед.
number
Начальное условие для $y(0)$ (размазывается на $x_0$)
dt
$1.0$
с
number
Шаг интегрирования
Состояния и интегрирование
Внутреннее состояние —
io.state["x"], вектор длины
$n = \mathrm{deg}(D)$.
sau_first_order — частный случай
($m = 0$, $n = 1$);
sau_delay — формально аппроксимируется
рядом Паде, но не этим блоком.
Дисплей значений
sau_display
Логический
логическийСАУ / Источники и приёмникиsau/display/
Приёмник, отображающий текущее значение входного сигнала в
числовом виде (цифровой индикатор). Выходной порт
выполняет pass-through для корректной сортировки графа.
Визуализация выполняется на фронтенде через отдельный
виджет; сам компонент не хранит историю и не входит в DAE.
Применяется для индикации текущего значения регулируемой
величины, уставки, ошибки и т. п.
SPEC.folderСАУ / Источники и приёмники
Папкаsau/display/
Типлогический
Уровеньlogic
symDisp
bodyDisp
Связи компонента (порты)
out
out
right
Pass-through ($=x$)
Не применимо.
Параметры и состояние
Входные параметры
unit
«ед.»
—
string
Подпись единиц измерения
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
\mathrm{display} = x
\]
io.write("out", io.read("in")).
Связанные компоненты
Универсальный приёмник, совместим с любым источником
сигнала.
Импульсный источник
sau_pulse
Логический
логическийСАУ / Источники и приёмникиsau/pulse/
Периодическая последовательность прямоугольных импульсов:
$y = A$ на интервале длительности $d$ каждого периода $T$,
$y = 0$ в остальное время. Используется для снятия
импульсных переходных характеристик, для имитации
ШИМ-воздействий, для возбуждения импульсных систем
автоматического регулирования. Состояние отсутствует;
момент начала отсчитывается от модельного времени.
SPEC.folderСАУ / Источники и приёмники
Папкаsau/pulse/
Типлогический
Уровеньlogic
sym$\Pi$
bodyPulse
Связи компонента (порты)
Не применимо.
Параметры и состояние
Входные параметры
period
$10.0$
с
number
Период $T$
duty
$0.5$
—
number
Скважность (доля $A$ внутри периода, $0 \le \text{duty} \le 1$)
phase
$0.0$
с
number
Начальная фаза (задержка первого фронта)
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y(t) = \begin{cases}
A, & ((t - t_{\text{phase}}) \bmod T) < d, \\
0, & \text{иначе},
\end{cases}
\qquad d = \mathrm{duty} \cdot T
\]
Считать A, T, duty, phase через
io.param.
t = io.ts.
tau = (t - phase) \% T (фаза внутри периода).
y = A, если tau < duty * T, иначе
y = 0.
io.write("out", y).
Связанные компоненты
sau_scope — для регистрации импульсного
отклика;
sau_first_order — для наблюдения кривой
разгона/спада.
Источник константы
sau_const
Логический
логическийСАУ / Источники и приёмникиsau/const/
Источник постоянного во времени сигнала. Используется как
уставка, начальное приближение, опорное значение для
компараторов и т. п. Не имеет состояния и не зависит от
модельного времени.
SPEC.folderСАУ / Источники и приёмники
Папкаsau/const/
Типлогический
Уровеньlogic
sym$K$
body$C$
Связи компонента (порты)
Не применимо.
Параметры и состояние
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y(t) = C = \mathrm{const}
\]
C = io.param("value", 1.0).
io.write("out", C).
Связанные компоненты
sau_eq, sau_gt, sau_lt —
в качестве опорного сигнала;
pid — параметр setpoint.
Осциллограф
sau_scope
Логический
логическийСАУ / Источники и приёмникиsau/scope/
Приёмник сигнала с буферизацией: каждый отсчёт входного
сигнала добавляется в кольцевой буфер, который затем
визуализируется фронтендом в виде графика. Выходной порт
выполняет pass-through (равен входу) — это нужно только
для корректной топологической сортировки графа сигналов.
Не входит в DAE, не влияет на динамику модели.
SPEC.folderСАУ / Источники и приёмники
Папкаsau/scope/
Типлогический
Уровеньlogic
symScope
bodyScope
Связи компонента (порты)
out
out
right
Pass-through ($=x$)
Не применимо.
Параметры и состояние
Входные параметры
buffer_size
$1000$
—
int
Максимальная длина буфера (точек)
Состояния и интегрирование
Внутреннее состояние — io.state["buf"]: список
длиной не более buffer_size.
Если len(buf) > buffer_size — удалить
самый старый элемент (buf.pop(0)).
io.state["buf"] = buf;
io.write("out", x).
Связанные компоненты
sau_display — цифровая индикация;
любой источник сигнала (sau_step,
sau_sine, sau_pulse) в качестве
входа.
Синусоидальный источник
sau_sine
Логический
логическийСАУ / Источники и приёмникиsau/sine/
Гармонический источник:
$y(t) = A \sin(2\pi f t) + b$.
Используется как периодическое воздействие для снятия
амплитудно-фазовых характеристик, для проверки линейности
системы, для возбуждения резонансных контуров. Без
состояния; модельное время берётся из шины.
SPEC.folderСАУ / Источники и приёмники
Папкаsau/sine/
Типлогический
Уровеньlogic
sym$\sin$
body$\sin$
Связи компонента (порты)
Не применимо.
Параметры и состояние
Входные параметры
frequency
$0.1$
Гц
number
Частота $f$
bias
$0.0$
ед.
number
Смещение $b$
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y(t) = A \sin(2\pi f t) + b
\]
Считать A = io.param("amplitude", 1.0),
f = io.param("frequency", 0.1),
b = io.param("bias", 0.0).
t = io.ts.
io.write("out", A * math.sin(2 * math.pi * f * t) + b).
Связанные компоненты
sau_scope — для регистрации гармонического
отклика;
sau_first_order, sau_transfer_fcn
— как тестовое воздействие при снятии АЧХ/ФЧХ.
Ступенчатое воздействие
sau_step
Логический
логическийСАУ / Источники и приёмникиsau/step/
Источник тестового сигнала в форме ступеньки: до момента
$t_{\mathrm{step}}$ выход равен начальному уровню $y_0$, начиная
с $t_{\mathrm{step}}$ выход переключается на $y_1$ и далее не
меняется. Используется как стандартное воздействие при
исследовании переходных процессов в САУ: снятие кривой разгона,
оценка времени регулирования, перерегулирования и т. п.
Без внутреннего состояния — на каждом тике значение
вычисляется заново по текущему модельному времени.
SPEC.folderСАУ / Источники и приёмники
Папкаsau/step/
Типлогический
Уровеньlogic
symStep
bodyStep
Связи компонента (порты)
Не применимо — компонент логический, acausal-портов и
узловых переменных не имеет.
Не используется.
Параметры и состояние
Входные параметры
final
$1.0$
ед.
number
Конечный уровень $y_1$ (при $t\ge t_{\mathrm{step}}$)
step_time
$1.0$
с
number
Момент переключения $t_{\mathrm{step}}$
Состояния и интегрирование
Внутреннее состояние отсутствует: компонент не хранит историю
входов и не интегрирует значения. Модельное время берётся
напрямую из шины (io.ts).
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
На каждом тике вычисляется выход по правилу кусочно-постоянной
функции модельного времени:
\[
y(t) = \begin{cases}
y_0, & t < t_{\mathrm{step}}, \\
y_1, & t \ge t_{\mathrm{step}}.
\end{cases}
\]
Реализация (sau/step/sau_step.py):
Считать текущее модельное время t = io.ts.
Считать параметры t_step, y_0,
y_1 через io.param(..., default).
Записать в выходной порт
io.write("out", y1 if t >= t_step else y0).
Связанные компоненты
Чаще всего используется совместно с:
sau_scope — для регистрации переходного
процесса;
sau_display — для индикации текущего
значения;
sau_sum, sau_gain,
sau_integrator, sau_first_order —
в качестве типового воздействия на исследуемую цепочку
САУ.
<<Компаратор (>)>>
sau_gt
Логический
логическийСАУ / Мат. операцииsau/gt/
Строгий компаратор: $y = 1$, если $x_1 > x_2$, иначе $y = 0$.
Используется для построения релейной логики, сигнализации
превышения порога, разрешающих сигналов. Без состояния.
SPEC.folderСАУ / Мат. операции
Папкаsau/gt/
Типлогический
Уровеньlogic
sym>
body>
Связи компонента (порты)
in2
in
left
Опорное значение $x_2$
out
out
right
Результат $y \in \{0, 1\}$
Не применимо.
Параметры и состояние
Входные параметры
Не имеет параметров (только входы).
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = [\,x_1 > x_2\,]
\]
io.write("out", 1.0 if io.read("in1") > io.read("in2") else 0.0).
Связанные компоненты
См. sau_eq, sau_lt.
Компаратор (<)
sau_lt
Логический
логическийСАУ / Мат. операцииsau/lt/
Строгий компаратор: $y = 1$, если $x_1 < x_2$, иначе $y = 0$.
Используется для построения релейной логики, сигнализации
«ниже нормы» и т. п. Без состояния.
SPEC.folderСАУ / Мат. операции
Папкаsau/lt/
Типлогический
Уровеньlogic
sym<
body<
Связи компонента (порты)
in2
in
left
Опорное значение $x_2$
out
out
right
Результат $y \in \{0, 1\}$
Не применимо.
Параметры и состояние
Входные параметры
Не имеет параметров.
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = [\,x_1 < x_2\,]
\]
io.write("out", 1.0 if io.read("in1") < io.read("in2") else 0.0).
Связанные компоненты
См. sau_eq, sau_gt.
Компаратор (==)
sau_eq
Логический
логическийСАУ / Мат. операцииsau/eq/
Компаратор: $y = 1$, если $|x_1 - x_2| \le \varepsilon$, иначе
$y = 0$. Используется для контроля попадания в допуск
(«сигнализация отклонения»), для построения логики
разрешения при совпадении уставки и текущего значения.
Без состояния.
io.write("out", 1.0 if abs(io.read("in1") - io.read("in2")) <= eps else 0.0).
Связанные компоненты
sau_gt, sau_lt — другие
компараторы;
sau_and, sau_or — логические
операции над результатами.
Логическое И
sau_and
Логический
логическийСАУ / Мат. операцииsau/and/
Конъюнкция двух бинарных сигналов: $y = 1$, если ОБА входа
превышают порог threshold, иначе $y = 0$. Используется
для построения релейно-логических схем, схем разрешения
и блокировок. Без состояния.
sau_eq, sau_gt, sau_lt —
компараторы (могут подаваться на вход как бинарные
сигналы).
Логическое ИЛИ
sau_or
Логический
логическийСАУ / Мат. операцииsau/or/
Дизъюнкция двух бинарных сигналов: $y = 1$, если хотя бы
один вход превышает порог threshold, иначе $y = 0$.
Используется в релейно-логических схемах, схемах разрешения,
сигнализации. Без состояния.
Инверсия бинарного сигнала: $y = 1$, если вход НЕ превышает
порог threshold, иначе $y = 0$. Без состояния.
SPEC.folderСАУ / Мат. операции
Папкаsau/not/
Типлогический
Уровеньlogic
symNOT
bodyNOT
Связи компонента (порты)
out
out
right
Инвертированный сигнал $y$
Не применимо.
Параметры и состояние
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = \neg [\,x > \mathrm{threshold}\,]
\]
thr = io.param("threshold", 0.5).
x = io.read("in").
io.write("out", 0.0 if x > thr else 1.0).
Связанные компоненты
См. sau_and, sau_or.
Ограничитель
sau_saturation
Логический
логическийСАУ / Мат. операцииsau/saturation/
Кусочно-линейная нелинейность типа «насыщение»: выход
$y = \mathrm{clamp}(x, y_{\min}, y_{\max})$. Применяется для
ограничения управляющего сигнала (выход ПИД-регулятора —
в диапазон $0 \ldots 1$, открытие клапана — $0 \ldots 1$,
и т. п.), для моделирования физических ограничений
приводов. Без состояния; ставится на логическом слое после
звена, дающего неограниченный сигнал.
SPEC.folderСАУ / Мат. операции
Папкаsau/saturation/
Типлогический
Уровеньlogic
symSat
bodySat
Связи компонента (порты)
out
out
right
Ограниченный сигнал $y$
Не применимо.
Параметры и состояние
Входные параметры
upper
$\phantom{-}1.0$
ед.
number
Верхний предел $y_{\max}$
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = \mathrm{clamp}(x, y_{\min}, y_{\max}) =
\begin{cases}
y_{\min}, & x \le y_{\min}, \\
y_{\max}, & x \ge y_{\max}, \\
x, & \text{иначе}.
\end{cases}
\]
x = io.read("in"), lo = io.param("lower", -1.0),
hi = io.param("upper", 1.0).
Сумматор с настраиваемыми знаками слагаемых. По умолчанию
сложение двух входов ($y = x_1 + x_2$), но строкой
signs можно задать любую комбинацию знаков
("++", "+−", "−+", "−−"), то есть получить вычитание.
Используется как типовой узел САУ для вычисления ошибки
регулирования ($\varepsilon = x - x_{\text{set}}$) и
алгебраической комбинации нескольких сигналов в один. Без
внутреннего состояния, чистая алгебра на каждом тике.
Считать signs = io.text("signs", "++"),
нормализовать Unicode-минус − в ASCII -.
Пройти по символам signs: если "-" —
вычесть соответствующий вход, иначе — прибавить.
io.write("out", result).
Связанные компоненты
Часто используется с sau_gain (масштабирование
ошибки) и pid (вход — ошибка).
Умножитель
sau_product
Логический
логическийСАУ / Мат. операцииsau/product/
Поэлементное произведение двух входных сигналов: $y = x_1 \cdot x_2$. Используется для моделирования нелинейных
звеньев, перемножения управляющих воздействий (например, для
«холодного»/«горячего» регулирования), расчёта мощности
($P = U \cdot I$). Без состояния.
SPEC.folderСАУ / Мат. операции
Папкаsau/product/
Типлогический
Уровеньlogic
sym$\times$
body$\times$
Связи компонента (порты)
in2
in
left
Второй множитель $x_2$
out
out
right
Произведение $y$
Не применимо.
Параметры и состояние
Входные параметры
Не имеет параметров (только входы).
Состояния и интегрирование
Состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = x_1 \cdot x_2
\]
x1 = io.read("in1"), x2 = io.read("in2").
io.write("out", x1 * x2).
Связанные компоненты
sau_gain — для масштабирования одного из
множителей;
sau_sum, sau_div (если есть) —
другие матем. операции.
Усилитель
sau_gain
Логический
логическийСАУ / Мат. операцииsau/gain/
Линейный усилитель (безынерционное пропорциональное звено):
выход равен входу, умноженному на коэффициент $K$. Является
самым употребительным блоком САУ — используется как
П-регулятор в учебных задачах ТАУ, для масштабирования
сигналов между подсистемами (например, для согласования
диапазонов 0..1 и физических единиц), а также как тестовое
звено при оценке статической ошибки. Без внутреннего
состояния, чистая алгебра.
SPEC.folderСАУ / Мат. операции
Папкаsau/gain/
Типлогический
Уровеньlogic
symK
bodyK
Связи компонента (порты)
out
out
right
Выходной сигнал $y$
Не применимо.
Параметры и состояние
Состояния и интегрирование
Внутреннее состояние отсутствует.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
\[
y = K \cdot x
\]
x = io.read("in").
K = io.param("K", 1.0).
io.write("out", K * x).
Связанные компоненты
sau_sum — для получения ошибки
регулирования;
sau_integrator — интегрирующее звено, в
паре с gain образует ПИ-регулятор;
pid — заменяется gain при
$K_i = K_d = 0$.
Генератор шума
sau_noise
Логический
логическийСАУ/Источники и приёмникиsau/noise/
Источник нормально распределённого случайного сигнала:
$y \sim \mathcal{N}(\mu, \sigma^2)$. Используется для
тестирования устойчивости контуров регулирования и
фильтров к шуму измерений, для имитации
случайных возмущений, для статистического анализа
(многократные прогоны с разными seed). Состояние:
random.Random создаётся при первом тике и
сохраняется в io.state["rng"] (это даёт
детерминированный поток случайных чисел на всём
прогоне; seed можно поменять через параметр
seed).
SPEC.folderСАУ/Источники и приёмники
Папкаsau/noise/
Типлогический
Уровеньlogic
symnoise
bodynoise
Связи компонента (порты)
Не применимо.
Параметры и состояние
Входные параметры
std
$1.0$
ед.
number
Стандартное отклонение $\sigma$
seed
$42$
—
int
Seed инициализации ГСЧ
Состояния и интегрирование
Внутреннее состояние: rng (ГСЧ). Метод
интегрирования не используется (генератор не
интегрируется, он выдаёт значение).
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
rng = io.state.get("rng").
Если rng is None:
rng = random.Random(int(io.param("seed",
42)));
io.state["rng"] = rng.
sau_sum, sau_gain,
sau_integrator — для добавления
шума к сигналу управления (моделирование
возмущений).
sau_scope — для визуализации
временного ряда шума.
Контроллер
СГМС
sgms_controller
Логический
логическийСтенды/СГМСstands/sgms_controller/
Блок «Контроллер СГМС» — host / Renode / real
(этап 14, каркас). Физика объекта живёт в схеме
ORPHYS; этот блок задаёт mode исполнения
(host, renode, real) и
TCP-параметры подключения. Порты данных
(CH1, CH2, KEY/GPIO, GEN, ADC/AIN,
PWM и др.) подтягиваются при выборе блока / смене
project / кнопке «Обновить порты» через
derivePorts(project.io) / SgmsIoMap
.toBlockNodes (на стороне Electron/renderer). В
SPEC указаны только диагностические выходы;
IO-пины добавляются динамически. Используется как
интеграционная точка для СГМС-проектов (лабораторные
работы с эмуляцией Renode или реальной платой STM32).
SPEC.folderСтенды/СГМС
Папкаstands/sgms_controller/
Типлогический
Уровеньlogic
symeSGMS
bodySGMS\nctl
Связи компонента (порты)
diag_cycle
out
right
Диагностика: цикл выполнения, мкс
diag_overdue
out
right
Диагностика: флаг «overdue» (1/0)
В SPEC перечислены только эти три порта —
диагностические. Данные-порты (CH1, CH2,
KEY, GPIO, GEN, ADC, AIN, PWM и др.) добавляются
динамически через derivePorts(project.io).
Не применимо.
Параметры и состояние
Входные параметры
mode
«renode»
—
combo
Режим исполнения: host, renode, real
host
«127.0.0.1»
—
string
Хост TCP-сервера ORPHYS
port
$1111$
—
number
Порт TCP
profile
«stm32-lab1»
—
string
Профиль платы
elf
«»
—
string
Путь к .elf (renode)
autoDeploy
True
—
bool
Автодеплой
board
«stm32f769-lab»
—
string
Целевая плата
Состояния и интегрирование
Внутреннее состояние: connected,
cycle_us, overdue, и др.
(поднимается в Electron). Метод интегрирования не
используется.
COM-фасад над serial-мостом (Electron IPC
window.marsIO). На тике шины публикует
последние принятые сигналы CH1/CH2
(если инжектированы через state / внешний runtime) и
читает входы k1–k4 для кодирования
KEY-команды (4-битный код). Реальный open/close COM и
сериал-обмен выполняются в renderer через
window.marsIO (отдельный процесс). Используется
как интерфейс между схемой ORPHYS и физическим устройством
по сериал-порту (COM).
Внутреннее состояние: io.state["ch1_last"],
io.state["ch2_last"], io.state["keys"].
Метод интегрирования не используется (компонент
транслирует state в выходы и входы в код).
TCP-клиент для подключения схемы ORPHYS к серверу другого
инстанса MARS. Принимает 4 кнопки (k1–k4)
и отдаёт 2 аналоговых канала (CH1, CH2).
Логика обмена и формирования кадра — в Electron main
(tcp-stand-client). Используется для
двухмашинных стендов: один ORPHYS эмулирует оборудование,
другой — управляет им через TCP.
Логика обмена и декодирования кадров — в Electron
main (tcp-stand-server). Используется для
приёма данных от реального оборудования по TCP
(STM32, Arduino с Ethernet) или для
связи двух ORPHYS-инстансов.
SPEC.folderСтенды/Транспорт
Папкаstands/tcp_stand_server/
Типлогический
Уровеньlogic
symTCPs
bodyTCP\nSRV
Связи компонента (порты)
k2
in
left
Кнопка 2
k3
in
left
Кнопка 3
k4
in
left
Кнопка 4
in_CH1
in
left
Аналоговый вход 1 (от шины)
in_CH2
in
left
Аналоговый вход 2 (от шины)
CH1
out
right
Канал 1 (для шины)
CH2
out
right
Канал 2 (для шины)
cmd_out
out
right
Сформированная команда
Не применимо.
Параметры и состояние
Входные параметры
port
$1111$
—
number
Порт
profile
«stm32-lab1»
—
string
Профиль кадра
mode
«device»
—
combo
Режим: device / publish / isul
autoStart
True
—
bool
Автозапуск
genFreq
$50$
Гц
number
Частота генератора (для isul)
genPhase
$0$
—
number
Фаза
genForm
$0$
—
number
Форма сигнала
Состояния и интегрирование
Внутреннее состояние: ch1_last,
ch2_last, keys.
Математическая модель
Не применимо для логических/мета компонентов.
Алгоритм работы
io.write("CH1", ...) — выдать
последний принятый сэмпл канала 1
(для режима device — от
удалённого устройства; иначе — pass-through
из in_CH1).
Аналогично для CH2.
Считать k1, k2, k3, k4 из входов
(бинаризация по 0.5), in_CH1, in_CH2
(pass-through).
io.state["keys"] = [k1, k2, k3, k4].
io.write("cmd_out", k1*8 + k2*4 + k3*2
+ k4).
(Полный код функции занимает $\sim 17$ строк после
декоратора; см. исходный файл.)
Связанные компоненты
stands/tcp_stand_client — парный
TCP-клиент (в режиме publish).
Заглушка Arduino: компонент палитры, представляющий
стенд-эмулятор (TCP-сервер / stub / serial-эмулятор).
Реальная логика стенда живёт в Electron main
(fake-bridge → arduino-fake-stand) и
пишет значения в io.state (расстояние в
state["distance_cm"], статус соединения в
state["connected"]). На каждом тике шины
компонент отдаёт эти значения как сигналы. Используется
для тестирования схем ORPHYS без реального оборудования.
SPEC.folderСтенды/Фейки
Папкаstands/arduino_fake_stand/
Типлогический
Уровеньlogic
symfARD
bodyARD\nfake
Связи компонента (порты)
status
out
right
Статус соединения (1/0)
Не применимо.
Параметры и состояние
Входные параметры
host
«0.0.0.0»
—
string
Хост (для режима tcp)
port
$9000$
—
number
Порт (для tcp)
path
«COM10»
—
string
COM-путь (для serial)
baud
$115200$
—
number
Baud rate (для serial)
hz
$5$
Гц
number
Частота обновления (для runtime)
autoStart
True
—
bool
Автозапуск runtime при инициализации
Состояния и интегрирование
Внутреннее состояние — io.state["distance_cm"],
io.state["connected"]. Метод интегрирования не
используется (компонент читает чужие значения и
транслирует их в выходные порты).
stands/tcp_stand_client,
stands/com_source — транспорты,
через которые идёт реальный обмен.
stands/stm_fake_stand — аналог для
STM32.
sau_scope, sau_display —
для визуализации.
Эмулятор STM32
stm_fake_stand
Логический
логическийСтенды/Эмуляторыstands/stm_fake_stand/
Заглушка STM32: компонент палитры, представляющий
программный стенд-эмулятор (TCP-клиент). Эмулятор
живёт в Electron main (fake-bridge →
stm-fake-stand), шлёт кадры АЦП как прошивка.
На тике шины отдаёт статус соединения. Каналы
CH1/CH2 приходят через соседний
TCP-сервер (tcp_stand_server). Внимание:
для прошивки .elf используйте схему HIL (Renode),
не этот блок. Используется для тестирования без
реального STM32.