@@ -13,18 +13,18 @@ def check_LQE(L, P, poles, G, QN, RN):
1313 P_expected = asmatarrayout (np .sqrt (G @ QN @ G @ RN ))
1414 L_expected = asmatarrayout (P_expected / RN )
1515 poles_expected = - np .squeeze (np .asarray (L_expected ))
16- np .testing .assert_array_almost_equal (P , P_expected )
17- np .testing .assert_array_almost_equal (L , L_expected )
18- np .testing .assert_array_almost_equal (poles , poles_expected )
16+ np .testing .assert_almost_equal (P , P_expected )
17+ np .testing .assert_almost_equal (L , L_expected )
18+ np .testing .assert_almost_equal (poles , poles_expected )
1919
2020# Utility function to check discrete LQE solutions
2121def check_DLQE (L , P , poles , G , QN , RN ):
2222 P_expected = asmatarrayout (G .dot (QN ).dot (G ))
2323 L_expected = asmatarrayout (0 )
2424 poles_expected = - np .squeeze (np .asarray (L_expected ))
25- np .testing .assert_array_almost_equal (P , P_expected )
26- np .testing .assert_array_almost_equal (L , L_expected )
27- np .testing .assert_array_almost_equal (poles , poles_expected )
25+ np .testing .assert_almost_equal (P , P_expected )
26+ np .testing .assert_almost_equal (L , L_expected )
27+ np .testing .assert_almost_equal (poles , poles_expected )
2828
2929@pytest .mark .parametrize ("method" , [None , 'slycot' , 'scipy' ])
3030def test_LQE (matarrayin , method ):
@@ -51,9 +51,9 @@ def test_lqe_call_format(cdlqe):
5151
5252 # Call with system instead of matricees
5353 L , P , E = cdlqe (sys , Q , R )
54- np .testing .assert_array_almost_equal (Lref , L )
55- np .testing .assert_array_almost_equal (Pref , P )
56- np .testing .assert_array_almost_equal (Eref , E )
54+ np .testing .assert_almost_equal (Lref , L )
55+ np .testing .assert_almost_equal (Pref , P )
56+ np .testing .assert_almost_equal (Eref , E )
5757
5858 # Make sure we get an error if we specify N
5959 with pytest .raises (ct .ControlNotImplemented ):
@@ -156,10 +156,10 @@ def test_estimator_iosys():
156156 # Check to make sure everything matches
157157 cls = clsys .linearize (0 , 0 )
158158 nstates = sys .nstates
159- np .testing .assert_array_almost_equal (cls .A [:2 * nstates , :2 * nstates ], A_clchk )
160- np .testing .assert_array_almost_equal (cls .B [:2 * nstates , :], B_clchk )
161- np .testing .assert_array_almost_equal (cls .C [:, :2 * nstates ], C_clchk )
162- np .testing .assert_array_almost_equal (cls .D , D_clchk )
159+ np .testing .assert_almost_equal (cls .A [:2 * nstates , :2 * nstates ], A_clchk )
160+ np .testing .assert_almost_equal (cls .B [:2 * nstates , :], B_clchk )
161+ np .testing .assert_almost_equal (cls .C [:, :2 * nstates ], C_clchk )
162+ np .testing .assert_almost_equal (cls .D , D_clchk )
163163
164164
165165def test_estimator_errors ():
@@ -185,3 +185,78 @@ def test_estimator_errors():
185185 sys_fs .C = np .eye (4 )
186186 C = np .eye (1 , 4 )
187187 estim = ct .create_estimator_iosystem (sys_fs , QN , RN , C = C )
188+
189+
190+ def test_white_noise ():
191+ # Scalar white noise signal
192+ T = np .linspace (0 , 1000 , 1000 )
193+ R = 0.5
194+ V = ct .white_noise (T , R )
195+ assert abs (np .mean (V )) < 0.1 # can occassionally fail
196+ assert abs (np .cov (V ) - 0.5 ) < 0.1 # can occassionally fail
197+
198+ # Vector white noise signal
199+ R = [[0.5 , 0 ], [0 , 0.1 ]]
200+ V = ct .white_noise (T , R )
201+ assert abs (np .mean (V )) < 0.1 # can occassionally fail
202+ assert np .all (abs (np .cov (V ) - R ) < 0.1 ) # can occassionally fail
203+
204+ # Make sure time scaling works properly
205+ T = T / 10
206+ V = ct .white_noise (T , R )
207+ assert abs (np .mean (V )) < np .sqrt (10 ) # can occassionally fail
208+ assert np .all (abs (np .cov (V ) - R ) < 10 ) # can occassionally fail
209+
210+ # Make sure discrete time works properly
211+ V = ct .white_noise (T , R , dt = T [1 ] - T [0 ])
212+ assert abs (np .mean (V )) < 0.1 # can occassionally fail
213+ assert np .all (abs (np .cov (V ) - R ) < 0.1 ) # can occassionally fail
214+
215+ # Test error conditions
216+ with pytest .raises (ValueError , match = "T must be 1D" ):
217+ V = ct .white_noise (R , R )
218+
219+ with pytest .raises (ValueError , match = "Q must be square" ):
220+ R = np .outer (np .eye (2 , 3 ), np .ones_like (T ))
221+ V = ct .white_noise (T , R )
222+
223+ with pytest .raises (ValueError , match = "Time values must be equally" ):
224+ T = np .logspace (0 , 2 , 100 )
225+ R = [[0.5 , 0 ], [0 , 0.1 ]]
226+ V = ct .white_noise (T , R )
227+
228+
229+ def test_correlation ():
230+ # Create an uncorrelated random sigmal
231+ T = np .linspace (0 , 1000 , 1000 )
232+ R = 0.5
233+ V = ct .white_noise (T , R )
234+
235+ # Compute the correlation
236+ tau , Rtau = ct .correlation (T , V )
237+
238+ # Make sure the correlation makes sense
239+ zero_index = np .where (tau == 0 )
240+ np .testing .assert_almost_equal (Rtau [zero_index ], np .cov (V ), decimal = 2 )
241+ for i , t in enumerate (tau ):
242+ if i == zero_index :
243+ continue
244+ assert abs (Rtau [i ]) < 0.01
245+
246+ # Try passing a second argument
247+ tau , Rneg = ct .correlation (T , V , - V )
248+ np .testing .assert_equal (Rtau , - Rneg )
249+
250+ # Test error conditions
251+ with pytest .raises (ValueError , match = "Time vector T must be 1D" ):
252+ tau , Rtau = ct .correlation (V , V )
253+
254+ with pytest .raises (ValueError , match = "X and Y must be 2D" ):
255+ tau , Rtau = ct .correlation (T , np .zeros ((3 , T .size , 2 )))
256+
257+ with pytest .raises (ValueError , match = "X and Y must have same length as T" ):
258+ tau , Rtau = ct .correlation (T , V [:, 0 :- 1 ])
259+
260+ with pytest .raises (ValueError , match = "Time values must be equally" ):
261+ T = np .logspace (0 , 2 , T .size )
262+ tau , Rtau = ct .correlation (T , V )
0 commit comments