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.
Files changed (262) hide show
  1. examples/advanced/hardware/block_diagram.py +162 -0
  2. examples/advanced/hardware/camera.py +93 -0
  3. examples/advanced/hardware/gui_emio.py +231 -0
  4. examples/advanced/hardware/lmi.py +69 -0
  5. examples/advanced/hardware/main.py +57 -0
  6. examples/advanced/hardware/parameters.py +54 -0
  7. examples/advanced/qp_problem/params.py +10 -0
  8. examples/advanced/qp_problem/run.py +14 -0
  9. examples/advanced/sofa/gui/finger/Finger.py +108 -0
  10. examples/advanced/sofa/gui/finger/FingerController.py +53 -0
  11. examples/advanced/sofa/gui/finger/parameters_auto.py +22 -0
  12. examples/advanced/sofa/gui/sofa_plant/run.py +14 -0
  13. examples/advanced/sofa/python/Finger.py +107 -0
  14. examples/advanced/sofa/python/FingerController.py +48 -0
  15. examples/advanced/sofa/python/closedloop.py +64 -0
  16. examples/advanced/sofa/python/openloop.py +58 -0
  17. examples/basics/algebraic_function/g.py +7 -0
  18. examples/basics/algebraic_function/run.py +14 -0
  19. examples/basics/dc_motor/gui/run.py +14 -0
  20. examples/basics/dc_motor/multiple_order.py +91 -0
  21. examples/basics/dc_motor/openloop.py +62 -0
  22. examples/basics/dc_motor/pi.py +99 -0
  23. examples/basics/dc_motor/pid.py +118 -0
  24. examples/basics/dc_motor/pid_block.py +82 -0
  25. examples/basics/dc_motor/pid_block_vs_manual.py +143 -0
  26. examples/basics/external/parameters.py +4 -0
  27. examples/basics/external/run.py +14 -0
  28. examples/basics/file_sources/temp.py +16 -0
  29. examples/basics/observer.py +76 -0
  30. examples/basics/state_feedback/gui/parameters.py +9 -0
  31. examples/basics/state_feedback/gui/run.py +14 -0
  32. examples/basics/state_feedback/state_feedback.py +102 -0
  33. examples/basics/state_space/linear/gui/run.py +14 -0
  34. examples/basics/state_space/linear/ss_block.py +89 -0
  35. examples/basics/state_space/linear/ss_manual.py +105 -0
  36. examples/basics/state_space/non_linear/nlss.py +47 -0
  37. examples/basics/state_space/non_linear/run.py +14 -0
  38. examples/basics/state_space/polytope/params.py +39 -0
  39. examples/basics/state_space/polytope/weights.py +12 -0
  40. examples/comparison/simulink/convert.py +29 -0
  41. examples/comparison/simulink/openloop.py +127 -0
  42. examples/comparison/simulink/pi.py +148 -0
  43. examples/comparison/simulink/pid.py +154 -0
  44. examples/comparison/simulink/pid_backward.py +155 -0
  45. examples/quick_start/filter.py +35 -0
  46. examples/quick_start/gui/run.py +14 -0
  47. examples/tutorials/tutorial_1_python/main.py +99 -0
  48. examples/tutorials/tutorial_3_sofa/finger/Finger.py +120 -0
  49. examples/tutorials/tutorial_3_sofa/finger/FingerController.py +37 -0
  50. pySimBlocks/__init__.py +35 -0
  51. pySimBlocks/blocks/__init__.py +68 -0
  52. pySimBlocks/blocks/controllers/__init__.py +27 -0
  53. pySimBlocks/blocks/controllers/pid.py +250 -0
  54. pySimBlocks/blocks/controllers/state_feedback.py +141 -0
  55. pySimBlocks/blocks/interfaces/__init__.py +27 -0
  56. pySimBlocks/blocks/interfaces/external_input.py +107 -0
  57. pySimBlocks/blocks/interfaces/external_output.py +113 -0
  58. pySimBlocks/blocks/observers/__init__.py +23 -0
  59. pySimBlocks/blocks/observers/luenberger.py +175 -0
  60. pySimBlocks/blocks/operators/__init__.py +47 -0
  61. pySimBlocks/blocks/operators/algebraic_function.py +258 -0
  62. pySimBlocks/blocks/operators/dead_zone.py +186 -0
  63. pySimBlocks/blocks/operators/delay.py +254 -0
  64. pySimBlocks/blocks/operators/demux.py +123 -0
  65. pySimBlocks/blocks/operators/discrete_derivator.py +237 -0
  66. pySimBlocks/blocks/operators/discrete_integrator.py +265 -0
  67. pySimBlocks/blocks/operators/gain.py +294 -0
  68. pySimBlocks/blocks/operators/mux.py +131 -0
  69. pySimBlocks/blocks/operators/product.py +194 -0
  70. pySimBlocks/blocks/operators/rate_limiter.py +214 -0
  71. pySimBlocks/blocks/operators/saturation.py +178 -0
  72. pySimBlocks/blocks/operators/sum.py +188 -0
  73. pySimBlocks/blocks/operators/zero_order_hold.py +141 -0
  74. pySimBlocks/blocks/optimizers/__init__.py +23 -0
  75. pySimBlocks/blocks/optimizers/quadratic_program.py +326 -0
  76. pySimBlocks/blocks/sources/__init__.py +37 -0
  77. pySimBlocks/blocks/sources/chirp.py +168 -0
  78. pySimBlocks/blocks/sources/constant.py +82 -0
  79. pySimBlocks/blocks/sources/file_source.py +294 -0
  80. pySimBlocks/blocks/sources/function_source.py +197 -0
  81. pySimBlocks/blocks/sources/ramp.py +99 -0
  82. pySimBlocks/blocks/sources/sinusoidal.py +113 -0
  83. pySimBlocks/blocks/sources/step.py +138 -0
  84. pySimBlocks/blocks/sources/white_noise.py +107 -0
  85. pySimBlocks/blocks/systems/__init__.py +27 -0
  86. pySimBlocks/blocks/systems/linear_state_space.py +180 -0
  87. pySimBlocks/blocks/systems/non_linear_state_space.py +309 -0
  88. pySimBlocks/blocks/systems/polytopic_state_space.py +193 -0
  89. pySimBlocks/blocks/systems/sofa/__init__.py +30 -0
  90. pySimBlocks/blocks/systems/sofa/sofa_controller.py +472 -0
  91. pySimBlocks/blocks/systems/sofa/sofa_exchange_i_o.py +120 -0
  92. pySimBlocks/blocks/systems/sofa/sofa_plant.py +306 -0
  93. pySimBlocks/cli.py +127 -0
  94. pySimBlocks/core/__init__.py +32 -0
  95. pySimBlocks/core/block.py +167 -0
  96. pySimBlocks/core/block_source.py +94 -0
  97. pySimBlocks/core/config.py +90 -0
  98. pySimBlocks/core/fixed_time_manager.py +46 -0
  99. pySimBlocks/core/model.py +250 -0
  100. pySimBlocks/core/scheduler.py +30 -0
  101. pySimBlocks/core/simulator.py +329 -0
  102. pySimBlocks/core/task.py +73 -0
  103. pySimBlocks/docs/blocks/controllers/pid.md +78 -0
  104. pySimBlocks/docs/blocks/controllers/state_feedback.md +60 -0
  105. pySimBlocks/docs/blocks/interfaces/external_input.md +39 -0
  106. pySimBlocks/docs/blocks/interfaces/external_output.md +39 -0
  107. pySimBlocks/docs/blocks/observers/luenberger.md +70 -0
  108. pySimBlocks/docs/blocks/operators/algebraic_function.md +76 -0
  109. pySimBlocks/docs/blocks/operators/dead_zone.md +67 -0
  110. pySimBlocks/docs/blocks/operators/delay.md +76 -0
  111. pySimBlocks/docs/blocks/operators/demux.md +64 -0
  112. pySimBlocks/docs/blocks/operators/discrete_derivator.md +61 -0
  113. pySimBlocks/docs/blocks/operators/discrete_integrator.md +87 -0
  114. pySimBlocks/docs/blocks/operators/gain.md +97 -0
  115. pySimBlocks/docs/blocks/operators/mux.md +64 -0
  116. pySimBlocks/docs/blocks/operators/product.md +51 -0
  117. pySimBlocks/docs/blocks/operators/rate_limiter.md +70 -0
  118. pySimBlocks/docs/blocks/operators/saturation.md +62 -0
  119. pySimBlocks/docs/blocks/operators/sum.md +49 -0
  120. pySimBlocks/docs/blocks/operators/zero_order_hold.md +61 -0
  121. pySimBlocks/docs/blocks/optimizers/quadratic_program.md +98 -0
  122. pySimBlocks/docs/blocks/sources/chirp.md +102 -0
  123. pySimBlocks/docs/blocks/sources/constant.md +53 -0
  124. pySimBlocks/docs/blocks/sources/file_source.md +51 -0
  125. pySimBlocks/docs/blocks/sources/function_source.md +52 -0
  126. pySimBlocks/docs/blocks/sources/ramp.md +58 -0
  127. pySimBlocks/docs/blocks/sources/sinusoidal.md +60 -0
  128. pySimBlocks/docs/blocks/sources/step.md +63 -0
  129. pySimBlocks/docs/blocks/sources/white_noise.md +58 -0
  130. pySimBlocks/docs/blocks/systems/linear_state_space.md +66 -0
  131. pySimBlocks/docs/blocks/systems/non_linear_state_space.md +90 -0
  132. pySimBlocks/docs/blocks/systems/polytopic_state_space.md +72 -0
  133. pySimBlocks/docs/blocks/systems/sofa/sofa_exchange_i_o.md +63 -0
  134. pySimBlocks/docs/blocks/systems/sofa/sofa_plant.md +62 -0
  135. pySimBlocks/gui/__init__.py +20 -0
  136. pySimBlocks/gui/addons/__init__.py +19 -0
  137. pySimBlocks/gui/addons/sofa/__init__.py +19 -0
  138. pySimBlocks/gui/addons/sofa/sofa_dialog.py +190 -0
  139. pySimBlocks/gui/addons/sofa/sofa_service.py +209 -0
  140. pySimBlocks/gui/blocks/block_dialog_session.py +47 -0
  141. pySimBlocks/gui/blocks/block_meta.py +408 -0
  142. pySimBlocks/gui/blocks/controllers/pid.py +116 -0
  143. pySimBlocks/gui/blocks/controllers/state_feedback.py +80 -0
  144. pySimBlocks/gui/blocks/interfaces/external_input.py +64 -0
  145. pySimBlocks/gui/blocks/interfaces/external_output.py +63 -0
  146. pySimBlocks/gui/blocks/observers/luenberger.py +108 -0
  147. pySimBlocks/gui/blocks/operators/algebraic_function.py +232 -0
  148. pySimBlocks/gui/blocks/operators/dead_zone.py +79 -0
  149. pySimBlocks/gui/blocks/operators/delay.py +79 -0
  150. pySimBlocks/gui/blocks/operators/demux.py +98 -0
  151. pySimBlocks/gui/blocks/operators/discrete_derivator.py +67 -0
  152. pySimBlocks/gui/blocks/operators/discrete_integrator.py +80 -0
  153. pySimBlocks/gui/blocks/operators/gain.py +79 -0
  154. pySimBlocks/gui/blocks/operators/mux.py +100 -0
  155. pySimBlocks/gui/blocks/operators/product.py +109 -0
  156. pySimBlocks/gui/blocks/operators/rate_limiter.py +79 -0
  157. pySimBlocks/gui/blocks/operators/saturation.py +72 -0
  158. pySimBlocks/gui/blocks/operators/sum.py +91 -0
  159. pySimBlocks/gui/blocks/operators/zero_order_hold.py +64 -0
  160. pySimBlocks/gui/blocks/optimizers/quadratic_program.py +128 -0
  161. pySimBlocks/gui/blocks/parameter_meta.py +34 -0
  162. pySimBlocks/gui/blocks/port_meta.py +31 -0
  163. pySimBlocks/gui/blocks/sources/chirp.py +146 -0
  164. pySimBlocks/gui/blocks/sources/constant.py +63 -0
  165. pySimBlocks/gui/blocks/sources/file_source.py +196 -0
  166. pySimBlocks/gui/blocks/sources/function_source.py +202 -0
  167. pySimBlocks/gui/blocks/sources/ramp.py +73 -0
  168. pySimBlocks/gui/blocks/sources/sinusoidal.py +81 -0
  169. pySimBlocks/gui/blocks/sources/step.py +83 -0
  170. pySimBlocks/gui/blocks/sources/white_noise.py +70 -0
  171. pySimBlocks/gui/blocks/systems/linear_state_space.py +102 -0
  172. pySimBlocks/gui/blocks/systems/non_linear_state_space.py +233 -0
  173. pySimBlocks/gui/blocks/systems/polytopic_state_space.py +109 -0
  174. pySimBlocks/gui/blocks/systems/sofa/sofa_exchange_i_o.py +221 -0
  175. pySimBlocks/gui/blocks/systems/sofa/sofa_plant.py +220 -0
  176. pySimBlocks/gui/dialogs/__init__.py +19 -0
  177. pySimBlocks/gui/dialogs/block_dialog.py +125 -0
  178. pySimBlocks/gui/dialogs/display_yaml_dialog.py +89 -0
  179. pySimBlocks/gui/dialogs/help_dialog.py +39 -0
  180. pySimBlocks/gui/dialogs/plot_dialog.py +230 -0
  181. pySimBlocks/gui/dialogs/settings/plots.py +187 -0
  182. pySimBlocks/gui/dialogs/settings/project.py +146 -0
  183. pySimBlocks/gui/dialogs/settings/simulation.py +137 -0
  184. pySimBlocks/gui/dialogs/settings_dialog.py +88 -0
  185. pySimBlocks/gui/dialogs/unsaved_dialog.py +92 -0
  186. pySimBlocks/gui/editor.py +49 -0
  187. pySimBlocks/gui/graphics/__init__.py +29 -0
  188. pySimBlocks/gui/graphics/block_item.py +289 -0
  189. pySimBlocks/gui/graphics/connection_item.py +266 -0
  190. pySimBlocks/gui/graphics/port_item.py +153 -0
  191. pySimBlocks/gui/graphics/theme.py +119 -0
  192. pySimBlocks/gui/main_window.py +162 -0
  193. pySimBlocks/gui/models/__init__.py +31 -0
  194. pySimBlocks/gui/models/block_instance.py +114 -0
  195. pySimBlocks/gui/models/connection_instance.py +43 -0
  196. pySimBlocks/gui/models/port_instance.py +52 -0
  197. pySimBlocks/gui/models/project_simulation_params.py +50 -0
  198. pySimBlocks/gui/models/project_state.py +114 -0
  199. pySimBlocks/gui/project_controller.py +302 -0
  200. pySimBlocks/gui/services/__init__.py +20 -0
  201. pySimBlocks/gui/services/project_loader.py +381 -0
  202. pySimBlocks/gui/services/project_saver.py +68 -0
  203. pySimBlocks/gui/services/simulation_runner.py +66 -0
  204. pySimBlocks/gui/services/yaml_tools.py +261 -0
  205. pySimBlocks/gui/widgets/__init__.py +19 -0
  206. pySimBlocks/gui/widgets/block_list.py +131 -0
  207. pySimBlocks/gui/widgets/diagram_view.py +312 -0
  208. pySimBlocks/gui/widgets/toolbar_view.py +161 -0
  209. pySimBlocks/project/__init__.py +35 -0
  210. pySimBlocks/project/build_model.py +92 -0
  211. pySimBlocks/project/generate_run_script.py +109 -0
  212. pySimBlocks/project/generate_sofa_controller.py +215 -0
  213. pySimBlocks/project/load_project_config.py +197 -0
  214. pySimBlocks/project/load_simulation_config.py +166 -0
  215. pySimBlocks/project/load_simulator.py +45 -0
  216. pySimBlocks/project/plot_from_config.py +174 -0
  217. pySimBlocks/project/pySimBlocks_blocks_index.yaml +106 -0
  218. pySimBlocks/real_time/__init__.py +23 -0
  219. pySimBlocks/real_time/real_time_runner.py +148 -0
  220. pySimBlocks/tools/__init__.py +19 -0
  221. pySimBlocks/tools/blocks_registry.py +141 -0
  222. pySimBlocks/tools/generate_blocks_index.py +124 -0
  223. pysimblocks-0.1.0.dist-info/METADATA +180 -0
  224. pysimblocks-0.1.0.dist-info/RECORD +262 -0
  225. pysimblocks-0.1.0.dist-info/WHEEL +5 -0
  226. pysimblocks-0.1.0.dist-info/entry_points.txt +2 -0
  227. pysimblocks-0.1.0.dist-info/licenses/LICENSE.md +165 -0
  228. pysimblocks-0.1.0.dist-info/top_level.txt +3 -0
  229. tests/blocks/controllers/test_pid.py +143 -0
  230. tests/blocks/controllers/test_state_feedback.py +193 -0
  231. tests/blocks/observers/test_luenberger.py +225 -0
  232. tests/blocks/operators/test_algebraic_function.py +230 -0
  233. tests/blocks/operators/test_dead_zone.py +106 -0
  234. tests/blocks/operators/test_delay.py +167 -0
  235. tests/blocks/operators/test_demux.py +111 -0
  236. tests/blocks/operators/test_discrete_derivator.py +160 -0
  237. tests/blocks/operators/test_discrete_integrator.py +149 -0
  238. tests/blocks/operators/test_gain.py +182 -0
  239. tests/blocks/operators/test_mux.py +101 -0
  240. tests/blocks/operators/test_product.py +171 -0
  241. tests/blocks/operators/test_rate_limiter.py +166 -0
  242. tests/blocks/operators/test_saturation.py +157 -0
  243. tests/blocks/operators/test_sum.py +183 -0
  244. tests/blocks/operators/test_zero_order_hold.py +106 -0
  245. tests/blocks/sources/test_chirp.py +157 -0
  246. tests/blocks/sources/test_constant.py +55 -0
  247. tests/blocks/sources/test_file_source.py +185 -0
  248. tests/blocks/sources/test_function_source.py +135 -0
  249. tests/blocks/sources/test_ramp.py +110 -0
  250. tests/blocks/sources/test_sinusoidal.py +113 -0
  251. tests/blocks/sources/test_step.py +76 -0
  252. tests/blocks/sources/test_white_noise.py +108 -0
  253. tests/blocks/systems/test_linear_state_space.py +135 -0
  254. tests/blocks/systems/test_polytopic_state_space.py +133 -0
  255. tests/core/test_core_errors_and_determinism.py +82 -0
  256. tests/core/test_core_multirate_tasks.py +88 -0
  257. tests/core/test_core_two_phase_and_propagation.py +132 -0
  258. tests/gui/main_window_open_test.py +162 -0
  259. tests/gui/test_block_meta_param_cache.py +16 -0
  260. tests/gui/test_file_source_meta.py +17 -0
  261. tests/gui/test_function_source_meta.py +28 -0
  262. tests/regression/test_simulink_dc_motor.py +217 -0
@@ -0,0 +1,64 @@
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 ZeroOrderHoldMeta(BlockMeta):
27
+
28
+ def __init__(self):
29
+ self.name = "ZeroOrderHold"
30
+ self.category = "operators"
31
+ self.type = "zero_order_hold"
32
+ self.summary = "Zero-Order Hold (ZOH) block."
33
+ self.description = (
34
+ "Samples the input signal at discrete instants and holds its value\n"
35
+ "constant between sampling instants. The held output is updated when\n"
36
+ "the elapsed time since the last sampling instant reaches the sampling\n"
37
+ "period."
38
+ )
39
+
40
+ self.parameters = [
41
+ ParameterMeta(
42
+ name="sample_time",
43
+ type="float",
44
+ required=True
45
+ )
46
+ ]
47
+
48
+ self.inputs = [
49
+ PortMeta(
50
+ name="in",
51
+ display_as="in",
52
+ shape=["n", "m"],
53
+ description="Input signal."
54
+ )
55
+ ]
56
+
57
+ self.outputs = [
58
+ PortMeta(
59
+ name="out",
60
+ display_as="out",
61
+ shape=["n", "m"],
62
+ description="Held output signal."
63
+ )
64
+ ]
@@ -0,0 +1,128 @@
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 QuadraticProgramMeta(BlockMeta):
27
+
28
+ def __init__(self):
29
+ self.name = "QuadraticProgram"
30
+ self.category = "optimizers"
31
+ self.type = "quadratic_program"
32
+ self.summary = "General time-varying quadratic program (QP) solver."
33
+ self.description = (
34
+ "Solves at each simulation step the quadratic program:\n"
35
+ "$$\n"
36
+ "\\begin{aligned}\n"
37
+ "\\min_x \\quad & \\tfrac12 x^T P x + q^T x \\\\\n"
38
+ "\\text{s.t.} \\quad\n"
39
+ "& Gx \\le h \\\\\n"
40
+ "& Ax = b \\\\\n"
41
+ "& \\ell \\le x \\le u\n"
42
+ "\\end{aligned}\n"
43
+ "$$\n"
44
+ "All problem data are provided as inputs and may vary with time.\n"
45
+ "Inequality, equality, and bound constraints are optional."
46
+ )
47
+
48
+ self.parameters = [
49
+ ParameterMeta(
50
+ name="solver",
51
+ type="string",
52
+ autofill=True,
53
+ default="clarabel",
54
+ description="Name of the QP solver used by qpsolvers."
55
+ )
56
+ ]
57
+
58
+ self.inputs = [
59
+ PortMeta(
60
+ name="P",
61
+ display_as="P",
62
+ shape=["n", "n"],
63
+ description="Quadratic cost matrix (Hessian). Must be square and compatible with size."
64
+ ),
65
+ PortMeta(
66
+ name="q",
67
+ display_as="q",
68
+ shape=["n"],
69
+ description="Linear cost vector. Accepted shapes are (n,) or (n,1)."
70
+ ),
71
+ PortMeta(
72
+ name="G",
73
+ display_as="G",
74
+ shape=["m", "n"],
75
+ description="Inequality constraint matrix. Must be provided together with h."
76
+ ),
77
+ PortMeta(
78
+ name="h",
79
+ display_as="h",
80
+ shape=["m"],
81
+ description="Inequality constraint vector. Accepted shapes are (m,) or (m,1)."
82
+ ),
83
+ PortMeta(
84
+ name="A",
85
+ display_as="A",
86
+ shape=["p", "n"],
87
+ description="Equality constraint matrix. Must be provided together with b."
88
+ ),
89
+ PortMeta(
90
+ name="b",
91
+ display_as="b",
92
+ shape=["p"],
93
+ description="Equality constraint vector. Accepted shapes are (p,) or (p,1)."
94
+ ),
95
+ PortMeta(
96
+ name="lb",
97
+ display_as="lb",
98
+ shape=["n"],
99
+ description="Lower bound on decision variables. Accepted shapes are (n,) or (n,1)."
100
+ ),
101
+ PortMeta(
102
+ name="ub",
103
+ display_as="ub",
104
+ shape=["n"],
105
+ description="Upper bound on decision variables. Accepted shapes are (n,) or (n,1)."
106
+ )
107
+ ]
108
+
109
+ self.outputs = [
110
+ PortMeta(
111
+ name="x",
112
+ display_as="x",
113
+ shape=["n", 1],
114
+ description="Optimal solution of the quadratic program."
115
+ ),
116
+ PortMeta(
117
+ name="status",
118
+ display_as="status",
119
+ shape=[1, 1],
120
+ description="Solver status code:\n0 = optimal solution found,\n1 = problem infeasible,\n2 = solver or numerical error."
121
+ ),
122
+ PortMeta(
123
+ name="cost",
124
+ display_as="cost",
125
+ shape=[1, 1],
126
+ description="Optimal value of the quadratic cost function."
127
+ )
128
+ ]
@@ -0,0 +1,34 @@
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
+
22
+ from dataclasses import dataclass, field
23
+ from typing import Any, List, Optional
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class ParameterMeta:
28
+ name: str
29
+ type: str
30
+ required: bool = False
31
+ autofill: bool = False
32
+ default: Optional[Any] = None
33
+ enum: List[Any] = field(default_factory=list)
34
+ description: str = ""
@@ -0,0 +1,31 @@
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
+
22
+ from dataclasses import dataclass
23
+ from typing import Any
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class PortMeta:
28
+ name: str
29
+ display_as: str
30
+ shape: list[Any]
31
+ description: str = ""
@@ -0,0 +1,146 @@
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 ChirpMeta(BlockMeta):
27
+
28
+ def __init__(self):
29
+ self.name = "Chirp"
30
+ self.category = "sources"
31
+ self.type = "chirp"
32
+ self.summary = "Multi-dimensional chirp signal source (linear or logarithmic)."
33
+
34
+ self.description = (
35
+ "Generates a frequency-sweep (chirp) signal.\n\n"
36
+
37
+ "Linear mode:\n"
38
+ "$$\n"
39
+ "\\phi_i(t) = 2\\pi\\left(f_{0,i}\\tau + "
40
+ "\\tfrac{1}{2}k_i\\tau^2\\right) + \\varphi_i\n"
41
+ "$$\n"
42
+ "with:\n"
43
+ "$$\n"
44
+ "k_i = \\frac{f_{1,i} - f_{0,i}}{T_i}\n"
45
+ "$$\n\n"
46
+
47
+ "Logarithmic mode:\n"
48
+ "$$\n"
49
+ "\\phi_i(t) = "
50
+ "\\frac{2\\pi f_{0,i} T_i}{\\ln(f_{1,i}/f_{0,i})}"
51
+ "\\left[\\left(\\frac{f_{1,i}}{f_{0,i}}\\right)^{\\tau/T_i} - 1\\right]"
52
+ " + \\varphi_i\n"
53
+ "$$\n\n"
54
+
55
+ "Output:\n"
56
+ "$$\n"
57
+ "y_i(t) = A_i \\sin(\\phi_i(t)) + o_i\n"
58
+ "$$\n\n"
59
+
60
+ "with:\n"
61
+ "$$\n"
62
+ "\\tau = \\max(0, t - t_{0,i})\n"
63
+ "$$\n"
64
+ )
65
+
66
+ self.parameters = [
67
+
68
+ ParameterMeta(
69
+ name="amplitude",
70
+ type="scalar | vector | matrix",
71
+ required=True,
72
+ autofill=True,
73
+ default=[[1.0]],
74
+ description="Chirp amplitude."
75
+ ),
76
+
77
+ ParameterMeta(
78
+ name="f0",
79
+ type="scalar | vector | matrix",
80
+ required=True,
81
+ autofill=True,
82
+ default=[[1.0]],
83
+ description="Start frequency in Hertz."
84
+ ),
85
+
86
+ ParameterMeta(
87
+ name="f1",
88
+ type="scalar | vector | matrix",
89
+ required=True,
90
+ autofill=True,
91
+ default=[[10.0]],
92
+ description="End frequency in Hertz."
93
+ ),
94
+
95
+ ParameterMeta(
96
+ name="duration",
97
+ type="scalar | vector | matrix",
98
+ required=True,
99
+ autofill=True,
100
+ default=[[5.0]],
101
+ description="Frequency sweep duration in seconds."
102
+ ),
103
+
104
+ ParameterMeta(
105
+ name="mode",
106
+ type="enum",
107
+ required=True,
108
+ autofill=True,
109
+ default="linear",
110
+ enum=["linear", "log"],
111
+ description="Sweep mode: 'linear' or 'log'."
112
+ ),
113
+
114
+ ParameterMeta(
115
+ name="start_time",
116
+ type="scalar | vector | matrix",
117
+ description="Time at which the chirp starts."
118
+ ),
119
+
120
+ ParameterMeta(
121
+ name="phase",
122
+ type="scalar | vector | matrix",
123
+ description="Initial phase in radians."
124
+ ),
125
+
126
+ ParameterMeta(
127
+ name="offset",
128
+ type="scalar | vector | matrix",
129
+ description="Constant offset added to the signal."
130
+ ),
131
+
132
+ ParameterMeta(
133
+ name="sample_time",
134
+ type="float",
135
+ description="Block execution period."
136
+ )
137
+ ]
138
+
139
+ self.outputs = [
140
+ PortMeta(
141
+ name="out",
142
+ display_as="out",
143
+ shape=["n", "m"],
144
+ description="Chirp output signal."
145
+ )
146
+ ]
@@ -0,0 +1,63 @@
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 ConstantMeta(BlockMeta):
27
+
28
+ def __init__(self):
29
+ self.name = "Constant"
30
+ self.category = "sources"
31
+ self.type = "constant"
32
+ self.summary = "Constant signal source."
33
+ self.description = (
34
+ "Generates a constant output signal:\n"
35
+ "$$\n"
36
+ "y(t) = c"
37
+ "$$\n"
38
+ )
39
+
40
+ self.parameters = [
41
+ ParameterMeta(
42
+ name = "value",
43
+ type = "scalar | vector | matrix",
44
+ required = True,
45
+ autofill = True,
46
+ default = [[1.0]],
47
+ description = "Constant output value."
48
+ ),
49
+
50
+ ParameterMeta(
51
+ name = "sample_time",
52
+ type = "float",
53
+ )
54
+ ]
55
+
56
+ self.outputs = [
57
+ PortMeta(
58
+ name="out",
59
+ display_as="out",
60
+ shape=["n", "m"],
61
+ description="Constant output signal."
62
+ )
63
+ ]
@@ -0,0 +1,196 @@
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 Any, Dict
26
+
27
+ from PySide6.QtWidgets import QFormLayout, QLabel, QLineEdit, QPushButton
28
+
29
+ from pySimBlocks.gui.blocks.block_meta import BlockMeta
30
+ from pySimBlocks.gui.blocks.parameter_meta import ParameterMeta
31
+ from pySimBlocks.gui.blocks.port_meta import PortMeta
32
+
33
+
34
+ class FileSourceMeta(BlockMeta):
35
+
36
+ def __init__(self):
37
+ self.name = "FileSource"
38
+ self.category = "sources"
39
+ self.type = "file_source"
40
+ self.summary = "Read a sequence of samples from a CSV, NPY, or NPZ file."
41
+ self.description = (
42
+ "Loads samples from file and outputs one sample per simulation step.\n\n"
43
+ "- `.npz`: reads one array from the archive (`key` mandatory).\n"
44
+ "- `.npy`: reads one array from a NPY file (`key` unused).\n"
45
+ "- `.csv`: reads one numeric CSV column (`key` = column name).\n\n"
46
+ "Each step emits one row as a column vector."
47
+ )
48
+
49
+ self.parameters = [
50
+ ParameterMeta(
51
+ name="file_path",
52
+ type="str",
53
+ required=True,
54
+ description="Path to the source file."
55
+ ),
56
+ ParameterMeta(
57
+ name="key",
58
+ type="str",
59
+ description="NPZ array key or CSV column name."
60
+ ),
61
+ ParameterMeta(
62
+ name="repeat",
63
+ type="enum",
64
+ autofill=True,
65
+ default=False,
66
+ enum=[False, True],
67
+ description="If true, replay samples from the beginning after end of file."
68
+ ),
69
+ ParameterMeta(
70
+ name="use_time",
71
+ type="enum",
72
+ autofill=True,
73
+ default=False,
74
+ enum=[False, True],
75
+ description="If true (NPZ/CSV), use 'time' data and apply ZOH at simulation time t."
76
+ ),
77
+ ParameterMeta(
78
+ name="sample_time",
79
+ type="float",
80
+ description="Block execution period."
81
+ ),
82
+ ]
83
+
84
+ self.outputs = [
85
+ PortMeta(
86
+ name="out",
87
+ display_as="out",
88
+ shape=["n", 1],
89
+ description="Current output sample."
90
+ )
91
+ ]
92
+
93
+ # ------------------------------------------------------
94
+ def is_parameter_active(self,
95
+ param_name: str,
96
+ instance_params: Dict[str, Any]) -> bool:
97
+ file_path = str(instance_params.get("file_path", "") or "")
98
+ ext = file_path.rsplit(".", 1)[-1].lower() if "." in file_path else ""
99
+
100
+ if param_name == "key":
101
+ return ext in {"npz", "csv"}
102
+
103
+ if param_name == "use_time":
104
+ return ext in {"npz", "csv"}
105
+
106
+ return super().is_parameter_active(param_name, instance_params)
107
+
108
+ # --------------------------------------------------------------------------
109
+ # Dialog Methods
110
+ # --------------------------------------------------------------------------
111
+ def build_param(
112
+ self,
113
+ session,
114
+ form: QFormLayout,
115
+ readonly: bool = False,
116
+ ):
117
+ name_edit = QLineEdit(session.instance.name)
118
+ name_edit.textChanged.connect(
119
+ lambda val: self._on_param_changed(val, "name", session, readonly)
120
+ )
121
+ form.addRow(QLabel("Block name:"), name_edit)
122
+ if readonly:
123
+ name_edit.setReadOnly(True)
124
+ session.name_edit = name_edit
125
+
126
+ for pmeta in self.parameters:
127
+ if pmeta.name == "file_path":
128
+ self.build_file_param_row(
129
+ session,
130
+ form,
131
+ pmeta,
132
+ readonly=readonly,
133
+ file_filter="Data files (*.npz *.npy *.csv);;All files (*)",
134
+ )
135
+ continue
136
+
137
+ label, widget = self._create_param_row(session, pmeta, readonly)
138
+ if widget is None:
139
+ continue
140
+ if readonly:
141
+ self._set_readonly_style(widget)
142
+
143
+ form.addRow(label, widget)
144
+ session.param_widgets[pmeta.name] = widget
145
+ session.param_labels[pmeta.name] = label
146
+
147
+ # ------------------------------------------------------
148
+ def build_post_param(self, session, form: QFormLayout, readonly: bool = False):
149
+ open_btn = QPushButton("Open file")
150
+ open_btn.clicked.connect(lambda: self._open_file_from_session(session))
151
+ form.addRow(QLabel(""), open_btn)
152
+ session.open_file_btn = open_btn
153
+ self._refresh_open_button_state(session)
154
+
155
+ # ------------------------------------------------------
156
+ def refresh_form(self, session):
157
+ super().refresh_form(session)
158
+ self._refresh_open_button_state(session)
159
+
160
+ # ------------------------------------------------------
161
+ def _resolve_file_path(self, session) -> Path | None:
162
+ raw = session.local_params.get("file_path")
163
+ if not raw:
164
+ return None
165
+
166
+ path = Path(str(raw)).expanduser()
167
+ if not path.is_absolute() and session.project_dir is not None:
168
+ path = (session.project_dir / path).resolve()
169
+ return path
170
+
171
+ # ------------------------------------------------------
172
+ def _refresh_open_button_state(self, session) -> None:
173
+ btn = getattr(session, "open_file_btn", None)
174
+ if btn is None:
175
+ return
176
+
177
+ target = self._resolve_file_path(session)
178
+ exists = target is not None and target.is_file()
179
+ btn.setEnabled(exists)
180
+ if exists:
181
+ btn.setToolTip(str(target))
182
+ else:
183
+ btn.setToolTip("Set a valid existing file_path to open the file.")
184
+
185
+ # ------------------------------------------------------
186
+ def _open_file_from_session(self, session) -> None:
187
+ target = self._resolve_file_path(session)
188
+ if target is None or not target.is_file():
189
+ return
190
+
191
+ if sys.platform.startswith("darwin"):
192
+ subprocess.Popen(["open", str(target)])
193
+ elif os.name == "nt":
194
+ os.startfile(str(target))
195
+ else:
196
+ subprocess.Popen(["xdg-open", str(target)])