pySimBlocks 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/advanced/hardware/block_diagram.py +162 -0
- examples/advanced/hardware/camera.py +93 -0
- examples/advanced/hardware/gui_emio.py +231 -0
- examples/advanced/hardware/lmi.py +69 -0
- examples/advanced/hardware/main.py +57 -0
- examples/advanced/hardware/parameters.py +54 -0
- examples/advanced/qp_problem/params.py +10 -0
- examples/advanced/qp_problem/run.py +14 -0
- examples/advanced/sofa/gui/finger/Finger.py +108 -0
- examples/advanced/sofa/gui/finger/FingerController.py +53 -0
- examples/advanced/sofa/gui/finger/parameters_auto.py +22 -0
- examples/advanced/sofa/gui/sofa_plant/run.py +14 -0
- examples/advanced/sofa/python/Finger.py +107 -0
- examples/advanced/sofa/python/FingerController.py +48 -0
- examples/advanced/sofa/python/closedloop.py +64 -0
- examples/advanced/sofa/python/openloop.py +58 -0
- examples/basics/algebraic_function/g.py +7 -0
- examples/basics/algebraic_function/run.py +14 -0
- examples/basics/dc_motor/gui/run.py +14 -0
- examples/basics/dc_motor/multiple_order.py +91 -0
- examples/basics/dc_motor/openloop.py +62 -0
- examples/basics/dc_motor/pi.py +99 -0
- examples/basics/dc_motor/pid.py +118 -0
- examples/basics/dc_motor/pid_block.py +82 -0
- examples/basics/dc_motor/pid_block_vs_manual.py +143 -0
- examples/basics/external/parameters.py +4 -0
- examples/basics/external/run.py +14 -0
- examples/basics/file_sources/temp.py +16 -0
- examples/basics/observer.py +76 -0
- examples/basics/state_feedback/gui/parameters.py +9 -0
- examples/basics/state_feedback/gui/run.py +14 -0
- examples/basics/state_feedback/state_feedback.py +102 -0
- examples/basics/state_space/linear/gui/run.py +14 -0
- examples/basics/state_space/linear/ss_block.py +89 -0
- examples/basics/state_space/linear/ss_manual.py +105 -0
- examples/basics/state_space/non_linear/nlss.py +47 -0
- examples/basics/state_space/non_linear/run.py +14 -0
- examples/basics/state_space/polytope/params.py +39 -0
- examples/basics/state_space/polytope/weights.py +12 -0
- examples/comparison/simulink/convert.py +29 -0
- examples/comparison/simulink/openloop.py +127 -0
- examples/comparison/simulink/pi.py +148 -0
- examples/comparison/simulink/pid.py +154 -0
- examples/comparison/simulink/pid_backward.py +155 -0
- examples/quick_start/filter.py +35 -0
- examples/quick_start/gui/run.py +14 -0
- examples/tutorials/tutorial_1_python/main.py +99 -0
- examples/tutorials/tutorial_3_sofa/finger/Finger.py +120 -0
- examples/tutorials/tutorial_3_sofa/finger/FingerController.py +37 -0
- pySimBlocks/__init__.py +35 -0
- pySimBlocks/blocks/__init__.py +68 -0
- pySimBlocks/blocks/controllers/__init__.py +27 -0
- pySimBlocks/blocks/controllers/pid.py +250 -0
- pySimBlocks/blocks/controllers/state_feedback.py +141 -0
- pySimBlocks/blocks/interfaces/__init__.py +27 -0
- pySimBlocks/blocks/interfaces/external_input.py +107 -0
- pySimBlocks/blocks/interfaces/external_output.py +113 -0
- pySimBlocks/blocks/observers/__init__.py +23 -0
- pySimBlocks/blocks/observers/luenberger.py +175 -0
- pySimBlocks/blocks/operators/__init__.py +47 -0
- pySimBlocks/blocks/operators/algebraic_function.py +258 -0
- pySimBlocks/blocks/operators/dead_zone.py +186 -0
- pySimBlocks/blocks/operators/delay.py +254 -0
- pySimBlocks/blocks/operators/demux.py +123 -0
- pySimBlocks/blocks/operators/discrete_derivator.py +237 -0
- pySimBlocks/blocks/operators/discrete_integrator.py +265 -0
- pySimBlocks/blocks/operators/gain.py +294 -0
- pySimBlocks/blocks/operators/mux.py +131 -0
- pySimBlocks/blocks/operators/product.py +194 -0
- pySimBlocks/blocks/operators/rate_limiter.py +214 -0
- pySimBlocks/blocks/operators/saturation.py +178 -0
- pySimBlocks/blocks/operators/sum.py +188 -0
- pySimBlocks/blocks/operators/zero_order_hold.py +141 -0
- pySimBlocks/blocks/optimizers/__init__.py +23 -0
- pySimBlocks/blocks/optimizers/quadratic_program.py +326 -0
- pySimBlocks/blocks/sources/__init__.py +37 -0
- pySimBlocks/blocks/sources/chirp.py +168 -0
- pySimBlocks/blocks/sources/constant.py +82 -0
- pySimBlocks/blocks/sources/file_source.py +294 -0
- pySimBlocks/blocks/sources/function_source.py +197 -0
- pySimBlocks/blocks/sources/ramp.py +99 -0
- pySimBlocks/blocks/sources/sinusoidal.py +113 -0
- pySimBlocks/blocks/sources/step.py +138 -0
- pySimBlocks/blocks/sources/white_noise.py +107 -0
- pySimBlocks/blocks/systems/__init__.py +27 -0
- pySimBlocks/blocks/systems/linear_state_space.py +180 -0
- pySimBlocks/blocks/systems/non_linear_state_space.py +309 -0
- pySimBlocks/blocks/systems/polytopic_state_space.py +193 -0
- pySimBlocks/blocks/systems/sofa/__init__.py +30 -0
- pySimBlocks/blocks/systems/sofa/sofa_controller.py +472 -0
- pySimBlocks/blocks/systems/sofa/sofa_exchange_i_o.py +120 -0
- pySimBlocks/blocks/systems/sofa/sofa_plant.py +306 -0
- pySimBlocks/cli.py +127 -0
- pySimBlocks/core/__init__.py +32 -0
- pySimBlocks/core/block.py +167 -0
- pySimBlocks/core/block_source.py +94 -0
- pySimBlocks/core/config.py +90 -0
- pySimBlocks/core/fixed_time_manager.py +46 -0
- pySimBlocks/core/model.py +250 -0
- pySimBlocks/core/scheduler.py +30 -0
- pySimBlocks/core/simulator.py +329 -0
- pySimBlocks/core/task.py +73 -0
- pySimBlocks/docs/blocks/controllers/pid.md +78 -0
- pySimBlocks/docs/blocks/controllers/state_feedback.md +60 -0
- pySimBlocks/docs/blocks/interfaces/external_input.md +39 -0
- pySimBlocks/docs/blocks/interfaces/external_output.md +39 -0
- pySimBlocks/docs/blocks/observers/luenberger.md +70 -0
- pySimBlocks/docs/blocks/operators/algebraic_function.md +76 -0
- pySimBlocks/docs/blocks/operators/dead_zone.md +67 -0
- pySimBlocks/docs/blocks/operators/delay.md +76 -0
- pySimBlocks/docs/blocks/operators/demux.md +64 -0
- pySimBlocks/docs/blocks/operators/discrete_derivator.md +61 -0
- pySimBlocks/docs/blocks/operators/discrete_integrator.md +87 -0
- pySimBlocks/docs/blocks/operators/gain.md +97 -0
- pySimBlocks/docs/blocks/operators/mux.md +64 -0
- pySimBlocks/docs/blocks/operators/product.md +51 -0
- pySimBlocks/docs/blocks/operators/rate_limiter.md +70 -0
- pySimBlocks/docs/blocks/operators/saturation.md +62 -0
- pySimBlocks/docs/blocks/operators/sum.md +49 -0
- pySimBlocks/docs/blocks/operators/zero_order_hold.md +61 -0
- pySimBlocks/docs/blocks/optimizers/quadratic_program.md +98 -0
- pySimBlocks/docs/blocks/sources/chirp.md +102 -0
- pySimBlocks/docs/blocks/sources/constant.md +53 -0
- pySimBlocks/docs/blocks/sources/file_source.md +51 -0
- pySimBlocks/docs/blocks/sources/function_source.md +52 -0
- pySimBlocks/docs/blocks/sources/ramp.md +58 -0
- pySimBlocks/docs/blocks/sources/sinusoidal.md +60 -0
- pySimBlocks/docs/blocks/sources/step.md +63 -0
- pySimBlocks/docs/blocks/sources/white_noise.md +58 -0
- pySimBlocks/docs/blocks/systems/linear_state_space.md +66 -0
- pySimBlocks/docs/blocks/systems/non_linear_state_space.md +90 -0
- pySimBlocks/docs/blocks/systems/polytopic_state_space.md +72 -0
- pySimBlocks/docs/blocks/systems/sofa/sofa_exchange_i_o.md +63 -0
- pySimBlocks/docs/blocks/systems/sofa/sofa_plant.md +62 -0
- pySimBlocks/gui/__init__.py +20 -0
- pySimBlocks/gui/addons/__init__.py +19 -0
- pySimBlocks/gui/addons/sofa/__init__.py +19 -0
- pySimBlocks/gui/addons/sofa/sofa_dialog.py +190 -0
- pySimBlocks/gui/addons/sofa/sofa_service.py +209 -0
- pySimBlocks/gui/blocks/block_dialog_session.py +47 -0
- pySimBlocks/gui/blocks/block_meta.py +408 -0
- pySimBlocks/gui/blocks/controllers/pid.py +116 -0
- pySimBlocks/gui/blocks/controllers/state_feedback.py +80 -0
- pySimBlocks/gui/blocks/interfaces/external_input.py +64 -0
- pySimBlocks/gui/blocks/interfaces/external_output.py +63 -0
- pySimBlocks/gui/blocks/observers/luenberger.py +108 -0
- pySimBlocks/gui/blocks/operators/algebraic_function.py +232 -0
- pySimBlocks/gui/blocks/operators/dead_zone.py +79 -0
- pySimBlocks/gui/blocks/operators/delay.py +79 -0
- pySimBlocks/gui/blocks/operators/demux.py +98 -0
- pySimBlocks/gui/blocks/operators/discrete_derivator.py +67 -0
- pySimBlocks/gui/blocks/operators/discrete_integrator.py +80 -0
- pySimBlocks/gui/blocks/operators/gain.py +79 -0
- pySimBlocks/gui/blocks/operators/mux.py +100 -0
- pySimBlocks/gui/blocks/operators/product.py +109 -0
- pySimBlocks/gui/blocks/operators/rate_limiter.py +79 -0
- pySimBlocks/gui/blocks/operators/saturation.py +72 -0
- pySimBlocks/gui/blocks/operators/sum.py +91 -0
- pySimBlocks/gui/blocks/operators/zero_order_hold.py +64 -0
- pySimBlocks/gui/blocks/optimizers/quadratic_program.py +128 -0
- pySimBlocks/gui/blocks/parameter_meta.py +34 -0
- pySimBlocks/gui/blocks/port_meta.py +31 -0
- pySimBlocks/gui/blocks/sources/chirp.py +146 -0
- pySimBlocks/gui/blocks/sources/constant.py +63 -0
- pySimBlocks/gui/blocks/sources/file_source.py +196 -0
- pySimBlocks/gui/blocks/sources/function_source.py +202 -0
- pySimBlocks/gui/blocks/sources/ramp.py +73 -0
- pySimBlocks/gui/blocks/sources/sinusoidal.py +81 -0
- pySimBlocks/gui/blocks/sources/step.py +83 -0
- pySimBlocks/gui/blocks/sources/white_noise.py +70 -0
- pySimBlocks/gui/blocks/systems/linear_state_space.py +102 -0
- pySimBlocks/gui/blocks/systems/non_linear_state_space.py +233 -0
- pySimBlocks/gui/blocks/systems/polytopic_state_space.py +109 -0
- pySimBlocks/gui/blocks/systems/sofa/sofa_exchange_i_o.py +221 -0
- pySimBlocks/gui/blocks/systems/sofa/sofa_plant.py +220 -0
- pySimBlocks/gui/dialogs/__init__.py +19 -0
- pySimBlocks/gui/dialogs/block_dialog.py +125 -0
- pySimBlocks/gui/dialogs/display_yaml_dialog.py +89 -0
- pySimBlocks/gui/dialogs/help_dialog.py +39 -0
- pySimBlocks/gui/dialogs/plot_dialog.py +230 -0
- pySimBlocks/gui/dialogs/settings/plots.py +187 -0
- pySimBlocks/gui/dialogs/settings/project.py +146 -0
- pySimBlocks/gui/dialogs/settings/simulation.py +137 -0
- pySimBlocks/gui/dialogs/settings_dialog.py +88 -0
- pySimBlocks/gui/dialogs/unsaved_dialog.py +92 -0
- pySimBlocks/gui/editor.py +49 -0
- pySimBlocks/gui/graphics/__init__.py +29 -0
- pySimBlocks/gui/graphics/block_item.py +289 -0
- pySimBlocks/gui/graphics/connection_item.py +266 -0
- pySimBlocks/gui/graphics/port_item.py +153 -0
- pySimBlocks/gui/graphics/theme.py +119 -0
- pySimBlocks/gui/main_window.py +162 -0
- pySimBlocks/gui/models/__init__.py +31 -0
- pySimBlocks/gui/models/block_instance.py +114 -0
- pySimBlocks/gui/models/connection_instance.py +43 -0
- pySimBlocks/gui/models/port_instance.py +52 -0
- pySimBlocks/gui/models/project_simulation_params.py +50 -0
- pySimBlocks/gui/models/project_state.py +114 -0
- pySimBlocks/gui/project_controller.py +302 -0
- pySimBlocks/gui/services/__init__.py +20 -0
- pySimBlocks/gui/services/project_loader.py +381 -0
- pySimBlocks/gui/services/project_saver.py +68 -0
- pySimBlocks/gui/services/simulation_runner.py +66 -0
- pySimBlocks/gui/services/yaml_tools.py +261 -0
- pySimBlocks/gui/widgets/__init__.py +19 -0
- pySimBlocks/gui/widgets/block_list.py +131 -0
- pySimBlocks/gui/widgets/diagram_view.py +312 -0
- pySimBlocks/gui/widgets/toolbar_view.py +161 -0
- pySimBlocks/project/__init__.py +35 -0
- pySimBlocks/project/build_model.py +92 -0
- pySimBlocks/project/generate_run_script.py +109 -0
- pySimBlocks/project/generate_sofa_controller.py +215 -0
- pySimBlocks/project/load_project_config.py +197 -0
- pySimBlocks/project/load_simulation_config.py +166 -0
- pySimBlocks/project/load_simulator.py +45 -0
- pySimBlocks/project/plot_from_config.py +174 -0
- pySimBlocks/project/pySimBlocks_blocks_index.yaml +106 -0
- pySimBlocks/real_time/__init__.py +23 -0
- pySimBlocks/real_time/real_time_runner.py +148 -0
- pySimBlocks/tools/__init__.py +19 -0
- pySimBlocks/tools/blocks_registry.py +141 -0
- pySimBlocks/tools/generate_blocks_index.py +124 -0
- pysimblocks-0.1.0.dist-info/METADATA +180 -0
- pysimblocks-0.1.0.dist-info/RECORD +262 -0
- pysimblocks-0.1.0.dist-info/WHEEL +5 -0
- pysimblocks-0.1.0.dist-info/entry_points.txt +2 -0
- pysimblocks-0.1.0.dist-info/licenses/LICENSE.md +165 -0
- pysimblocks-0.1.0.dist-info/top_level.txt +3 -0
- tests/blocks/controllers/test_pid.py +143 -0
- tests/blocks/controllers/test_state_feedback.py +193 -0
- tests/blocks/observers/test_luenberger.py +225 -0
- tests/blocks/operators/test_algebraic_function.py +230 -0
- tests/blocks/operators/test_dead_zone.py +106 -0
- tests/blocks/operators/test_delay.py +167 -0
- tests/blocks/operators/test_demux.py +111 -0
- tests/blocks/operators/test_discrete_derivator.py +160 -0
- tests/blocks/operators/test_discrete_integrator.py +149 -0
- tests/blocks/operators/test_gain.py +182 -0
- tests/blocks/operators/test_mux.py +101 -0
- tests/blocks/operators/test_product.py +171 -0
- tests/blocks/operators/test_rate_limiter.py +166 -0
- tests/blocks/operators/test_saturation.py +157 -0
- tests/blocks/operators/test_sum.py +183 -0
- tests/blocks/operators/test_zero_order_hold.py +106 -0
- tests/blocks/sources/test_chirp.py +157 -0
- tests/blocks/sources/test_constant.py +55 -0
- tests/blocks/sources/test_file_source.py +185 -0
- tests/blocks/sources/test_function_source.py +135 -0
- tests/blocks/sources/test_ramp.py +110 -0
- tests/blocks/sources/test_sinusoidal.py +113 -0
- tests/blocks/sources/test_step.py +76 -0
- tests/blocks/sources/test_white_noise.py +108 -0
- tests/blocks/systems/test_linear_state_space.py +135 -0
- tests/blocks/systems/test_polytopic_state_space.py +133 -0
- tests/core/test_core_errors_and_determinism.py +82 -0
- tests/core/test_core_multirate_tasks.py +88 -0
- tests/core/test_core_two_phase_and_propagation.py +132 -0
- tests/gui/main_window_open_test.py +162 -0
- tests/gui/test_block_meta_param_cache.py +16 -0
- tests/gui/test_file_source_meta.py +17 -0
- tests/gui/test_function_source_meta.py +28 -0
- tests/regression/test_simulink_dc_motor.py +217 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# ******************************************************************************
|
|
2
|
+
# pySimBlocks
|
|
3
|
+
# Copyright (c) 2026 Université de Lille & INRIA
|
|
4
|
+
# ******************************************************************************
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
# ******************************************************************************
|
|
18
|
+
# Authors: see Authors.txt
|
|
19
|
+
# ******************************************************************************
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import subprocess
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Literal
|
|
26
|
+
|
|
27
|
+
from PySide6.QtWidgets import QFormLayout, QLabel, QLineEdit, QPushButton
|
|
28
|
+
|
|
29
|
+
from pySimBlocks.gui.blocks.block_meta import BlockMeta, ParameterMeta
|
|
30
|
+
from pySimBlocks.gui.blocks.port_meta import PortMeta
|
|
31
|
+
from pySimBlocks.gui.models import BlockInstance, PortInstance
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class FunctionSourceMeta(BlockMeta):
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.name = "FunctionSource"
|
|
38
|
+
self.category = "sources"
|
|
39
|
+
self.type = "function_source"
|
|
40
|
+
self.summary = "User-defined source block y = f(t, dt)."
|
|
41
|
+
self.description = (
|
|
42
|
+
"This block evaluates a user-provided Python function with no inputs:\n\n"
|
|
43
|
+
" y = f(t, dt)\n\n"
|
|
44
|
+
"The function is loaded from an external Python file and executed at each\n"
|
|
45
|
+
"activation. The function must return a dict whose keys match\n"
|
|
46
|
+
"`output_keys`. One output port is created for each key."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
self.parameters = [
|
|
50
|
+
ParameterMeta(
|
|
51
|
+
name="file_path",
|
|
52
|
+
type="string",
|
|
53
|
+
required=True,
|
|
54
|
+
description=(
|
|
55
|
+
"Path to the Python file containing the function, relative to "
|
|
56
|
+
"the project.yaml file."
|
|
57
|
+
),
|
|
58
|
+
),
|
|
59
|
+
ParameterMeta(
|
|
60
|
+
name="function_name",
|
|
61
|
+
type="string",
|
|
62
|
+
required=True,
|
|
63
|
+
description="Name of the function to call inside the Python file.",
|
|
64
|
+
),
|
|
65
|
+
ParameterMeta(
|
|
66
|
+
name="output_keys",
|
|
67
|
+
type="list[string]",
|
|
68
|
+
required=True,
|
|
69
|
+
autofill=True,
|
|
70
|
+
default=["out"],
|
|
71
|
+
description="List of output port names. The function must return a dict with exactly these keys.",
|
|
72
|
+
),
|
|
73
|
+
ParameterMeta(
|
|
74
|
+
name="sample_time",
|
|
75
|
+
type="float",
|
|
76
|
+
description="Optional execution period of the block.",
|
|
77
|
+
),
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
self.outputs = [
|
|
81
|
+
PortMeta(
|
|
82
|
+
name="out",
|
|
83
|
+
display_as="",
|
|
84
|
+
shape=[],
|
|
85
|
+
description="Function output signals defined by output_keys.",
|
|
86
|
+
)
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
# --------------------------------------------------------------------------
|
|
90
|
+
# Port resolution
|
|
91
|
+
# --------------------------------------------------------------------------
|
|
92
|
+
def resolve_port_group(
|
|
93
|
+
self,
|
|
94
|
+
port_meta: PortMeta,
|
|
95
|
+
direction: Literal["input", "output"],
|
|
96
|
+
instance: "BlockInstance",
|
|
97
|
+
) -> list["PortInstance"]:
|
|
98
|
+
if direction == "output":
|
|
99
|
+
keys = instance.parameters.get("output_keys", [])
|
|
100
|
+
if keys is None:
|
|
101
|
+
return []
|
|
102
|
+
return [
|
|
103
|
+
PortInstance(
|
|
104
|
+
name=f"{key}",
|
|
105
|
+
display_as=key,
|
|
106
|
+
direction="output",
|
|
107
|
+
block=instance,
|
|
108
|
+
)
|
|
109
|
+
for key in keys
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
return super().resolve_port_group(port_meta, direction, instance)
|
|
113
|
+
|
|
114
|
+
# --------------------------------------------------------------------------
|
|
115
|
+
# Dialog methods
|
|
116
|
+
# --------------------------------------------------------------------------
|
|
117
|
+
def build_param(
|
|
118
|
+
self,
|
|
119
|
+
session,
|
|
120
|
+
form: QFormLayout,
|
|
121
|
+
readonly: bool = False,
|
|
122
|
+
):
|
|
123
|
+
name_edit = QLineEdit(session.instance.name)
|
|
124
|
+
name_edit.textChanged.connect(
|
|
125
|
+
lambda val: self._on_param_changed(val, "name", session, readonly)
|
|
126
|
+
)
|
|
127
|
+
form.addRow(QLabel("Block name:"), name_edit)
|
|
128
|
+
if readonly:
|
|
129
|
+
name_edit.setReadOnly(True)
|
|
130
|
+
session.name_edit = name_edit
|
|
131
|
+
|
|
132
|
+
for pmeta in self.parameters:
|
|
133
|
+
if pmeta.name == "file_path":
|
|
134
|
+
self.build_file_param_row(
|
|
135
|
+
session,
|
|
136
|
+
form,
|
|
137
|
+
pmeta,
|
|
138
|
+
readonly=readonly,
|
|
139
|
+
file_filter="Python files (*.py);;All files (*)",
|
|
140
|
+
)
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
label, widget = self._create_param_row(session, pmeta, readonly)
|
|
144
|
+
if widget is None:
|
|
145
|
+
continue
|
|
146
|
+
if readonly:
|
|
147
|
+
self._set_readonly_style(widget)
|
|
148
|
+
|
|
149
|
+
form.addRow(label, widget)
|
|
150
|
+
session.param_widgets[pmeta.name] = widget
|
|
151
|
+
session.param_labels[pmeta.name] = label
|
|
152
|
+
|
|
153
|
+
# ------------------------------------------------------
|
|
154
|
+
def build_post_param(self, session, form: QFormLayout, readonly: bool = False):
|
|
155
|
+
open_btn = QPushButton("Open file")
|
|
156
|
+
open_btn.clicked.connect(lambda: self._open_file_from_session(session))
|
|
157
|
+
form.addRow(QLabel(""), open_btn)
|
|
158
|
+
session.open_file_btn = open_btn
|
|
159
|
+
self._refresh_open_button_state(session)
|
|
160
|
+
|
|
161
|
+
# ------------------------------------------------------
|
|
162
|
+
def refresh_form(self, session):
|
|
163
|
+
super().refresh_form(session)
|
|
164
|
+
self._refresh_open_button_state(session)
|
|
165
|
+
|
|
166
|
+
# ------------------------------------------------------
|
|
167
|
+
def _resolve_file_path(self, session) -> Path | None:
|
|
168
|
+
raw = session.local_params.get("file_path")
|
|
169
|
+
if not raw:
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
path = Path(str(raw)).expanduser()
|
|
173
|
+
if not path.is_absolute() and session.project_dir is not None:
|
|
174
|
+
path = (session.project_dir / path).resolve()
|
|
175
|
+
return path
|
|
176
|
+
|
|
177
|
+
# ------------------------------------------------------
|
|
178
|
+
def _refresh_open_button_state(self, session) -> None:
|
|
179
|
+
btn = getattr(session, "open_file_btn", None)
|
|
180
|
+
if btn is None:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
target = self._resolve_file_path(session)
|
|
184
|
+
exists = target is not None and target.is_file()
|
|
185
|
+
btn.setEnabled(exists)
|
|
186
|
+
if exists:
|
|
187
|
+
btn.setToolTip(str(target))
|
|
188
|
+
else:
|
|
189
|
+
btn.setToolTip("Set a valid existing file_path to open the file.")
|
|
190
|
+
|
|
191
|
+
# ------------------------------------------------------
|
|
192
|
+
def _open_file_from_session(self, session) -> None:
|
|
193
|
+
target = self._resolve_file_path(session)
|
|
194
|
+
if target is None or not target.is_file():
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
if sys.platform.startswith("darwin"):
|
|
198
|
+
subprocess.Popen(["open", str(target)])
|
|
199
|
+
elif os.name == "nt":
|
|
200
|
+
os.startfile(str(target))
|
|
201
|
+
else:
|
|
202
|
+
subprocess.Popen(["xdg-open", str(target)])
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ******************************************************************************
|
|
2
|
+
# pySimBlocks
|
|
3
|
+
# Copyright (c) 2026 Université de Lille & INRIA
|
|
4
|
+
# ******************************************************************************
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
# ******************************************************************************
|
|
18
|
+
# Authors: see Authors.txt
|
|
19
|
+
# ******************************************************************************
|
|
20
|
+
|
|
21
|
+
from pySimBlocks.gui.blocks.block_meta import BlockMeta
|
|
22
|
+
from pySimBlocks.gui.blocks.parameter_meta import ParameterMeta
|
|
23
|
+
from pySimBlocks.gui.blocks.port_meta import PortMeta
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RampMeta(BlockMeta):
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self.name = "Ramp"
|
|
30
|
+
self.category = "sources"
|
|
31
|
+
self.type = "ramp"
|
|
32
|
+
self.summary = "Multi-dimensional ramp signal source."
|
|
33
|
+
self.description = (
|
|
34
|
+
"Generates a ramp signal defined by:\n"
|
|
35
|
+
"$$\n"
|
|
36
|
+
"y_i(t) = o_i + s_i \\max(0, t - t_{0,i})\n"
|
|
37
|
+
"$$\n"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self.parameters = [
|
|
41
|
+
ParameterMeta(
|
|
42
|
+
name="slope",
|
|
43
|
+
type="scalar | vector | matrix",
|
|
44
|
+
required=True,
|
|
45
|
+
autofill=True,
|
|
46
|
+
default=[[1.0]],
|
|
47
|
+
description="Ramp slope for each output dimension."
|
|
48
|
+
),
|
|
49
|
+
ParameterMeta(
|
|
50
|
+
name="start_time",
|
|
51
|
+
type="scalar | vector | matrix",
|
|
52
|
+
description="Time at which the ramp starts."
|
|
53
|
+
),
|
|
54
|
+
ParameterMeta(
|
|
55
|
+
name="offset",
|
|
56
|
+
type="scalar | vector | matrix",
|
|
57
|
+
description="Output value before the ramp starts."
|
|
58
|
+
),
|
|
59
|
+
ParameterMeta(
|
|
60
|
+
name="sample_time",
|
|
61
|
+
type="float",
|
|
62
|
+
description="Block execution period."
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
self.outputs = [
|
|
67
|
+
PortMeta(
|
|
68
|
+
name="out",
|
|
69
|
+
display_as="out",
|
|
70
|
+
shape=["n", "m"],
|
|
71
|
+
description="Ramp output signal."
|
|
72
|
+
)
|
|
73
|
+
]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# ******************************************************************************
|
|
2
|
+
# pySimBlocks
|
|
3
|
+
# Copyright (c) 2026 Université de Lille & INRIA
|
|
4
|
+
# ******************************************************************************
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
# ******************************************************************************
|
|
18
|
+
# Authors: see Authors.txt
|
|
19
|
+
# ******************************************************************************
|
|
20
|
+
|
|
21
|
+
from pySimBlocks.gui.blocks.block_meta import BlockMeta
|
|
22
|
+
from pySimBlocks.gui.blocks.parameter_meta import ParameterMeta
|
|
23
|
+
from pySimBlocks.gui.blocks.port_meta import PortMeta
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SinusoidalMeta(BlockMeta):
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self.name = "Sinusoidal"
|
|
30
|
+
self.category = "sources"
|
|
31
|
+
self.type = "sinusoidal"
|
|
32
|
+
self.summary = "Multi-dimensional sinusoidal signal source."
|
|
33
|
+
self.description = (
|
|
34
|
+
"Generates a sinusoidal signal defined by:\n"
|
|
35
|
+
"$$\n"
|
|
36
|
+
"y_i(t) = A_i \\sin(2\\pi f_i t + \\varphi_i) + o_i\n"
|
|
37
|
+
"$$\n"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self.parameters = [
|
|
41
|
+
ParameterMeta(
|
|
42
|
+
name="amplitude",
|
|
43
|
+
type="scalar | vector | matrix",
|
|
44
|
+
required=True,
|
|
45
|
+
autofill=True,
|
|
46
|
+
default=[[1.0]],
|
|
47
|
+
description="Sinusoidal amplitude."
|
|
48
|
+
),
|
|
49
|
+
ParameterMeta(
|
|
50
|
+
name="frequency",
|
|
51
|
+
type="scalar | vector | matrix",
|
|
52
|
+
required=True,
|
|
53
|
+
autofill=True,
|
|
54
|
+
default=[[1.0]],
|
|
55
|
+
description="Sinusoidal frequency in Hertz."
|
|
56
|
+
),
|
|
57
|
+
ParameterMeta(
|
|
58
|
+
name="phase",
|
|
59
|
+
type="scalar | vector | matrix",
|
|
60
|
+
description="Phase shift in radians."
|
|
61
|
+
),
|
|
62
|
+
ParameterMeta(
|
|
63
|
+
name="offset",
|
|
64
|
+
type="scalar | vector | matrix",
|
|
65
|
+
description="Constant offset added to the signal."
|
|
66
|
+
),
|
|
67
|
+
ParameterMeta(
|
|
68
|
+
name="sample_time",
|
|
69
|
+
type="float",
|
|
70
|
+
description="Block execution period."
|
|
71
|
+
)
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
self.outputs = [
|
|
75
|
+
PortMeta(
|
|
76
|
+
name="out",
|
|
77
|
+
display_as="out",
|
|
78
|
+
shape=["n", "m"],
|
|
79
|
+
description="Sinusoidal output signal."
|
|
80
|
+
)
|
|
81
|
+
]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# ******************************************************************************
|
|
2
|
+
# pySimBlocks
|
|
3
|
+
# Copyright (c) 2026 Université de Lille & INRIA
|
|
4
|
+
# ******************************************************************************
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
# ******************************************************************************
|
|
18
|
+
# Authors: see Authors.txt
|
|
19
|
+
# ******************************************************************************
|
|
20
|
+
|
|
21
|
+
from pySimBlocks.gui.blocks.block_meta import BlockMeta
|
|
22
|
+
from pySimBlocks.gui.blocks.parameter_meta import ParameterMeta
|
|
23
|
+
from pySimBlocks.gui.blocks.port_meta import PortMeta
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class StepMeta(BlockMeta):
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self.name = "Step"
|
|
30
|
+
self.category = "sources"
|
|
31
|
+
self.type = "step"
|
|
32
|
+
self.summary = "Step signal source."
|
|
33
|
+
self.description = (
|
|
34
|
+
"Generates a step signal defined by:\n"
|
|
35
|
+
"$$\n"
|
|
36
|
+
"y(t) =\n"
|
|
37
|
+
"\\begin{cases}\n"
|
|
38
|
+
"y_{\\text{before}}, & t < t_0 \\\\\n"
|
|
39
|
+
"y_{\\text{after}}, & t \\geq t_0\n"
|
|
40
|
+
"\\end{cases}\n"
|
|
41
|
+
"$$\n"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self.parameters = [
|
|
45
|
+
ParameterMeta(
|
|
46
|
+
name="value_before",
|
|
47
|
+
type="scalar | vector | matrix",
|
|
48
|
+
required=True,
|
|
49
|
+
autofill=True,
|
|
50
|
+
default=[[0.0]],
|
|
51
|
+
description="Output value before the step time."
|
|
52
|
+
),
|
|
53
|
+
ParameterMeta(
|
|
54
|
+
name="value_after",
|
|
55
|
+
type="scalar | vector | matrix",
|
|
56
|
+
required=True,
|
|
57
|
+
autofill=True,
|
|
58
|
+
default=[[1.0]],
|
|
59
|
+
description="Output value after the step time."
|
|
60
|
+
),
|
|
61
|
+
ParameterMeta(
|
|
62
|
+
name="start_time",
|
|
63
|
+
type="float",
|
|
64
|
+
required=True,
|
|
65
|
+
autofill=True,
|
|
66
|
+
default=1.0,
|
|
67
|
+
description="Time at which the step occurs."
|
|
68
|
+
),
|
|
69
|
+
ParameterMeta(
|
|
70
|
+
name="sample_time",
|
|
71
|
+
type="float",
|
|
72
|
+
description="Block execution period."
|
|
73
|
+
)
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
self.outputs = [
|
|
77
|
+
PortMeta(
|
|
78
|
+
name="out",
|
|
79
|
+
display_as="out",
|
|
80
|
+
shape=["n", "m"],
|
|
81
|
+
description="Step output signal."
|
|
82
|
+
)
|
|
83
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# ******************************************************************************
|
|
2
|
+
# pySimBlocks
|
|
3
|
+
# Copyright (c) 2026 Université de Lille & INRIA
|
|
4
|
+
# ******************************************************************************
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
# ******************************************************************************
|
|
18
|
+
# Authors: see Authors.txt
|
|
19
|
+
# ******************************************************************************
|
|
20
|
+
|
|
21
|
+
from pySimBlocks.gui.blocks.block_meta import BlockMeta
|
|
22
|
+
from pySimBlocks.gui.blocks.parameter_meta import ParameterMeta
|
|
23
|
+
from pySimBlocks.gui.blocks.port_meta import PortMeta
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WhiteNoiseMeta(BlockMeta):
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self.name = "WhiteNoise"
|
|
30
|
+
self.category = "sources"
|
|
31
|
+
self.type = "white_noise"
|
|
32
|
+
self.summary = "Multi-dimensional Gaussian white noise source."
|
|
33
|
+
self.description = (
|
|
34
|
+
"Generates independent Gaussian noise samples at each simulation step:\n"
|
|
35
|
+
"$$\n"
|
|
36
|
+
"y_i(t) \\sim \\mathcal{N}(\\mu_i, \\sigma_i^2)\n"
|
|
37
|
+
"$$\n"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self.parameters = [
|
|
41
|
+
ParameterMeta(
|
|
42
|
+
name="mean",
|
|
43
|
+
type="scalar | vector | matrix",
|
|
44
|
+
description="Mean value of the noise."
|
|
45
|
+
),
|
|
46
|
+
ParameterMeta(
|
|
47
|
+
name="std",
|
|
48
|
+
type="scalar | vector | matrix",
|
|
49
|
+
description="Standard deviation of the noise."
|
|
50
|
+
),
|
|
51
|
+
ParameterMeta(
|
|
52
|
+
name="seed",
|
|
53
|
+
type="int",
|
|
54
|
+
description="Random seed for reproducibility."
|
|
55
|
+
),
|
|
56
|
+
ParameterMeta(
|
|
57
|
+
name="sample_time",
|
|
58
|
+
type="float",
|
|
59
|
+
description="Block execution period."
|
|
60
|
+
)
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
self.outputs = [
|
|
64
|
+
PortMeta(
|
|
65
|
+
name="out",
|
|
66
|
+
display_as="out",
|
|
67
|
+
shape=["n", "m"],
|
|
68
|
+
description="Gaussian noise output signal."
|
|
69
|
+
)
|
|
70
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# ******************************************************************************
|
|
2
|
+
# pySimBlocks
|
|
3
|
+
# Copyright (c) 2026 Université de Lille & INRIA
|
|
4
|
+
# ******************************************************************************
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
# ******************************************************************************
|
|
18
|
+
# Authors: see Authors.txt
|
|
19
|
+
# ******************************************************************************
|
|
20
|
+
|
|
21
|
+
from pySimBlocks.gui.blocks.block_meta import BlockMeta
|
|
22
|
+
from pySimBlocks.gui.blocks.parameter_meta import ParameterMeta
|
|
23
|
+
from pySimBlocks.gui.blocks.port_meta import PortMeta
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LinearStateSpaceMeta(BlockMeta):
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self.name = "LinearStateSpace"
|
|
30
|
+
self.category = "systems"
|
|
31
|
+
self.type = "linear_state_space"
|
|
32
|
+
self.summary = "Discrete-time linear state-space system."
|
|
33
|
+
self.description = (
|
|
34
|
+
"Implements the discrete-time state-space equations:\n"
|
|
35
|
+
"$$\n"
|
|
36
|
+
"x[k+1] = A x[k] + B u[k]\n"
|
|
37
|
+
"$$\n"
|
|
38
|
+
"$$\n"
|
|
39
|
+
"y[k] = C x[k]\n"
|
|
40
|
+
"$$\n"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
self.parameters = [
|
|
44
|
+
ParameterMeta(
|
|
45
|
+
name="A",
|
|
46
|
+
type="matrix",
|
|
47
|
+
required=True,
|
|
48
|
+
autofill=True,
|
|
49
|
+
default=[[0.99]],
|
|
50
|
+
description="State transition matrix."
|
|
51
|
+
),
|
|
52
|
+
ParameterMeta(
|
|
53
|
+
name="B",
|
|
54
|
+
type="matrix",
|
|
55
|
+
required=True,
|
|
56
|
+
autofill=True,
|
|
57
|
+
default=[[1.0]],
|
|
58
|
+
description="Input matrix."
|
|
59
|
+
),
|
|
60
|
+
ParameterMeta(
|
|
61
|
+
name="C",
|
|
62
|
+
type="matrix",
|
|
63
|
+
required=True,
|
|
64
|
+
autofill=True,
|
|
65
|
+
default=[[1.0]],
|
|
66
|
+
description="Output matrix."
|
|
67
|
+
),
|
|
68
|
+
ParameterMeta(
|
|
69
|
+
name="x0",
|
|
70
|
+
type="vector",
|
|
71
|
+
description="Initial state vector."
|
|
72
|
+
),
|
|
73
|
+
ParameterMeta(
|
|
74
|
+
name="sample_time",
|
|
75
|
+
type="float",
|
|
76
|
+
description="Block execution period."
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
self.inputs = [
|
|
81
|
+
PortMeta(
|
|
82
|
+
name="u",
|
|
83
|
+
display_as="u",
|
|
84
|
+
shape=["m", 1],
|
|
85
|
+
description="Input vector."
|
|
86
|
+
)
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
self.outputs = [
|
|
90
|
+
PortMeta(
|
|
91
|
+
name="x",
|
|
92
|
+
display_as="x",
|
|
93
|
+
shape=["n", 1],
|
|
94
|
+
description="State vector."
|
|
95
|
+
),
|
|
96
|
+
PortMeta(
|
|
97
|
+
name="y",
|
|
98
|
+
display_as="y",
|
|
99
|
+
shape=["p", 1],
|
|
100
|
+
description="Output vector."
|
|
101
|
+
)
|
|
102
|
+
]
|