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,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)