pathsim 0.2.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 (109) hide show
  1. pathsim/__init__.py +3 -0
  2. pathsim/blocks/__init__.py +14 -0
  3. pathsim/blocks/_block.py +209 -0
  4. pathsim/blocks/adder.py +30 -0
  5. pathsim/blocks/amplifier.py +34 -0
  6. pathsim/blocks/delay.py +70 -0
  7. pathsim/blocks/differentiator.py +70 -0
  8. pathsim/blocks/function.py +82 -0
  9. pathsim/blocks/integrator.py +66 -0
  10. pathsim/blocks/lti.py +155 -0
  11. pathsim/blocks/multiplier.py +30 -0
  12. pathsim/blocks/ode.py +86 -0
  13. pathsim/blocks/rf/__init__.py +4 -0
  14. pathsim/blocks/rf/filters.py +169 -0
  15. pathsim/blocks/rf/noise.py +218 -0
  16. pathsim/blocks/rf/sources.py +163 -0
  17. pathsim/blocks/rf/wienerhammerstein.py +338 -0
  18. pathsim/blocks/rng.py +57 -0
  19. pathsim/blocks/scope.py +224 -0
  20. pathsim/blocks/sources.py +71 -0
  21. pathsim/blocks/spectrum.py +316 -0
  22. pathsim/connection.py +112 -0
  23. pathsim/simulation.py +652 -0
  24. pathsim/solvers/__init__.py +25 -0
  25. pathsim/solvers/_solver.py +403 -0
  26. pathsim/solvers/bdf.py +240 -0
  27. pathsim/solvers/dirk2.py +101 -0
  28. pathsim/solvers/dirk3.py +86 -0
  29. pathsim/solvers/esdirk32.py +131 -0
  30. pathsim/solvers/esdirk4.py +99 -0
  31. pathsim/solvers/esdirk43.py +139 -0
  32. pathsim/solvers/esdirk54.py +141 -0
  33. pathsim/solvers/esdirk85.py +200 -0
  34. pathsim/solvers/euler.py +81 -0
  35. pathsim/solvers/rk4.py +61 -0
  36. pathsim/solvers/rkbs32.py +101 -0
  37. pathsim/solvers/rkck54.py +108 -0
  38. pathsim/solvers/rkdp54.py +111 -0
  39. pathsim/solvers/rkdp87.py +116 -0
  40. pathsim/solvers/rkf45.py +102 -0
  41. pathsim/solvers/rkf78.py +111 -0
  42. pathsim/solvers/rkv65.py +103 -0
  43. pathsim/solvers/ssprk22.py +62 -0
  44. pathsim/solvers/ssprk33.py +65 -0
  45. pathsim/solvers/ssprk34.py +74 -0
  46. pathsim/subsystem.py +267 -0
  47. pathsim/utils/__init__.py +0 -0
  48. pathsim/utils/adaptivebuffer.py +87 -0
  49. pathsim/utils/anderson.py +180 -0
  50. pathsim/utils/funcs.py +205 -0
  51. pathsim/utils/gilbert.py +110 -0
  52. pathsim/utils/progresstracker.py +90 -0
  53. pathsim/utils/realtimeplotter.py +230 -0
  54. pathsim/utils/statespacerealizations.py +116 -0
  55. pathsim/utils/waveforms.py +36 -0
  56. pathsim-0.2.0.dist-info/LICENSE.txt +21 -0
  57. pathsim-0.2.0.dist-info/METADATA +149 -0
  58. pathsim-0.2.0.dist-info/RECORD +109 -0
  59. pathsim-0.2.0.dist-info/WHEEL +5 -0
  60. pathsim-0.2.0.dist-info/top_level.txt +2 -0
  61. tests/__init__.py +0 -0
  62. tests/blocks/__init__.py +0 -0
  63. tests/blocks/test_adder.py +85 -0
  64. tests/blocks/test_amplifier.py +66 -0
  65. tests/blocks/test_block.py +138 -0
  66. tests/blocks/test_delay.py +122 -0
  67. tests/blocks/test_differentiator.py +102 -0
  68. tests/blocks/test_function.py +165 -0
  69. tests/blocks/test_integrator.py +92 -0
  70. tests/blocks/test_lti.py +162 -0
  71. tests/blocks/test_multiplier.py +87 -0
  72. tests/blocks/test_ode.py +125 -0
  73. tests/blocks/test_rng.py +109 -0
  74. tests/blocks/test_scope.py +196 -0
  75. tests/blocks/test_sources.py +119 -0
  76. tests/blocks/test_spectrum.py +119 -0
  77. tests/solvers/__init__.py +0 -0
  78. tests/solvers/test_bdf.py +364 -0
  79. tests/solvers/test_dirk2.py +138 -0
  80. tests/solvers/test_dirk3.py +137 -0
  81. tests/solvers/test_esdirk32.py +158 -0
  82. tests/solvers/test_esdirk4.py +138 -0
  83. tests/solvers/test_esdirk43.py +158 -0
  84. tests/solvers/test_esdirk54.py +160 -0
  85. tests/solvers/test_esdirk85.py +157 -0
  86. tests/solvers/test_euler.py +223 -0
  87. tests/solvers/test_rk4.py +138 -0
  88. tests/solvers/test_rkbs32.py +159 -0
  89. tests/solvers/test_rkck54.py +157 -0
  90. tests/solvers/test_rkdp54.py +159 -0
  91. tests/solvers/test_rkdp87.py +157 -0
  92. tests/solvers/test_rkf45.py +159 -0
  93. tests/solvers/test_rkf78.py +160 -0
  94. tests/solvers/test_rkv65.py +160 -0
  95. tests/solvers/test_solver.py +119 -0
  96. tests/solvers/test_ssprk22.py +136 -0
  97. tests/solvers/test_ssprk33.py +136 -0
  98. tests/solvers/test_ssprk34.py +136 -0
  99. tests/test_connection.py +176 -0
  100. tests/test_simulation.py +271 -0
  101. tests/test_subsystem.py +182 -0
  102. tests/utils/__init__.py +0 -0
  103. tests/utils/test_adaptivebuffer.py +111 -0
  104. tests/utils/test_anderson.py +142 -0
  105. tests/utils/test_funcs.py +143 -0
  106. tests/utils/test_gilbert.py +108 -0
  107. tests/utils/test_progresstracker.py +144 -0
  108. tests/utils/test_realtimeplotter.py +122 -0
  109. tests/utils/test_statespacerealizations.py +107 -0
@@ -0,0 +1,116 @@
1
+ ########################################################################################
2
+ ##
3
+ ## METHODS FOR STATESPACE REALIZATIONS
4
+ ## (utils/statespacerealizations.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import numpy as np
13
+
14
+
15
+ # STATESPACE REALIZATION ===============================================================
16
+
17
+ def gilbert_realization(Poles=[], Residues=[], Const=0.0, tolerance=1e-9):
18
+
19
+ """
20
+ Build real valued statespace model from transfer function
21
+ in pole residue form by Gilberts method and an additional
22
+ similarity transformation to get fully real valued matrices.
23
+
24
+ pole residue form:
25
+ H(s) = Const + sum( Residues / (s - Poles) )
26
+
27
+ statespace form:
28
+ H(s) = C * (s*I - A)^-1 * B + D
29
+
30
+ NOTE :
31
+ The resulting system is identical to the so-called
32
+ 'Modal Form' and is a minimal realization.
33
+
34
+ INPUTS :
35
+ Poles : (array) real and complex poles
36
+ Residues : (array) array of real and complex residue matrices
37
+ Const : (array) matrix for constant term
38
+ tolerance : (float) relative tolerance for checking real poles
39
+ """
40
+
41
+ #check validity of args
42
+ if not Poles or not Residues:
43
+ raise ValueError("No 'Poles' and 'Residues' defined!")
44
+
45
+ if len(Poles) != len(Residues):
46
+ raise ValueError("Same number of 'Poles' and 'Residues' have to be given!")
47
+
48
+ #make array
49
+ Residues = np.asarray(Residues)
50
+
51
+ #check shape of residues for MIMO, etc
52
+ if Residues.ndim == 1:
53
+ N, m, n = Residues.size, 1, 1
54
+ Residues = np.reshape(Residues, (N, m, n))
55
+ elif Residues.ndim == 2:
56
+ N, m, n = *Residues.shape, 1
57
+ Residues = np.reshape(Residues, (N, m, n))
58
+ elif Residues.ndim == 3:
59
+ N, m, n = Residues.shape
60
+ else:
61
+ raise ValueError(f"shape mismatch of 'Residues': Residues.shape={Residues.shape}")
62
+
63
+ # #dimension checks for residue matrices
64
+ # if isinstance(Residues, (list, tuple)) or Residues.size == len(Residues):
65
+ # Residues = np.reshape(Residues, (len(Residues), 1, 1))
66
+
67
+ # #get dimensions for MIMO
68
+ # N, m, n = Residues.shape
69
+
70
+ #initialize companion matrix
71
+ a = np.zeros((N, N))
72
+ b = np.zeros(N)
73
+
74
+ #residues
75
+ C = np.ones((m, n*N))
76
+
77
+ #go through poles and handle conjugate pairs
78
+ _Poles, _Residues = [], []
79
+ for p, R in zip(Poles, Residues):
80
+
81
+ #real pole
82
+ if np.isreal(p) or abs(np.imag(p) / np.real(p)) < tolerance:
83
+ _Poles.append(p.real)
84
+ _Residues.append(R.real)
85
+
86
+ #complex conjugate pair
87
+ elif np.imag(p) > 0.0:
88
+ _Poles.extend([p, np.conj(p)])
89
+ _Residues.extend([R, np.conj(R)])
90
+
91
+ #build real companion matrix from the poles
92
+ p_old = 0.0
93
+ for k, (p, R) in enumerate(zip(_Poles, _Residues)):
94
+
95
+ #check if complex conjugate
96
+ is_cc = (p.imag != 0.0 and p == np.conj(p_old))
97
+ p_old = p
98
+
99
+ a[k,k] = np.real(p)
100
+ b[k] = 1.0
101
+ if is_cc:
102
+ a[k, k-1] = - np.imag(p)
103
+ a[k-1, k] = np.imag(p)
104
+ b[k] = 0.0
105
+ b[k-1] = 2.0
106
+
107
+ #iterate columns of residue
108
+ for i in range(n):
109
+ C[:,k+N*i] = np.imag(R[:,i]) if is_cc else np.real(R[:,i])
110
+
111
+ #build block diagonal
112
+ A = np.kron(np.eye(n, dtype=float), a)
113
+ B = np.kron(np.eye(n, dtype=float), b).T
114
+ D = Const
115
+
116
+ return A, B, C, D
@@ -0,0 +1,36 @@
1
+ ########################################################################################
2
+ ##
3
+ ## WAVEFORM FUNCTIONS (utils/waveforms.py)
4
+ ##
5
+ ## Milan Rother 2023/24
6
+ ##
7
+ ########################################################################################
8
+
9
+ # IMPORTS ==============================================================================
10
+
11
+ import numpy as np
12
+
13
+
14
+ # WAVEFORMS ============================================================================
15
+
16
+ def gaussian(t, f_max):
17
+ """
18
+ gaussian pulse with its maximum at t=0
19
+ """
20
+ tau = 0.5 / f_max
21
+ return np.exp(-(t/tau)**2)
22
+
23
+
24
+ def triangle_wave(t, f):
25
+ """
26
+ triangle wave with amplitude '1' and frequency 'f'
27
+ """
28
+ return 2 * abs(t*f - np.floor(t*f + 0.5)) - 1
29
+
30
+
31
+ def square_wave(t, f):
32
+ """
33
+ square wave with amplitude '1' and frequency 'f'
34
+ """
35
+ return np.sign(np.sin(2*np.pi*f*t))
36
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Milan Rother
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.1
2
+ Name: pathsim
3
+ Version: 0.2.0
4
+ Summary: A block based time domain system simulation framework.
5
+ Home-page: https://github.com/milanofthe/pathsim
6
+ Author: Milan Rother
7
+ Author-email: milan.rother@gmx.de
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE.txt
14
+ Requires-Dist: numpy
15
+ Requires-Dist: matplotlib
16
+ Requires-Dist: scipy
17
+
18
+ # PathSim: A Time-Domain System Simulation Framework
19
+
20
+
21
+ ## Overview
22
+
23
+ PathSim is a minimalistic and flexible block-based time-domain system simulation framework in Python. It provides a modular and intuitive approach to modeling and simulating complex dynamical systems using a directed computational graph. It is similar to Matlab Simulink in spirit but works very differently under the hood.
24
+
25
+ Key features of PathSim include:
26
+
27
+ - Decentralized architecture where each dynamical block has their own numerical integration engine.
28
+ - The system is solved directly on the computational graph instead of compiling a unified differential algebraic system.
29
+ - This has some advantages such as hot-swappable blocks during simulation and reading simulation results directly from the scopes.
30
+ - The block execution is decoupled from the data transfer, which enables parallelization (future) and linear computational complexity scaling for sparsely connected systems.
31
+ - Support for MIMO (Multiple Input, Multiple Output) blocks, enabling the creation of complex interconnected system topologies.
32
+ - Fixed-point iteration approach with path length estimation to efficiently resolve algebraic loops.
33
+ - Wide range of numerical solvers, including implicit and explicit multi-stage, and adaptive Runge-Kutta methods such as `RKDP54` or `ESDIRK54`.
34
+ - Modular and hierarchical modeling with (nested) subsystems.
35
+ - Library of pre-defined blocks, including mathematical operations, integrators, delays, transfer functions, and more.
36
+ - Easy extensibility, allowing users to define custom blocks by subclassing the base `Block` class and implementing just a handful of methods.
37
+
38
+
39
+
40
+ ## Installation
41
+
42
+ Version `0.1.0` of pathsim is pip installable
43
+
44
+ ```console
45
+ $ pip install pathsim
46
+ ```
47
+
48
+ ## Getting Started
49
+
50
+ To get started with PathSim, you need to import the necessary modules and classes. The main components of the package are:
51
+
52
+ - `Simulation`: The main class that handles the blocks, connections, and the simulation loop.
53
+ - `Connection`: The class that defines the connections between blocks.
54
+ - Various block classes from the `blocks` module, such as `Integrator`, `Amplifier`, `Adder`, `Scope`, etc.
55
+
56
+ Here's an example that demonstrates how to create a basic simulation.
57
+ In this example, we create a simulation of the harmonic oscillator (a spring mass damper 2nd order system) initial value problem. The ODE that defines it is give by
58
+
59
+ $$
60
+ \ddot{x} + \frac{c}{m} \dot{x} + \frac{k}{m} x = 0
61
+ $$
62
+
63
+ where $c$ is the damping, $k$ the spring constant and $m$ the mass.
64
+
65
+ It can be translated to a block diagram using integrators, amplifiers and adders in the following way:
66
+
67
+ ![png](README_files/harmonic_oscillator_blockdiagram.png)
68
+
69
+ The topology of the block diagram above can be directly defined as blocks and connections in the PathSim framework. First we initialize the blocks needed to represent the dynamical systems with their respective arguments such as initial conditions and gain values, then the blocks are connected using `Connection` objects, forming two feedback loops. The `Simulation` instance manages the blocks and connections and advances the system in time with the timestep (`dt`). The `log` flag for logging the simulation progress is also set. Finally, we run the simulation for some number of seconds and plot the results using the `plot()` method of the scope block.
70
+
71
+
72
+
73
+ ```python
74
+ from pathsim import Simulation
75
+ from pathsim import Connection
76
+ from pathsim.blocks import Integrator, Amplifier, Adder, Scope
77
+ from pathsim.solvers import SSPRK22 # 2nd order fixed timestep, this is also the default
78
+
79
+ #initial position and velocity
80
+ x0, v0 = 2, 5
81
+
82
+ #parameters (mass, damping, spring constant)
83
+ m, c, k = 0.8, 0.2, 1.5
84
+
85
+ # Create blocks
86
+ I1 = Integrator(v0) # integrator for velocity
87
+ I2 = Integrator(x0) # integrator for position
88
+ A1 = Amplifier(-c/m)
89
+ A2 = Amplifier(-k/m)
90
+ P1 = Adder()
91
+ Sc = Scope(labels=["v(t)", "x(t)"])
92
+
93
+ blocks = [I1, I2, A1, A2, P1, Sc]
94
+
95
+ # Create connections
96
+ connections = [
97
+ Connection(I1, I2, A1, Sc), # one to many connection
98
+ Connection(I2, A2, Sc[1]),
99
+ Connection(A1, P1), # default connection to port 0
100
+ Connection(A2, P1[1]), # specific connection to port 1
101
+ Connection(P1, I1)
102
+ ]
103
+
104
+ # Create a simulation instance from the blocks and connections
105
+ Sim = Simulation(blocks, connections, dt=0.05, log=True, Solver=SSPRK22)
106
+
107
+ # Run the simulation for 50 seconds
108
+ Sim.run(duration=50.0)
109
+
110
+ # Plot the results directly from the scope
111
+ Sc.plot()
112
+
113
+ # Read the results from the scope for further processing
114
+ time, data = Sc.read()
115
+ ```
116
+
117
+ 2024-08-30 14:20:10,361 - INFO - LOGGING enabled
118
+ 2024-08-30 14:20:10,362 - INFO - SOLVER SSPRK22 adaptive=False implicit=False
119
+ 2024-08-30 14:20:10,363 - INFO - PATH LENGTH ESTIMATE 2, 'iterations_min' set to 2
120
+ 2024-08-30 14:20:10,364 - INFO - RESET
121
+ 2024-08-30 14:20:10,365 - INFO - RUN duration=50.0
122
+ 2024-08-30 14:20:10,366 - INFO - STARTING progress tracker
123
+ 2024-08-30 14:20:10,367 - INFO - progress=0%
124
+ 2024-08-30 14:20:10,400 - INFO - progress=10%
125
+ 2024-08-30 14:20:10,429 - INFO - progress=20%
126
+ 2024-08-30 14:20:10,455 - INFO - progress=30%
127
+ 2024-08-30 14:20:10,480 - INFO - progress=40%
128
+ 2024-08-30 14:20:10,504 - INFO - progress=50%
129
+ 2024-08-30 14:20:10,528 - INFO - progress=60%
130
+ 2024-08-30 14:20:10,553 - INFO - progress=70%
131
+ 2024-08-30 14:20:10,578 - INFO - progress=80%
132
+ 2024-08-30 14:20:10,603 - INFO - progress=90%
133
+ 2024-08-30 14:20:10,628 - INFO - progress=100%
134
+ 2024-08-30 14:20:10,629 - INFO - FINISHED steps(total)=1001(1001) runtime=262.03ms
135
+
136
+
137
+
138
+
139
+ ![png](README_files/README_4_1.png)
140
+
141
+
142
+
143
+ ## Examples
144
+ There are many examples of dynamical system simulations in the `examples` directory. They cover almost all the blocks currently available in PathSim as well as different solvers.
145
+
146
+
147
+ ```python
148
+
149
+ ```
@@ -0,0 +1,109 @@
1
+ pathsim/__init__.py,sha256=aNopp-VEK5mypHRIE4qipa09lb1_JxxLpObMLhc8GbM,115
2
+ pathsim/connection.py,sha256=UtQrC1xXpA--Yub9e04BXHrz4HXTtV9AfyfMRin3FLQ,3801
3
+ pathsim/simulation.py,sha256=tkZwrvJqGIgId9AosHILWatWAufdE1pzJGuokb78aMo,24663
4
+ pathsim/subsystem.py,sha256=yBGL6127V4K2K_hdQ1r8sCACrUBM2QL315MKaoO4NoQ,9228
5
+ pathsim/blocks/__init__.py,sha256=Hgb2olVDbPwuZUAhD9IDQENs-FecIU3_vugXqfcPd84,312
6
+ pathsim/blocks/_block.py,sha256=WDcDjXBpgz4d7PDMfBCrYKURu_ERvgtxBvRM7T8qU-U,7477
7
+ pathsim/blocks/adder.py,sha256=eDs33MtJ-ASBQuNRELCD4ygh8Ftjlp3dp6kO163X-5c,940
8
+ pathsim/blocks/amplifier.py,sha256=8iYUf0-hyqLgynS5eewAOX7Z5E_cvx0WvXWng3h0ryY,1033
9
+ pathsim/blocks/delay.py,sha256=Od1DhvdFQ3qHRMip-5d_oG_j1CNqfiMG9V-TgNO1Owo,1735
10
+ pathsim/blocks/differentiator.py,sha256=jKXi-xoOS0nUW8sqg1EwXQO-exOFlI2vor3swcP48Oc,2358
11
+ pathsim/blocks/function.py,sha256=zIjzqM8uaX6iHcpM6yuZxmQyAVwi4wXlhFH1RBj8FWE,2643
12
+ pathsim/blocks/integrator.py,sha256=LHYScbLK4ngLy1KW7PddLp833Sxy2Z-IuF13ox8I870,1994
13
+ pathsim/blocks/lti.py,sha256=rn_TL56YAuQdmRnK8AmY-zhA9SW1xrf0-FSQCitmJi4,5018
14
+ pathsim/blocks/multiplier.py,sha256=wkij46eZmBPyL7xgJtg9NIsedUQU5IwcnGGq9387A-0,962
15
+ pathsim/blocks/ode.py,sha256=YsI0yJkPL6UX9DvcO0_8S8It_W1HDNrtp2bigbThbfA,2734
16
+ pathsim/blocks/rng.py,sha256=SQ8il4MMyHIu7P_-vfRUYp6qtvpb6PvEuq5cX3glT6A,1569
17
+ pathsim/blocks/scope.py,sha256=OhrJSGq6hrQ_Kswobt7XBWYjsXh6I5gn31jHnhWQrPM,7619
18
+ pathsim/blocks/sources.py,sha256=Xq9AGFnS63Lpot75XyD3018_yy5Dwu3Sh81sEH0KdtM,1879
19
+ pathsim/blocks/spectrum.py,sha256=G5ByuLKYG5dHLV5NbQEIQrzSLIoCp-FiZ_hXUo4Ti3A,10737
20
+ pathsim/blocks/rf/__init__.py,sha256=h1cuLIIy5XhMyumLFzbIdOEMOJbpXHMQcl2oB1wapsE,102
21
+ pathsim/blocks/rf/filters.py,sha256=ccJgJZIPWz9jRUgTEyl_aMHA-PePPxnSa2-ufa12RCk,5143
22
+ pathsim/blocks/rf/noise.py,sha256=zvTDlIbja6TybavSrSGgRHAPqQkdwpjtuoenCV6YAro,6645
23
+ pathsim/blocks/rf/sources.py,sha256=HNS-GxIX2LMi8KwuOLCIquhQL5ZoMrgYU6vhQhAL9vA,4227
24
+ pathsim/blocks/rf/wienerhammerstein.py,sha256=19Tx7woy9COXWR-ruhLnN6UqZSMaB8RDe_PylrPKHwA,11326
25
+ pathsim/solvers/__init__.py,sha256=H3pyfkEdIGstc4kxx2F6jdnV5X5atnsipKiP_1ssyy4,470
26
+ pathsim/solvers/_solver.py,sha256=VW5Q_TNMzwCsYBfg2B-BUVm-MnRYHc0QxGNHLTgVLSY,14480
27
+ pathsim/solvers/bdf.py,sha256=McuDCILt-U_Edy-LqICfjF9xRJohy8nho-AGalTSFCA,6620
28
+ pathsim/solvers/dirk2.py,sha256=k_ALjWE0t2cF17ef5CBX6lwDcAR6wM3QUMdiv6dHo9E,3122
29
+ pathsim/solvers/dirk3.py,sha256=xh0G_rpAvK54ySL6ltTg6UU7vJl4PxY9UKx6MEQgF9c,2576
30
+ pathsim/solvers/esdirk32.py,sha256=Pgg-aYc82nS7J730ooPPgiX3tn6wdvTfDvL9LIaEkIw,3983
31
+ pathsim/solvers/esdirk4.py,sha256=slSmpxpKVNo5VN1RzlYS-82JLkQAvydRUO6DaOARcLs,3147
32
+ pathsim/solvers/esdirk43.py,sha256=9kzFABruWzO8aA2CBrIBoiTNPyN-FE_MBVUtuZwgXgo,4938
33
+ pathsim/solvers/esdirk54.py,sha256=ph8GmoQVanv8UVBgnIMKcPBad5LpMDuWcXYU4vifdCg,5475
34
+ pathsim/solvers/esdirk85.py,sha256=aqc3ckoTgc7_La7CVVaPJB0y2Wr2wv7erfI4hqcSbpA,9110
35
+ pathsim/solvers/euler.py,sha256=Yjg8wsrksioKzPqn545-alNUNcbFnyjEb_KxMN1eOCU,2479
36
+ pathsim/solvers/rk4.py,sha256=GLjSPPp78TbpLd9OnfmvwSiFVHspXK6L5eBcxtY7UDE,1887
37
+ pathsim/solvers/rkbs32.py,sha256=J5PNFRBAIpcEf7PqFeENqhvErhKCVD8aAT_MTL0Oo88,3333
38
+ pathsim/solvers/rkck54.py,sha256=TwS9REaREnYFjdU0JLgyh7ONKDH7s7cP_kTL1aQVF6c,3930
39
+ pathsim/solvers/rkdp54.py,sha256=403usE-QTRsF6dD8fyyRvwNUfrcril1CrwsDEIsNdq0,3894
40
+ pathsim/solvers/rkdp87.py,sha256=2tVLmZDiCOKiM-8Z6gk7K7qSCP18mWE8zrthtdNjJXc,5142
41
+ pathsim/solvers/rkf45.py,sha256=M_B1MADPNCZp46oMXzXjlfpAU8RNyqExfXEGpxrJo0Y,3386
42
+ pathsim/solvers/rkf78.py,sha256=oHa56fT6Xb9WzH1DZp-_YAIu-tfDYNSCaEkAjur0Rc8,4345
43
+ pathsim/solvers/rkv65.py,sha256=8md24OudOk-ndaryz3vxZ4OoQhM_DzEQuJDToyllLZE,3909
44
+ pathsim/solvers/ssprk22.py,sha256=fn4zdq4SJTihxWP2UTNFGCGlnDCDrIlijPF4Slp9G9g,2032
45
+ pathsim/solvers/ssprk33.py,sha256=hFs0LG8IFZEj2TTpmrOx5XUos21sQplBIoOQ8GKHFew,2131
46
+ pathsim/solvers/ssprk34.py,sha256=OyzhJ9yN3bzrG8Nc1b8kJs3SJaKhvH6If7wA9aNzM0U,2428
47
+ pathsim/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ pathsim/utils/adaptivebuffer.py,sha256=W6NDevnerPgZVBqA3ROwHJ_3ml3dCkwBABU0ZKY-pxE,2478
49
+ pathsim/utils/anderson.py,sha256=7q6GmWE41YeWTSmVY7xlq9LlkvL-97NoEMeGP-UHkRs,5315
50
+ pathsim/utils/funcs.py,sha256=dzJxy3xNRpyrO1ioqUfVYKcpTXvbUtTIVt4zbyykqZ0,6341
51
+ pathsim/utils/gilbert.py,sha256=YlH7T3UiCbObwoAP9N9lTRCzEcJc7WHwApcSh7ohmGU,3596
52
+ pathsim/utils/progresstracker.py,sha256=hRHB0--W9yGubBS99GqrUHDIjIwyV0F9MMU3miM_FEc,2894
53
+ pathsim/utils/realtimeplotter.py,sha256=zGEDzz1OgxIpSe3_1xaZZe8Y7YAoYqYwFkrUNE0w5VI,7595
54
+ pathsim/utils/statespacerealizations.py,sha256=uZpmwsJBCgUBvpdkZK56Lql9u-Ijee7xUdqM2LNpT8Y,3815
55
+ pathsim/utils/waveforms.py,sha256=9EkhL0BEfu69ggsd72S7XnnQryk4kzw5ZKaktKSjXNg,974
56
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ tests/test_connection.py,sha256=ThI58KrwjtuGegz1aUkLOX6uOomp8o2enutbBUX8hcU,5026
58
+ tests/test_simulation.py,sha256=UoKyKZ69cooUrLk4j2Rvws7SM-2P_CvSLxOgoz_Fixk,8890
59
+ tests/test_subsystem.py,sha256=mSqirgFVFhqsdNMeeRiU38cFoVygK-wTPn3CrKdIANc,5185
60
+ tests/blocks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ tests/blocks/test_adder.py,sha256=uKAKpPcJFRGaKtvfVbWf4xNUJRSKAPALZNk14EPcUww,1993
62
+ tests/blocks/test_amplifier.py,sha256=GAwiiZ2klXNK90BWZOk7x_YktAvRSeAnTWgDbrSbCBU,1609
63
+ tests/blocks/test_block.py,sha256=xl49c_fbdrHGdRilu4ZZBlQnUlg5iWWXtzub_JYJ3q0,3164
64
+ tests/blocks/test_delay.py,sha256=BZuTgTC698Tp9y1YWSay6E62jHqa8IZjSo03fvQa6ZM,2861
65
+ tests/blocks/test_differentiator.py,sha256=Y7vNdgo8bfRCSr0eXAwwBbs32UsYKllmiMwksdOubWU,2611
66
+ tests/blocks/test_function.py,sha256=Fkez0YE7RJZ1Ze5pJhm41zc528E10r467wz6kjLIPGc,3776
67
+ tests/blocks/test_integrator.py,sha256=UcIWZsqTsSRva1KklIVtaM8Mu27kg3NrvH6aQibDFrQ,2388
68
+ tests/blocks/test_lti.py,sha256=jUhBQz5VUdVN3FwTPt8RT7wz9RBcbUQNEJILMw1XRQ8,4995
69
+ tests/blocks/test_multiplier.py,sha256=V_FOVv7xX9MMB9SC_6xu1POz-czM-1E_w5oCcsQPbzw,2047
70
+ tests/blocks/test_ode.py,sha256=kWvx20ZBOJ6EN8yBieM4HQTZM7tvAJ-aR-P8JvhA_b8,3528
71
+ tests/blocks/test_rng.py,sha256=IekE8IQguWxq3Npmhfew9Ai2on1cJZxuypsNTll8XEI,2523
72
+ tests/blocks/test_scope.py,sha256=JP7VHD3d_gB3Bfq8t0ytHOnR4JO87epRcWSOicpxSQc,4710
73
+ tests/blocks/test_sources.py,sha256=4NBDeTASUYRgi1XxMULxdErl4XDIuBgWyekXEVlopyA,2733
74
+ tests/blocks/test_spectrum.py,sha256=Yqo9wk11LxTbjj8IM6Um2UaFQiafpPwwo-P7RYe3MX0,3410
75
+ tests/solvers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
+ tests/solvers/test_bdf.py,sha256=C7odQHrPyJbQaBoBA7d4V9efUX4zTmEApt-vA77ltB8,10430
77
+ tests/solvers/test_dirk2.py,sha256=g4Rt8XBTRMCvD85lj9xpz5t3z4AeZUJf5uj_CZlVCF8,4170
78
+ tests/solvers/test_dirk3.py,sha256=Wdpky5iPwV3V9Fd3wWTlX3HkRZ1T38R-bzI4LeDp31A,4165
79
+ tests/solvers/test_esdirk32.py,sha256=iwf24nhfMBaJM2B0K9JH6et5vMFLtmqxPvjsZ2-XxYg,4976
80
+ tests/solvers/test_esdirk4.py,sha256=QxQjcSjA7aq6BfuCNqhJZswsAd5GkBO1fj79ukYLzT0,4203
81
+ tests/solvers/test_esdirk43.py,sha256=Ugn2ib1o27J9gUxH1monA-92zFbmCTeUAgbkL_Mnn60,4978
82
+ tests/solvers/test_esdirk54.py,sha256=DkLUVx2_lQJlhN8NVc4ZcpV1aL_qi1q-BEOMklYz8aw,4944
83
+ tests/solvers/test_esdirk85.py,sha256=FwtN1JVVQAQ77sIEVbwGamC6hhBEWNLlYWYtPqZoAvU,4939
84
+ tests/solvers/test_euler.py,sha256=Xo2unPh3zUMobIiPDwwK7aa8YhiLhUoYCvJ0FCjKqZo,6594
85
+ tests/solvers/test_rk4.py,sha256=eXWT26GH-zkVEdrlHT8mY3VeHpZzgXwVf0BptbcQVjQ,4064
86
+ tests/solvers/test_rkbs32.py,sha256=fxwR3B3QxZuXr4QuA4VPrlGQ8Nj2HHr95_aUpXrrMIY,4870
87
+ tests/solvers/test_rkck54.py,sha256=ePNJyz3X7H9L0j1qlFkX8CEDCSsOeu2IVXzoR8WRqZs,4825
88
+ tests/solvers/test_rkdp54.py,sha256=7FeMOEMRZ4UKzkkOZP48HkfScw08ehXNTcBkjz2ggxo,4823
89
+ tests/solvers/test_rkdp87.py,sha256=Mq0Djn234qkWQ1WekbpAeXM-UAzJuA_FhTsnaopEgDA,4818
90
+ tests/solvers/test_rkf45.py,sha256=npa3eLtV2AGIsJhR_zuULQE4PQFs36oXVS7qQ02waC0,4818
91
+ tests/solvers/test_rkf78.py,sha256=Tx2aNewCbq3n8kXG4cct6a2609qByR4eZIXnKA2b_Po,4818
92
+ tests/solvers/test_rkv65.py,sha256=OLlIwxrWL2h3XnXJWnKJP9yh7nse0VXewiBfvwzdgaY,4822
93
+ tests/solvers/test_solver.py,sha256=z_GkWx5svV4Ro-fAzyG2Y-VBLBd-o0lmGTgQo2TNMVM,3668
94
+ tests/solvers/test_ssprk22.py,sha256=OzFKnVw52VnZa0xfTVIpJqOFwhpELsutoFSg5ruNdx8,4098
95
+ tests/solvers/test_ssprk33.py,sha256=o3zIGs1d9DU1FgNtgIs576Mg0TAv8IJEBKNQJafb1y0,4098
96
+ tests/solvers/test_ssprk34.py,sha256=QUs4UlCGUlLRUXf1qFI-yAAtw5SU30lLiGzfMo12wB8,4110
97
+ tests/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
+ tests/utils/test_adaptivebuffer.py,sha256=EC8sTZne89ta8e2H7zQSAr7tm14KMS19VWHm2VN-GxQ,2461
99
+ tests/utils/test_anderson.py,sha256=JGm_6sC87yt19BWpfUO3S7Wk4Gvo8i7PFzYKpQHEmCw,4726
100
+ tests/utils/test_funcs.py,sha256=Tfru6dz3M0RWay7iTws_B7NF9a4Tjz3Hll23Q4DXviI,4884
101
+ tests/utils/test_gilbert.py,sha256=cS0vJ-g9gdNDrRgP2TsHywJTdHeTxCfVy_5VWjgTrbQ,4428
102
+ tests/utils/test_progresstracker.py,sha256=zfcC2eT9_cs9adP-ep5BYl4yq0dCrJwE-ynh-bN6eM0,4240
103
+ tests/utils/test_realtimeplotter.py,sha256=Nm4RKxWvhjHgQ6NYjoNHwEQ32tZosqhESLQagbdi81w,4222
104
+ tests/utils/test_statespacerealizations.py,sha256=-wRawEUVWAdB7TpElxIZcn887n_W7VqcFZn51HPDh4I,4410
105
+ pathsim-0.2.0.dist-info/LICENSE.txt,sha256=SeKo1Ftp8_Vx3X1M1PvMci7qvSH7uP1E7E03KDoe91g,1088
106
+ pathsim-0.2.0.dist-info/METADATA,sha256=zG4r2JYWoc9Ic9DdQNLD1r3wQ5GvIPsHDI58HfU-i5w,6524
107
+ pathsim-0.2.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
108
+ pathsim-0.2.0.dist-info/top_level.txt,sha256=9VWhDKMqa75oeoSg49FLkQozQcozHLWUVX4aERkO40g,14
109
+ pathsim-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ pathsim
2
+ tests
tests/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,85 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.adder.py'
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.blocks.adder import Adder
16
+
17
+
18
+ # TESTS ================================================================================
19
+
20
+ class TestAdder(unittest.TestCase):
21
+ """
22
+ Test the implementation of the 'Adder' block class
23
+ """
24
+
25
+ def test_str(self):
26
+
27
+ A = Adder()
28
+
29
+ #test default str method
30
+ self.assertEqual(str(A), "Adder")
31
+
32
+
33
+ def test_update_single(self):
34
+
35
+ A = Adder()
36
+
37
+ #set block inputs
38
+ A.set(0, 1)
39
+
40
+ #update block
41
+ err = A.update(None)
42
+
43
+ #test if update was correct
44
+ self.assertEqual(A.get(0), 1)
45
+
46
+ #test if error was computed correctly
47
+ self.assertGreater(err, 0)
48
+
49
+ #update block again
50
+ err = A.update(None)
51
+
52
+ #test error, now should be 0
53
+ self.assertEqual(err, 0)
54
+
55
+
56
+ def test_update_multi(self):
57
+
58
+ A = Adder()
59
+
60
+ #set block inputs
61
+ A.set(0, 1)
62
+ A.set(1, 2.0)
63
+ A.set(2, 3.1)
64
+
65
+ #update block
66
+ err = A.update(None)
67
+
68
+ #test if update was correct
69
+ self.assertEqual(A.get(0), 6.1)
70
+
71
+ #test if error was computed correctly
72
+ self.assertGreater(err, 0)
73
+
74
+ #update block again
75
+ err = A.update(None)
76
+
77
+ #test error, now should be 0
78
+ self.assertEqual(err, 0)
79
+
80
+
81
+
82
+ # RUN TESTS LOCALLY ====================================================================
83
+
84
+ if __name__ == '__main__':
85
+ unittest.main(verbosity=2)
@@ -0,0 +1,66 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.amplifier.py'
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.blocks.amplifier import Amplifier
16
+
17
+
18
+ # TESTS ================================================================================
19
+
20
+ class TestAmplifier(unittest.TestCase):
21
+ """
22
+ Test the implementation of the 'Amplifier' block class
23
+ """
24
+
25
+ def test_init(self):
26
+
27
+ A = Amplifier(gain=5)
28
+
29
+ self.assertEqual(A.gain, 5)
30
+
31
+
32
+ def test_str(self):
33
+
34
+ A = Amplifier()
35
+
36
+ #test default str method
37
+ self.assertEqual(str(A), "Amplifier")
38
+
39
+
40
+ def test_update(self):
41
+
42
+ A = Amplifier(gain=5)
43
+
44
+ #set block inputs
45
+ A.set(0, 1)
46
+
47
+ #update block
48
+ err = A.update(None)
49
+
50
+ #test if update was correct
51
+ self.assertEqual(A.get(0), 5)
52
+
53
+ #test if error was computed correctly
54
+ self.assertGreater(err, 0)
55
+
56
+ #update block again
57
+ err = A.update(None)
58
+
59
+ #test error, now should be 0
60
+ self.assertEqual(err, 0)
61
+
62
+
63
+ # RUN TESTS LOCALLY ====================================================================
64
+
65
+ if __name__ == '__main__':
66
+ unittest.main(verbosity=2)