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.
- pathsim/__init__.py +3 -0
- pathsim/blocks/__init__.py +14 -0
- pathsim/blocks/_block.py +209 -0
- pathsim/blocks/adder.py +30 -0
- pathsim/blocks/amplifier.py +34 -0
- pathsim/blocks/delay.py +70 -0
- pathsim/blocks/differentiator.py +70 -0
- pathsim/blocks/function.py +82 -0
- pathsim/blocks/integrator.py +66 -0
- pathsim/blocks/lti.py +155 -0
- pathsim/blocks/multiplier.py +30 -0
- pathsim/blocks/ode.py +86 -0
- pathsim/blocks/rf/__init__.py +4 -0
- pathsim/blocks/rf/filters.py +169 -0
- pathsim/blocks/rf/noise.py +218 -0
- pathsim/blocks/rf/sources.py +163 -0
- pathsim/blocks/rf/wienerhammerstein.py +338 -0
- pathsim/blocks/rng.py +57 -0
- pathsim/blocks/scope.py +224 -0
- pathsim/blocks/sources.py +71 -0
- pathsim/blocks/spectrum.py +316 -0
- pathsim/connection.py +112 -0
- pathsim/simulation.py +652 -0
- pathsim/solvers/__init__.py +25 -0
- pathsim/solvers/_solver.py +403 -0
- pathsim/solvers/bdf.py +240 -0
- pathsim/solvers/dirk2.py +101 -0
- pathsim/solvers/dirk3.py +86 -0
- pathsim/solvers/esdirk32.py +131 -0
- pathsim/solvers/esdirk4.py +99 -0
- pathsim/solvers/esdirk43.py +139 -0
- pathsim/solvers/esdirk54.py +141 -0
- pathsim/solvers/esdirk85.py +200 -0
- pathsim/solvers/euler.py +81 -0
- pathsim/solvers/rk4.py +61 -0
- pathsim/solvers/rkbs32.py +101 -0
- pathsim/solvers/rkck54.py +108 -0
- pathsim/solvers/rkdp54.py +111 -0
- pathsim/solvers/rkdp87.py +116 -0
- pathsim/solvers/rkf45.py +102 -0
- pathsim/solvers/rkf78.py +111 -0
- pathsim/solvers/rkv65.py +103 -0
- pathsim/solvers/ssprk22.py +62 -0
- pathsim/solvers/ssprk33.py +65 -0
- pathsim/solvers/ssprk34.py +74 -0
- pathsim/subsystem.py +267 -0
- pathsim/utils/__init__.py +0 -0
- pathsim/utils/adaptivebuffer.py +87 -0
- pathsim/utils/anderson.py +180 -0
- pathsim/utils/funcs.py +205 -0
- pathsim/utils/gilbert.py +110 -0
- pathsim/utils/progresstracker.py +90 -0
- pathsim/utils/realtimeplotter.py +230 -0
- pathsim/utils/statespacerealizations.py +116 -0
- pathsim/utils/waveforms.py +36 -0
- pathsim-0.2.0.dist-info/LICENSE.txt +21 -0
- pathsim-0.2.0.dist-info/METADATA +149 -0
- pathsim-0.2.0.dist-info/RECORD +109 -0
- pathsim-0.2.0.dist-info/WHEEL +5 -0
- pathsim-0.2.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/blocks/__init__.py +0 -0
- tests/blocks/test_adder.py +85 -0
- tests/blocks/test_amplifier.py +66 -0
- tests/blocks/test_block.py +138 -0
- tests/blocks/test_delay.py +122 -0
- tests/blocks/test_differentiator.py +102 -0
- tests/blocks/test_function.py +165 -0
- tests/blocks/test_integrator.py +92 -0
- tests/blocks/test_lti.py +162 -0
- tests/blocks/test_multiplier.py +87 -0
- tests/blocks/test_ode.py +125 -0
- tests/blocks/test_rng.py +109 -0
- tests/blocks/test_scope.py +196 -0
- tests/blocks/test_sources.py +119 -0
- tests/blocks/test_spectrum.py +119 -0
- tests/solvers/__init__.py +0 -0
- tests/solvers/test_bdf.py +364 -0
- tests/solvers/test_dirk2.py +138 -0
- tests/solvers/test_dirk3.py +137 -0
- tests/solvers/test_esdirk32.py +158 -0
- tests/solvers/test_esdirk4.py +138 -0
- tests/solvers/test_esdirk43.py +158 -0
- tests/solvers/test_esdirk54.py +160 -0
- tests/solvers/test_esdirk85.py +157 -0
- tests/solvers/test_euler.py +223 -0
- tests/solvers/test_rk4.py +138 -0
- tests/solvers/test_rkbs32.py +159 -0
- tests/solvers/test_rkck54.py +157 -0
- tests/solvers/test_rkdp54.py +159 -0
- tests/solvers/test_rkdp87.py +157 -0
- tests/solvers/test_rkf45.py +159 -0
- tests/solvers/test_rkf78.py +160 -0
- tests/solvers/test_rkv65.py +160 -0
- tests/solvers/test_solver.py +119 -0
- tests/solvers/test_ssprk22.py +136 -0
- tests/solvers/test_ssprk33.py +136 -0
- tests/solvers/test_ssprk34.py +136 -0
- tests/test_connection.py +176 -0
- tests/test_simulation.py +271 -0
- tests/test_subsystem.py +182 -0
- tests/utils/__init__.py +0 -0
- tests/utils/test_adaptivebuffer.py +111 -0
- tests/utils/test_anderson.py +142 -0
- tests/utils/test_funcs.py +143 -0
- tests/utils/test_gilbert.py +108 -0
- tests/utils/test_progresstracker.py +144 -0
- tests/utils/test_realtimeplotter.py +122 -0
- 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
|
+

|
|
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
|
+

|
|
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,,
|
tests/__init__.py
ADDED
|
File without changes
|
tests/blocks/__init__.py
ADDED
|
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)
|