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,162 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.lti.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.lti import StateSpace, TransferFunction
16
+
17
+ #base solver for testing
18
+ from pathsim.solvers._solver import Solver
19
+
20
+
21
+ # TESTS ================================================================================
22
+
23
+ class TestStateSpace(unittest.TestCase):
24
+ """
25
+ Test the implementation of the 'StateSpace' block class
26
+ """
27
+
28
+ def test_init(self):
29
+
30
+ #test default initialization
31
+ S = StateSpace()
32
+ self.assertEqual(S.initial_value, 0.0)
33
+ self.assertEqual(S.engine, None)
34
+ self.assertEqual(S.inputs, {0:0.0})
35
+ self.assertEqual(S.outputs, {0:0.0})
36
+
37
+ #test special initialization (siso)
38
+ S = StateSpace(A=np.eye(2),
39
+ B=np.ones(2),
40
+ C=np.ones(2),
41
+ D=1,
42
+ initial_value=None)
43
+ self.assertTrue(np.all(S.initial_value == np.zeros(2)))
44
+ self.assertEqual(S.inputs, {0:0.0})
45
+ self.assertEqual(S.outputs, {0:0.0})
46
+
47
+ #test special initialization (mimo)
48
+ S = StateSpace(A=np.eye(2),
49
+ B=np.ones((2, 2)),
50
+ C=np.ones((2, 2)),
51
+ D=np.ones((2, 2)),
52
+ initial_value=np.ones(2))
53
+ self.assertTrue(np.all(S.initial_value == np.ones(2)))
54
+ self.assertEqual(S.inputs, {0:0.0, 1:0.0})
55
+ self.assertEqual(S.outputs, {0:0.0, 1:0.0})
56
+
57
+
58
+ def test_len(self):
59
+
60
+ #no direct passthrough (siso)
61
+ S = StateSpace(D=0)
62
+ self.assertEqual(len(S), 0)
63
+
64
+ #no direct passthrough (mimo)
65
+ S = StateSpace(D=np.zeros(2))
66
+ self.assertEqual(len(S), 0)
67
+
68
+ #direct passthrough (siso)
69
+ S = StateSpace(D=3)
70
+ self.assertEqual(len(S), 1)
71
+
72
+ #direct passthrough (mimo)
73
+ S = StateSpace(D=np.array([0, 5]))
74
+ self.assertEqual(len(S), 1)
75
+
76
+
77
+ def test_str(self):
78
+
79
+ S = StateSpace()
80
+
81
+ #test default str method
82
+ self.assertEqual(str(S), "StateSpace")
83
+
84
+
85
+ def test_set_solver(self):
86
+
87
+ S = StateSpace(initial_value=1.0)
88
+
89
+ #test that no solver is initialized
90
+ self.assertEqual(S.engine, None)
91
+
92
+ S.set_solver(Solver, tolerance_lte=1e-6)
93
+
94
+ #test that solver is now available
95
+ self.assertTrue(isinstance(S.engine, Solver))
96
+
97
+ #test that solver parametes have been set
98
+ self.assertEqual(S.engine.tolerance_lte, 1e-6)
99
+ self.assertEqual(S.engine.initial_value, 1.0)
100
+
101
+ #test that jacobian has been generated correctly
102
+ self.assertEqual(S.engine.jac(0, 0, 0), S.A)
103
+
104
+ S.set_solver(Solver, tolerance_lte=1e-3)
105
+
106
+ #test that solver tolerance is changed
107
+ self.assertEqual(S.engine.tolerance_lte, 1e-3)
108
+
109
+
110
+ def test_update(self):
111
+
112
+ S = StateSpace(initial_value=1.1)
113
+ S.set_solver(Solver)
114
+
115
+ #test if output is zero
116
+ self.assertEqual(S.get(0), 0.0)
117
+
118
+ S.set(0, 3.3)
119
+ err = S.update(0)
120
+
121
+ #test if error is correctly 0
122
+ self.assertGreater(err, 0.0)
123
+
124
+ #test if engine state is calculated correctly
125
+ self.assertAlmostEqual(S.get(0), 2.2, 8)
126
+
127
+
128
+ class TtestTransferFunction(unittest.TestCase):
129
+ """
130
+ Test the implementation of the 'TransferFunction' block class
131
+
132
+ inherits most methods from the 'StateSpace' block, so only
133
+ testing ot the initialization is required
134
+ """
135
+
136
+ def test_init(self):
137
+
138
+ #test default initialization
139
+ with self.assertRaises(ValueError):
140
+ T = TransferFunction()
141
+
142
+ #test specific initialization (siso)
143
+ T = TransferFunction(Poles=2, Residues=0.5, Const=5.5)
144
+ self.assertEqual(T.A, 2)
145
+ self.assertEqual(T.B, 1)
146
+ self.assertEqual(T.C, 0.5)
147
+ self.assertEqual(T.D, 5.5)
148
+
149
+ #test specific initialization (mimo)
150
+ T = TransferFunction(Poles=np.array([1, 2]),
151
+ Residues=2*np.ones((2, 2)),
152
+ Const=np.ones(2))
153
+ self.assertTrue(np.all(T.A == np.diag(np.array([1, 2]))))
154
+ self.assertTrue(np.all(T.B == np.ones(2)))
155
+ self.assertTrue(np.all(T.C == 2*np.ones(2)))
156
+ self.assertTrue(np.all(T.D == np.ones(2)))
157
+
158
+
159
+ # RUN TESTS LOCALLY ====================================================================
160
+
161
+ if __name__ == '__main__':
162
+ unittest.main(verbosity=2)
@@ -0,0 +1,87 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.multiplier.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.multiplier import Multiplier
16
+
17
+
18
+ # TESTS ================================================================================
19
+
20
+ class TestMultiplier(unittest.TestCase):
21
+ """
22
+ Test the implementation of the 'Multiplier' block class
23
+ """
24
+
25
+ def test_str(self):
26
+
27
+ M = Multiplier()
28
+
29
+ #test default str method
30
+ self.assertEqual(str(M), "Multiplier")
31
+
32
+
33
+ def test_update_single(self):
34
+
35
+ M = Multiplier()
36
+
37
+ #set block inputs
38
+ M.set(0, 1)
39
+
40
+ #update block
41
+ err = M.update(None)
42
+
43
+ #test if update was correct
44
+ self.assertEqual(M.get(0), 1)
45
+
46
+ #test if error was computed correctly
47
+ self.assertGreater(err, 0)
48
+
49
+ #update block again
50
+ err = M.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
+ M = Multiplier()
59
+
60
+ #set block inputs
61
+ M.set(0, 1)
62
+ M.set(1, 2.0)
63
+ M.set(2, 3.1)
64
+
65
+ #update block
66
+ err = M.update(None)
67
+
68
+ #test if update was correct
69
+ self.assertEqual(M.get(0), 6.2)
70
+
71
+ #test if error was computed correctly
72
+ self.assertGreater(err, 0)
73
+
74
+ #update block again
75
+ err = M.update(None)
76
+
77
+ #test error, now should be 0
78
+ self.assertEqual(err, 0)
79
+
80
+
81
+
82
+
83
+
84
+ # RUN TESTS LOCALLY ====================================================================
85
+
86
+ if __name__ == '__main__':
87
+ unittest.main(verbosity=2)
@@ -0,0 +1,125 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.ode.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.ode import ODE
16
+
17
+ #base solver for testing
18
+ from pathsim.solvers._solver import Solver
19
+
20
+
21
+ # TESTS ================================================================================
22
+
23
+ class TestODE(unittest.TestCase):
24
+ """
25
+ Test the implementation of the 'ODE' block class
26
+ """
27
+
28
+ def test_init(self):
29
+
30
+ #test default initialization
31
+ D = ODE()
32
+
33
+ self.assertEqual(D.engine, None)
34
+ self.assertEqual(D.jac, None)
35
+ self.assertEqual(D.initial_value, 0.0)
36
+
37
+ #test special initialization
38
+ def f(x, u, t):
39
+ return -x**2
40
+ def j(x, u, t):
41
+ return -2*x
42
+
43
+ D = ODE(func=f, initial_value=1.0, jac=j)
44
+
45
+ #test that ode function is correctly assigned
46
+ self.assertEqual(D.func(1, 0, 0), f(1, 0, 0))
47
+ self.assertEqual(D.func(2, 0, 0), f(2, 0, 0))
48
+ self.assertEqual(D.func(3, 0, 0), f(3, 0, 0))
49
+
50
+ #test that ode jacobian is correctly assigned
51
+ self.assertEqual(D.jac(1, 0, 0), j(1, 0, 0))
52
+ self.assertEqual(D.jac(2, 0, 0), j(2, 0, 0))
53
+ self.assertEqual(D.jac(3, 0, 0), j(3, 0, 0))
54
+
55
+ self.assertEqual(D.initial_value, 1.0)
56
+
57
+
58
+ def test_len(self):
59
+
60
+ D = ODE()
61
+
62
+ #has direct passthrough
63
+ self.assertEqual(len(D), 0)
64
+
65
+
66
+ def test_str(self):
67
+
68
+ D = ODE()
69
+
70
+ #test default str method
71
+ self.assertEqual(str(D), "ODE")
72
+
73
+
74
+ def test_set_solver(self):
75
+
76
+ def f(x, u, t):
77
+ return -x**2
78
+ def j(x, u, t):
79
+ return -2*x
80
+
81
+ D = ODE(func=f, initial_value=1.0, jac=j)
82
+
83
+ #test that no solver is initialized
84
+ self.assertEqual(D.engine, None)
85
+
86
+ D.set_solver(Solver, tolerance_lte=1e-6)
87
+
88
+ #test that solver is now available
89
+ self.assertTrue(isinstance(D.engine, Solver))
90
+ self.assertEqual(D.engine.tolerance_lte, 1e-6)
91
+
92
+ #test that solver function is correctly assigned
93
+ self.assertEqual(D.engine.func(1, 0, 0), f(1, 0, 0))
94
+ self.assertEqual(D.engine.func(2, 0, 0), f(2, 0, 0))
95
+ self.assertEqual(D.engine.func(3, 0, 0), f(3, 0, 0))
96
+
97
+ #test that solver jacobian is correctly assigned
98
+ self.assertEqual(D.engine.jac(1, 0, 0), j(1, 0, 0))
99
+ self.assertEqual(D.engine.jac(2, 0, 0), j(2, 0, 0))
100
+ self.assertEqual(D.engine.jac(3, 0, 0), j(3, 0, 0))
101
+
102
+ D.set_solver(Solver, tolerance_lte=1e-3)
103
+
104
+ #test that solver tolerance is changed
105
+ self.assertEqual(D.engine.tolerance_lte, 1e-3)
106
+
107
+
108
+ def test_update(self):
109
+
110
+ D = ODE()
111
+ D.set_solver(Solver)
112
+
113
+ err = D.update(0)
114
+
115
+ #test if error is correctly 0
116
+ self.assertEqual(err, 0.0)
117
+
118
+ #test if engine state is retrieved correctly
119
+ self.assertEqual(D.get(0), 0.0)
120
+
121
+
122
+ # RUN TESTS LOCALLY ====================================================================
123
+
124
+ if __name__ == '__main__':
125
+ unittest.main(verbosity=2)
@@ -0,0 +1,109 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.rng.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.rng import RNG
16
+
17
+
18
+ # TESTS ================================================================================
19
+
20
+ class TestRNG(unittest.TestCase):
21
+ """
22
+ Test the implementation of the 'RNG' block class
23
+ """
24
+
25
+ def test_init(self):
26
+
27
+ R = RNG()
28
+
29
+ self.assertEqual(R.sampling_rate, None)
30
+
31
+ R = RNG(sampling_rate=1)
32
+
33
+ self.assertEqual(R.n_samples, 0)
34
+ self.assertEqual(R.sampling_rate, 1)
35
+
36
+
37
+ def test_len(self):
38
+
39
+ R = RNG()
40
+
41
+ #no passthrough
42
+ self.assertEqual(len(R), 0)
43
+
44
+
45
+ def test_str(self):
46
+
47
+ R = RNG()
48
+
49
+ #test default str method
50
+ self.assertEqual(str(R), "RNG")
51
+
52
+
53
+ def test_reset(self):
54
+
55
+ R = RNG()
56
+
57
+ for t in range(10):
58
+ R.sample(t)
59
+
60
+ R.reset()
61
+
62
+ #test if reset worked
63
+ self.assertEqual(R.n_samples, 0)
64
+ self.assertEqual(R.get(0), 0.0)
65
+
66
+
67
+ def test_sample(self):
68
+
69
+ #first test default 'sampling_rate=None'
70
+ R = RNG()
71
+
72
+ for t in range(10):
73
+
74
+ #test sample counter
75
+ self.assertEqual(R.n_samples, t)
76
+
77
+ old = R.get(0)
78
+
79
+ R.sample(t)
80
+
81
+ #test if new random value is sampled
82
+ self.assertNotEqual(old, R.get(0))
83
+
84
+
85
+ #next test finite sampling rate (samples every two seconds)
86
+ R = RNG(sampling_rate=0.5)
87
+
88
+ for t in range(10):
89
+
90
+ #test sample counter
91
+ self.assertEqual(R.n_samples, t//2)
92
+
93
+ old = R.get(0)
94
+
95
+ R.sample(t)
96
+
97
+ if t%2 == 0:
98
+ #test if value remains the same is sampled
99
+ self.assertEqual(old, R.get(0))
100
+
101
+ else:
102
+ #test if new random value is sampled
103
+ self.assertNotEqual(old, R.get(0))
104
+
105
+
106
+ # RUN TESTS LOCALLY ====================================================================
107
+
108
+ if __name__ == '__main__':
109
+ unittest.main(verbosity=2)
@@ -0,0 +1,196 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'blocks.scope.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.scope import Scope, RealtimeScope
16
+
17
+
18
+ # TESTS ================================================================================
19
+
20
+ class TestScope(unittest.TestCase):
21
+ """
22
+ Test the implementation of the 'Scope' block class
23
+ """
24
+
25
+ def test_init(self):
26
+
27
+ #test default initialization
28
+ S = Scope()
29
+
30
+ self.assertEqual(S.sampling_rate, None)
31
+ self.assertEqual(S.t_wait, 0.0)
32
+ self.assertEqual(S.labels, [])
33
+ self.assertEqual(S.recording, {})
34
+
35
+ #test specific initialization
36
+ S = Scope(sampling_rate=1, t_wait=1.0, labels=["1", "2"])
37
+
38
+ self.assertEqual(S.sampling_rate, 1)
39
+ self.assertEqual(S.t_wait, 1.0)
40
+ self.assertEqual(S.labels, ["1", "2"])
41
+
42
+
43
+ def test_len(self):
44
+
45
+ S = Scope()
46
+
47
+ #no passthrough
48
+ self.assertEqual(len(S), 0)
49
+
50
+
51
+ def test_str(self):
52
+
53
+ S = Scope()
54
+
55
+ #test default str method
56
+ self.assertEqual(str(S), "Scope")
57
+
58
+
59
+ def test_reset(self):
60
+
61
+ S = Scope()
62
+
63
+ for t in range(10):
64
+
65
+ S.set(0, t)
66
+ S.sample(t)
67
+
68
+ #test that we have some recording
69
+ self.assertGreater(len(S.recording), 0)
70
+
71
+ S.reset()
72
+
73
+ #test if reset was successful
74
+ self.assertEqual(S.recording, {})
75
+
76
+
77
+ def test_sample(self):
78
+
79
+ #single input default initialization
80
+ S = Scope()
81
+
82
+ for t in range(10):
83
+
84
+ S.set(0, t)
85
+ S.sample(t)
86
+
87
+ #test most recent recording
88
+ self.assertEqual(S.recording[t], t)
89
+
90
+ #multi input default initialization
91
+ S = Scope()
92
+
93
+ for t in range(10):
94
+
95
+ S.set(0, t)
96
+ S.set(1, 2*t)
97
+ S.set(2, 3*t)
98
+ S.sample(t)
99
+
100
+ #test most recent recording
101
+ self.assertTrue(np.all(np.equal(S.recording[t], [t, 2*t, 3*t])))
102
+
103
+
104
+ def test_read(self):
105
+
106
+ _time = np.arange(10)
107
+
108
+ #single input default initialization
109
+ S = Scope()
110
+
111
+ for t in _time:
112
+
113
+ S.set(0, t)
114
+ S.sample(t)
115
+
116
+ time, result = S.read()
117
+
118
+ #test if time was recorded correctly
119
+ self.assertTrue(np.all(np.equal(time, _time)))
120
+
121
+ #test if input was recorded correctly
122
+ self.assertTrue(np.all(np.equal(result, _time)))
123
+
124
+ #multi input default initialization
125
+ S = Scope()
126
+
127
+ for t in _time:
128
+
129
+ S.set(0, t)
130
+ S.set(1, 2*t)
131
+ S.set(2, 3*t)
132
+ S.sample(t)
133
+
134
+ time, result = S.read()
135
+
136
+ #test if time was recorded correctly
137
+ self.assertTrue(np.all(np.equal(time, _time)))
138
+
139
+ #test if multi input was recorded correctly
140
+ self.assertTrue(np.all(np.equal(result, [_time, 2*_time, 3*_time])))
141
+
142
+
143
+ def test_sampling_rate(self):
144
+
145
+ _time = np.arange(10)
146
+
147
+ #single input special sampling rate
148
+ S = Scope(sampling_rate=0.5)
149
+
150
+ for t in _time:
151
+
152
+ S.set(0, t)
153
+ S.sample(t)
154
+
155
+ time, result = S.read()
156
+
157
+ #test if time was recorded correctly
158
+ self.assertTrue(np.all(np.equal(time, _time[1::2])))
159
+
160
+ #test if input was recorded correctly
161
+ self.assertTrue(np.all(np.equal(result, _time[1::2])))
162
+
163
+
164
+ def test_t_wait(self):
165
+
166
+ _time = np.arange(10)
167
+
168
+ #single input special t_wait
169
+ S = Scope(t_wait=5)
170
+
171
+ for t in _time:
172
+
173
+ S.set(0, t)
174
+ S.sample(t)
175
+
176
+ time, result = S.read()
177
+
178
+ #test if time was recorded correctly
179
+ self.assertTrue(np.all(np.equal(time, _time[5:])))
180
+
181
+ #test if input was recorded correctly
182
+ self.assertTrue(np.all(np.equal(result, _time[5:])))
183
+
184
+
185
+ class TestRealtimeScope(unittest.TestCase):
186
+ """
187
+ Test the implementation of the 'RealtimeScope' block class
188
+ """
189
+
190
+ pass #no tests implemented yet, since it just inherits from 'Scope' and is not critical
191
+
192
+
193
+ # RUN TESTS LOCALLY ====================================================================
194
+
195
+ if __name__ == '__main__':
196
+ unittest.main(verbosity=2)