Files
SystemSimulationApp/app/simulation/components/amesim/signals/sources.py
T

80 lines
6.8 KiB
Python

"""Component parameters, ports and output definitions; numerical equations execute in C."""
from __future__ import annotations
from collections.abc import Mapping
from app.simulation.core.base import AlgebraicComponent
from app.simulation.core.catalog import ComponentDisplaySpec, ParameterGroupDisplaySpec, PortDisplaySpec
from app.simulation.core.metadata import ParameterCondition, ParameterDefinition, ParameterOption, ResultVariableDefinition
from app.simulation.core.medium import IdealGasMedium
from app.simulation.core.ports import PortDefinition
def _ud00_stage_parameters(index: int) -> tuple[ParameterDefinition, ...]:
visible_when = () if index == 1 else (ParameterCondition('nstages', tuple((float(stage_count) for stage_count in range(index, 9)))),)
return (ParameterDefinition(f'start{index}', 0.0 if index == 1 else 1.0, label=f'第 {index} 段起点', quantity='dimensionless', unit='', description=f'第 {index} 段开始时的输出值。', visible_when=visible_when), ParameterDefinition(f'end{index}', 1.0, label=f'第 {index} 段终点', quantity='dimensionless', unit='', description=f'第 {index} 段结束时的输出值。', visible_when=visible_when), ParameterDefinition(f't{index}', 1.0 if index == 1 else 0.0, label=f'第 {index} 段时长', quantity='time', unit='s', minimum=0.0, description=f'第 {index} 段的持续时间。', visible_when=visible_when))
_UD00_STAGE_PARAMETERS = tuple((parameter for stage_index in range(1, 9) for parameter in _ud00_stage_parameters(stage_index)))
class AmesimStep0(AlgebraicComponent):
"""AMESim STEP0 scalar step signal source."""
MODEL_TYPE = 'amesim_step0'
MODEL_VERSION = '0.1.0'
PORTS = (PortDefinition.signal('out', nominal_role='output'),)
PARAMETERS = (ParameterDefinition('initial', 0.0, label='初始值', quantity='dimensionless', unit=''), ParameterDefinition('final', 1.0, label='阶跃后值', quantity='dimensionless', unit=''), ParameterDefinition('time', 0.0, label='阶跃时间', quantity='time', unit='s'))
RESULT_VARIABLES = (ResultVariableDefinition('y', '输出', 'dimensionless', '', 'signal', 10),)
DISPLAY = ComponentDisplaySpec(label='STEP0 阶跃信号', library_id='amesim', category_id='signals', symbol='amesim_step0', ports=(PortDisplaySpec('out', 'right', order=10),), order=10)
def __init__(self, name: str, medium: IdealGasMedium, *, initial: float=0.0, final: float=1.0, time: float=0.0) -> None:
super().__init__(name=name)
self.set_parameter_values({'initial': initial, 'final': final, 'time': time})
self.initial = float(initial)
self.final = float(final)
self.time = float(time)
self.out = self.register_declared_port('out')
@classmethod
def create(cls, *, name: str, medium: IdealGasMedium, parameters: Mapping[str, float]) -> 'AmesimStep0':
return cls(name=name, medium=medium, initial=parameters['initial'], final=parameters['final'], time=parameters['time'])
EQUATIONS = ()
class AmesimUd00(AlgebraicComponent):
"""AMESim UD00 piecewise-linear scalar signal source."""
MODEL_TYPE = 'amesim_ud00'
MODEL_VERSION = '0.2.0'
PORTS = (PortDefinition.signal('out', nominal_role='output'),)
PARAMETERS = (ParameterDefinition('tstart', 0.0, label='启动时间', quantity='time', unit='s', description='分段信号开始输出第一段之前的等待时间。'), *_UD00_STAGE_PARAMETERS, ParameterDefinition('nstages', 1.0, label='段数', quantity='dimensionless', unit='', minimum=1.0, maximum=8.0, editor='choice', options=tuple((ParameterOption(float(stage_count), str(stage_count)) for stage_count in range(1, 9))), description='参与输出计算的有效线性分段数量。'), ParameterDefinition('iscyclic', 0.0, label='循环', quantity='dimensionless', unit='', minimum=0.0, maximum=1.0, editor='choice', options=(ParameterOption(0.0, '否'), ParameterOption(1.0, '是')), description='当前公共协议编码:0 表示单次输出,1 表示循环输出。'))
RESULT_VARIABLES = (ResultVariableDefinition('y', '输出', 'dimensionless', '', 'signal', 10),)
DISPLAY = ComponentDisplaySpec(label='UD00 分段线性信号', library_id='amesim', category_id='signals', symbol='amesim_ud00', ports=(PortDisplaySpec('out', 'right', order=10),), order=20, parameter_groups=(ParameterGroupDisplaySpec(id='stages', label='分段参数', parameters=tuple((parameter.name for parameter in _UD00_STAGE_PARAMETERS)), order=10),))
def __init__(self, name: str, medium: IdealGasMedium, *, tstart: float=0.0, starts: tuple[float, ...]=(0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), ends: tuple[float, ...]=(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), durations: tuple[float, ...]=(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), nstages: int=1, iscyclic: bool=False) -> None:
super().__init__(name=name)
if len(starts) != 8 or len(ends) != 8 or len(durations) != 8:
raise ValueError('UD00 requires exactly eight start, end, and duration values.')
if nstages < 1 or nstages > 8:
raise ValueError('UD00 nstages must be between 1 and 8.')
self.tstart = float(tstart)
self.starts = tuple((float(value) for value in starts))
self.ends = tuple((float(value) for value in ends))
self.durations = tuple((float(value) for value in durations))
self.nstages = int(nstages)
self.iscyclic = bool(iscyclic)
values: dict[str, float] = {'tstart': self.tstart, 'nstages': float(self.nstages), 'iscyclic': float(int(self.iscyclic))}
for index in range(1, 9):
values[f'start{index}'] = self.starts[index - 1]
values[f'end{index}'] = self.ends[index - 1]
values[f't{index}'] = self.durations[index - 1]
self.set_parameter_values(values)
self.out = self.register_declared_port('out')
@classmethod
def create(cls, *, name: str, medium: IdealGasMedium, parameters: Mapping[str, float]) -> 'AmesimUd00':
nstages = parameters['nstages']
iscyclic = parameters['iscyclic']
definitions = {definition.name: definition for definition in cls.PARAMETERS}
for parameter_name, value in (('nstages', nstages), ('iscyclic', iscyclic)):
numeric_value = float(value)
if not numeric_value.is_integer():
raise ValueError(f'UD00 {parameter_name} must be an integer.')
message = definitions[parameter_name].validation_message(numeric_value)
if message is not None:
raise ValueError(f'UD00 {parameter_name} {message}.')
return cls(name=name, medium=medium, tstart=parameters['tstart'], starts=tuple((parameters[f'start{index}'] for index in range(1, 9))), ends=tuple((parameters[f'end{index}'] for index in range(1, 9))), durations=tuple((parameters[f't{index}'] for index in range(1, 9))), nstages=int(nstages), iscyclic=bool(int(iscyclic)))
EQUATIONS = ()