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,138 @@
|
|
|
1
|
+
########################################################################################
|
|
2
|
+
##
|
|
3
|
+
## TESTS FOR
|
|
4
|
+
## 'blocks._block.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._block import Block
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# TESTS ================================================================================
|
|
19
|
+
|
|
20
|
+
class TestBlock(unittest.TestCase):
|
|
21
|
+
"""
|
|
22
|
+
Test the implementation of the base 'Block' class
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def test_init(self):
|
|
26
|
+
|
|
27
|
+
B = Block()
|
|
28
|
+
|
|
29
|
+
#test default inputs and outputs
|
|
30
|
+
self.assertEqual(B.inputs, {0: 0.0})
|
|
31
|
+
self.assertEqual(B.outputs, {0: 0.0})
|
|
32
|
+
|
|
33
|
+
#test default engine
|
|
34
|
+
self.assertEqual(B.engine, None)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_len(self):
|
|
38
|
+
|
|
39
|
+
B = Block()
|
|
40
|
+
|
|
41
|
+
#test default len method
|
|
42
|
+
self.assertEqual(len(B), 1)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_str(self):
|
|
46
|
+
|
|
47
|
+
B = Block()
|
|
48
|
+
|
|
49
|
+
#test default str method
|
|
50
|
+
self.assertEqual(str(B), "Block")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_getitem(self):
|
|
54
|
+
|
|
55
|
+
B = Block()
|
|
56
|
+
|
|
57
|
+
#test default getitem method (for connection creation)
|
|
58
|
+
self.assertEqual(B[0], (B, 0))
|
|
59
|
+
self.assertEqual(B[1], (B, 1))
|
|
60
|
+
self.assertEqual(B[2], (B, 2))
|
|
61
|
+
|
|
62
|
+
#test input validation
|
|
63
|
+
with self.assertRaises(ValueError): B[0.2]
|
|
64
|
+
with self.assertRaises(ValueError): B[1j]
|
|
65
|
+
with self.assertRaises(ValueError): B["a"]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_reset(self):
|
|
69
|
+
|
|
70
|
+
B = Block()
|
|
71
|
+
|
|
72
|
+
B.inputs = {0:0, 2:2, 1:1}
|
|
73
|
+
B.outputs = {1:1, 0:0, 2:2}
|
|
74
|
+
|
|
75
|
+
B.reset()
|
|
76
|
+
|
|
77
|
+
#test if inputs and outputs are reset correctly
|
|
78
|
+
self.assertEqual(B.inputs, {0:0.0, 1:0.0, 2:0.0})
|
|
79
|
+
self.assertEqual(B.outputs, {0:0.0, 1:0.0, 2:0.0})
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_set(self):
|
|
83
|
+
|
|
84
|
+
B = Block()
|
|
85
|
+
|
|
86
|
+
B.set(0, 1)
|
|
87
|
+
self.assertEqual(B.inputs[0], 1)
|
|
88
|
+
|
|
89
|
+
B.set(0, 2)
|
|
90
|
+
self.assertEqual(B.inputs[0], 2)
|
|
91
|
+
|
|
92
|
+
B.set(2, 3)
|
|
93
|
+
self.assertEqual(B.inputs[2], 3)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_get(self):
|
|
97
|
+
|
|
98
|
+
B = Block()
|
|
99
|
+
|
|
100
|
+
B.outputs = {0:0, 2:2, 1:1}
|
|
101
|
+
|
|
102
|
+
self.assertEqual(B.get(0), 0)
|
|
103
|
+
self.assertEqual(B.get(1), 1)
|
|
104
|
+
self.assertEqual(B.get(2), 2)
|
|
105
|
+
|
|
106
|
+
#undefined output -> defaults to 0.0
|
|
107
|
+
self.assertEqual(B.get(100), 0.0)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_update(self):
|
|
111
|
+
|
|
112
|
+
B = Block()
|
|
113
|
+
|
|
114
|
+
#test default implementation
|
|
115
|
+
self.assertEqual(B.update(None), 0.0)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_solve(self):
|
|
119
|
+
|
|
120
|
+
B = Block()
|
|
121
|
+
|
|
122
|
+
#test default implementation
|
|
123
|
+
self.assertEqual(B.solve(None, None), 0.0)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_step(self):
|
|
127
|
+
|
|
128
|
+
B = Block()
|
|
129
|
+
|
|
130
|
+
#test default implementation
|
|
131
|
+
self.assertEqual(B.step(None, None), (True, 0.0, 1.0))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# RUN TESTS LOCALLY ====================================================================
|
|
136
|
+
|
|
137
|
+
if __name__ == '__main__':
|
|
138
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
########################################################################################
|
|
2
|
+
##
|
|
3
|
+
## TESTS FOR
|
|
4
|
+
## 'blocks.delay.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.delay import Delay
|
|
16
|
+
from pathsim.utils.adaptivebuffer import AdaptiveBuffer
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# TESTS ================================================================================
|
|
20
|
+
|
|
21
|
+
class TestDelay(unittest.TestCase):
|
|
22
|
+
"""
|
|
23
|
+
Test the implementation of the 'Delay' block class
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def test_init(self):
|
|
27
|
+
|
|
28
|
+
#test specific initialization
|
|
29
|
+
D = Delay(tau=1)
|
|
30
|
+
|
|
31
|
+
self.assertTrue(isinstance(D._buffer, AdaptiveBuffer))
|
|
32
|
+
self.assertEqual(D.tau, 1)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_len(self):
|
|
36
|
+
|
|
37
|
+
D = Delay()
|
|
38
|
+
|
|
39
|
+
#no passthrough
|
|
40
|
+
self.assertEqual(len(D), 0)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_str(self):
|
|
44
|
+
|
|
45
|
+
D = Delay()
|
|
46
|
+
|
|
47
|
+
#test default str method
|
|
48
|
+
self.assertEqual(str(D), "Delay")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_reset(self):
|
|
52
|
+
|
|
53
|
+
D = Delay(tau=100)
|
|
54
|
+
|
|
55
|
+
for t in range(10):
|
|
56
|
+
D.sample(t)
|
|
57
|
+
|
|
58
|
+
self.assertEqual(len(D._buffer), 10)
|
|
59
|
+
|
|
60
|
+
D.reset()
|
|
61
|
+
|
|
62
|
+
#test if reset worked
|
|
63
|
+
self.assertEqual(len(D._buffer), 0)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_sample(self):
|
|
67
|
+
|
|
68
|
+
D = Delay(tau=100)
|
|
69
|
+
|
|
70
|
+
for t in range(10):
|
|
71
|
+
|
|
72
|
+
#test internal buffer length
|
|
73
|
+
self.assertEqual(len(D._buffer), t)
|
|
74
|
+
|
|
75
|
+
D.sample(t)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_update(self):
|
|
79
|
+
|
|
80
|
+
#test delay without interpolation
|
|
81
|
+
D = Delay(tau=10)
|
|
82
|
+
|
|
83
|
+
for t in range(100):
|
|
84
|
+
|
|
85
|
+
#test internal buffer length
|
|
86
|
+
self.assertEqual(len(D._buffer), t)
|
|
87
|
+
|
|
88
|
+
D.set(0, t)
|
|
89
|
+
D.sample(t)
|
|
90
|
+
|
|
91
|
+
err = D.update(t)
|
|
92
|
+
|
|
93
|
+
#test if error returns correctly
|
|
94
|
+
self.assertEqual(err, 0)
|
|
95
|
+
|
|
96
|
+
#test if delay is correctly applied
|
|
97
|
+
self.assertEqual(D.get(0), max(0, t-10))
|
|
98
|
+
|
|
99
|
+
#test delay with local interpolation
|
|
100
|
+
D = Delay(tau=10.5)
|
|
101
|
+
|
|
102
|
+
for t in range(100):
|
|
103
|
+
|
|
104
|
+
#test internal buffer length
|
|
105
|
+
self.assertEqual(len(D._buffer), t)
|
|
106
|
+
|
|
107
|
+
D.set(0, t)
|
|
108
|
+
D.sample(t)
|
|
109
|
+
|
|
110
|
+
err = D.update(t)
|
|
111
|
+
|
|
112
|
+
#test if error returns correctly
|
|
113
|
+
self.assertEqual(err, 0)
|
|
114
|
+
|
|
115
|
+
#test if delay is correctly applied
|
|
116
|
+
self.assertEqual(D.get(0), max(0, t-10.5))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# RUN TESTS LOCALLY ====================================================================
|
|
120
|
+
|
|
121
|
+
if __name__ == '__main__':
|
|
122
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
########################################################################################
|
|
2
|
+
##
|
|
3
|
+
## TESTS FOR
|
|
4
|
+
## 'blocks.differentiator.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.differentiator import Differentiator
|
|
16
|
+
|
|
17
|
+
#base solver for testing
|
|
18
|
+
from pathsim.solvers._solver import Solver
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# TESTS ================================================================================
|
|
22
|
+
|
|
23
|
+
class TestDifferentiator(unittest.TestCase):
|
|
24
|
+
"""
|
|
25
|
+
Test the implementation of the 'Differentiator' block class
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def test_init(self):
|
|
29
|
+
|
|
30
|
+
#test default initialization
|
|
31
|
+
D = Differentiator()
|
|
32
|
+
self.assertEqual(D.f_max, 1e2)
|
|
33
|
+
self.assertEqual(D.engine, None)
|
|
34
|
+
|
|
35
|
+
#test special initialization
|
|
36
|
+
D = Differentiator(f_max=1e3)
|
|
37
|
+
self.assertEqual(D.f_max, 1e3)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_len(self):
|
|
41
|
+
|
|
42
|
+
D = Differentiator()
|
|
43
|
+
|
|
44
|
+
#has direct passthrough
|
|
45
|
+
self.assertEqual(len(D), 1)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_str(self):
|
|
49
|
+
|
|
50
|
+
D = Differentiator()
|
|
51
|
+
|
|
52
|
+
#test default str method
|
|
53
|
+
self.assertEqual(str(D), "Differentiator")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_set_solver(self):
|
|
57
|
+
|
|
58
|
+
D = Differentiator()
|
|
59
|
+
|
|
60
|
+
#test that no solver is initialized
|
|
61
|
+
self.assertEqual(D.engine, None)
|
|
62
|
+
|
|
63
|
+
D.set_solver(Solver, tolerance_lte=1e-6)
|
|
64
|
+
|
|
65
|
+
#test that solver is now available
|
|
66
|
+
self.assertTrue(isinstance(D.engine, Solver))
|
|
67
|
+
self.assertEqual(D.engine.tolerance_lte, 1e-6)
|
|
68
|
+
|
|
69
|
+
D.set_solver(Solver, tolerance_lte=1e-3)
|
|
70
|
+
|
|
71
|
+
#test that solver tolerance is changed
|
|
72
|
+
self.assertEqual(D.engine.tolerance_lte, 1e-3)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_update(self):
|
|
76
|
+
|
|
77
|
+
D = Differentiator()
|
|
78
|
+
D.set_solver(Solver)
|
|
79
|
+
|
|
80
|
+
#test that input is zero
|
|
81
|
+
self.assertEqual(D.inputs[0], 0.0)
|
|
82
|
+
|
|
83
|
+
err = D.update(0)
|
|
84
|
+
|
|
85
|
+
#test if error is correctly 0
|
|
86
|
+
self.assertEqual(err, 0.0)
|
|
87
|
+
|
|
88
|
+
#test if state is retrieved correctly
|
|
89
|
+
self.assertEqual(D.get(0), 0.0)
|
|
90
|
+
|
|
91
|
+
D.set(0, 2)
|
|
92
|
+
|
|
93
|
+
err = D.update(0)
|
|
94
|
+
|
|
95
|
+
#test if error is correctly calculated
|
|
96
|
+
self.assertEqual(err, D.f_max*2)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# RUN TESTS LOCALLY ====================================================================
|
|
100
|
+
|
|
101
|
+
if __name__ == '__main__':
|
|
102
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
########################################################################################
|
|
2
|
+
##
|
|
3
|
+
## TESTS FOR
|
|
4
|
+
## 'blocks.function.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.function import Function
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# TESTS ================================================================================
|
|
19
|
+
|
|
20
|
+
class TestFunction(unittest.TestCase):
|
|
21
|
+
"""
|
|
22
|
+
Test the implementation of the 'Function' block class
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def test_init(self):
|
|
26
|
+
|
|
27
|
+
def f(a):
|
|
28
|
+
return a**2
|
|
29
|
+
|
|
30
|
+
F = Function(func=f)
|
|
31
|
+
|
|
32
|
+
#test if the function works
|
|
33
|
+
self.assertEqual(F.func(1), f(1))
|
|
34
|
+
self.assertEqual(F.func(2), f(2))
|
|
35
|
+
self.assertEqual(F.func(3), f(3))
|
|
36
|
+
|
|
37
|
+
#test input validation
|
|
38
|
+
with self.assertRaises(ValueError):
|
|
39
|
+
F = Function(func=2)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_str(self):
|
|
43
|
+
|
|
44
|
+
F = Function()
|
|
45
|
+
|
|
46
|
+
#test default str method
|
|
47
|
+
self.assertEqual(str(F), "Function")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_update_siso(self):
|
|
51
|
+
|
|
52
|
+
def f(a):
|
|
53
|
+
return a**2
|
|
54
|
+
|
|
55
|
+
F = Function(func=f)
|
|
56
|
+
|
|
57
|
+
#set block inputs
|
|
58
|
+
F.set(0, 3)
|
|
59
|
+
|
|
60
|
+
#update block
|
|
61
|
+
err = F.update(None)
|
|
62
|
+
|
|
63
|
+
#test if update was correct
|
|
64
|
+
self.assertEqual(F.get(0), f(3))
|
|
65
|
+
|
|
66
|
+
#test if error was computed correctly
|
|
67
|
+
self.assertGreater(err, 0)
|
|
68
|
+
|
|
69
|
+
#update block again
|
|
70
|
+
err = F.update(None)
|
|
71
|
+
|
|
72
|
+
#test error, now should be 0
|
|
73
|
+
self.assertEqual(err, 0)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_update_miso(self):
|
|
77
|
+
|
|
78
|
+
def f(a, b, c):
|
|
79
|
+
return a**2 + b - c
|
|
80
|
+
|
|
81
|
+
F = Function(func=f)
|
|
82
|
+
|
|
83
|
+
#set block inputs
|
|
84
|
+
F.set(0, 3)
|
|
85
|
+
F.set(1, 2)
|
|
86
|
+
F.set(2, 1)
|
|
87
|
+
|
|
88
|
+
#update block
|
|
89
|
+
err = F.update(None)
|
|
90
|
+
|
|
91
|
+
#test if update was correct
|
|
92
|
+
self.assertEqual(F.get(0), f(3, 2, 1))
|
|
93
|
+
|
|
94
|
+
#test if error was computed correctly
|
|
95
|
+
self.assertGreater(err, 0)
|
|
96
|
+
|
|
97
|
+
#update block again
|
|
98
|
+
err = F.update(None)
|
|
99
|
+
|
|
100
|
+
#test error, now should be 0
|
|
101
|
+
self.assertEqual(err, 0)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_update_simo(self):
|
|
105
|
+
|
|
106
|
+
def f(a):
|
|
107
|
+
return a**2, 2*a, 1
|
|
108
|
+
|
|
109
|
+
F = Function(func=f)
|
|
110
|
+
|
|
111
|
+
#set block inputs
|
|
112
|
+
F.set(0, 3)
|
|
113
|
+
|
|
114
|
+
#update block
|
|
115
|
+
err = F.update(None)
|
|
116
|
+
|
|
117
|
+
#test if update was correct
|
|
118
|
+
self.assertEqual(F.get(0), 9)
|
|
119
|
+
self.assertEqual(F.get(1), 6)
|
|
120
|
+
self.assertEqual(F.get(2), 1)
|
|
121
|
+
|
|
122
|
+
#test if error was computed correctly
|
|
123
|
+
self.assertGreater(err, 0)
|
|
124
|
+
|
|
125
|
+
#update block again
|
|
126
|
+
err = F.update(None)
|
|
127
|
+
|
|
128
|
+
#test error, now should be 0
|
|
129
|
+
self.assertEqual(err, 0)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_update_mimo(self):
|
|
133
|
+
|
|
134
|
+
def f(a, b, c):
|
|
135
|
+
return a**2-b, 3*c
|
|
136
|
+
|
|
137
|
+
F = Function(func=f)
|
|
138
|
+
|
|
139
|
+
#set block inputs
|
|
140
|
+
F.set(0, 3)
|
|
141
|
+
F.set(1, 2)
|
|
142
|
+
F.set(2, 1)
|
|
143
|
+
|
|
144
|
+
#update block
|
|
145
|
+
err = F.update(None)
|
|
146
|
+
|
|
147
|
+
#test if update was correct
|
|
148
|
+
self.assertEqual(F.get(0), 7)
|
|
149
|
+
self.assertEqual(F.get(1), 3)
|
|
150
|
+
|
|
151
|
+
#test if error was computed correctly
|
|
152
|
+
self.assertGreater(err, 0)
|
|
153
|
+
|
|
154
|
+
#update block again
|
|
155
|
+
err = F.update(None)
|
|
156
|
+
|
|
157
|
+
#test error, now should be 0
|
|
158
|
+
self.assertEqual(err, 0)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# RUN TESTS LOCALLY ====================================================================
|
|
163
|
+
|
|
164
|
+
if __name__ == '__main__':
|
|
165
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
########################################################################################
|
|
2
|
+
##
|
|
3
|
+
## TESTS FOR
|
|
4
|
+
## 'blocks.integrator.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.integrator import Integrator
|
|
16
|
+
|
|
17
|
+
#base solver for testing
|
|
18
|
+
from pathsim.solvers._solver import Solver
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# TESTS ================================================================================
|
|
22
|
+
|
|
23
|
+
class TestIntegrator(unittest.TestCase):
|
|
24
|
+
"""
|
|
25
|
+
Test the implementation of the 'Integrator' block class
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def test_init(self):
|
|
29
|
+
|
|
30
|
+
#test default initialization
|
|
31
|
+
I = Integrator()
|
|
32
|
+
self.assertEqual(I.initial_value, 0.0)
|
|
33
|
+
self.assertEqual(I.engine, None)
|
|
34
|
+
|
|
35
|
+
#test special initialization
|
|
36
|
+
I = Integrator(initial_value=1.0)
|
|
37
|
+
self.assertEqual(I.initial_value, 1.0)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_len(self):
|
|
41
|
+
|
|
42
|
+
I = Integrator()
|
|
43
|
+
|
|
44
|
+
#no direct passthrough
|
|
45
|
+
self.assertEqual(len(I), 0)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_str(self):
|
|
49
|
+
|
|
50
|
+
I = Integrator()
|
|
51
|
+
|
|
52
|
+
#test default str method
|
|
53
|
+
self.assertEqual(str(I), "Integrator")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_set_solver(self):
|
|
57
|
+
|
|
58
|
+
I = Integrator()
|
|
59
|
+
|
|
60
|
+
#test that no solver is initialized
|
|
61
|
+
self.assertEqual(I.engine, None)
|
|
62
|
+
|
|
63
|
+
I.set_solver(Solver, tolerance_lte=1e-6)
|
|
64
|
+
|
|
65
|
+
#test that solver is now available
|
|
66
|
+
self.assertTrue(isinstance(I.engine, Solver))
|
|
67
|
+
self.assertEqual(I.engine.tolerance_lte, 1e-6)
|
|
68
|
+
|
|
69
|
+
I.set_solver(Solver, tolerance_lte=1e-3)
|
|
70
|
+
|
|
71
|
+
#test that solver tolerance is changed
|
|
72
|
+
self.assertEqual(I.engine.tolerance_lte, 1e-3)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_update(self):
|
|
76
|
+
|
|
77
|
+
I = Integrator(initial_value=5.5)
|
|
78
|
+
I.set_solver(Solver)
|
|
79
|
+
|
|
80
|
+
err = I.update(0)
|
|
81
|
+
|
|
82
|
+
#test if error is correctly 0
|
|
83
|
+
self.assertEqual(err, 0.0)
|
|
84
|
+
|
|
85
|
+
#test if engine state is retrieved correctly
|
|
86
|
+
self.assertEqual(I.get(0), 5.5)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# RUN TESTS LOCALLY ====================================================================
|
|
90
|
+
|
|
91
|
+
if __name__ == '__main__':
|
|
92
|
+
unittest.main(verbosity=2)
|