@@ -193,6 +193,35 @@ def pole_cancellation(self):
193
193
def no_pole_cancellation (self ):
194
194
return TransferFunction ([1.881e+06 ],
195
195
[188.1 , 1.881e+06 ])
196
+
197
+ @pytest .fixture
198
+ def siso_tf_type1 (self ):
199
+ # System Type 1 - Step response not stationary: G(s)=1/s(s+1)
200
+ return TransferFunction (1 , [1 , 1 , 0 ])
201
+
202
+ @pytest .fixture
203
+ def siso_tf_kpos (self ):
204
+ # SISO under shoot response and positive final value G(s)=(-s+1)/(s²+s+1)
205
+ return TransferFunction ([- 1 , 1 ], [1 , 1 , 1 ])
206
+
207
+ @pytest .fixture
208
+ def siso_tf_kneg (self ):
209
+ # SISO under shoot response and negative final value k=-1 G(s)=-(-s+1)/(s²+s+1)
210
+ return TransferFunction ([1 , - 1 ], [1 , 1 , 1 ])
211
+
212
+ @pytest .fixture
213
+ def tf1_matlab_help (self ):
214
+ # example from matlab online help https://www.mathworks.com/help/control/ref/stepinfo.html
215
+ return TransferFunction ([1 , 5 , 5 ], [1 , 1.65 , 5 , 6.5 , 2 ])
216
+
217
+ @pytest .fixture
218
+ def tf2_matlab_help (self ):
219
+ A = [[0.68 , - 0.34 ], [0.34 , 0.68 ]]
220
+ B = [[0.18 ], [0.04 ]]
221
+ C = [- 1.12 , - 1.10 ]
222
+ D = [0.06 ]
223
+ sys = StateSpace (A , B , C , D , 0.2 )
224
+ return sys
196
225
197
226
@pytest .fixture
198
227
def tsystem (self ,
@@ -202,7 +231,9 @@ def tsystem(self,
202
231
siso_dtf0 , siso_dtf1 , siso_dtf2 ,
203
232
siso_dss1 , siso_dss2 ,
204
233
mimo_dss1 , mimo_dss2 , mimo_dtf1 ,
205
- pole_cancellation , no_pole_cancellation ):
234
+ pole_cancellation , no_pole_cancellation , siso_tf_type1 ,
235
+ siso_tf_kpos , siso_tf_kneg , tf1_matlab_help ,
236
+ tf2_matlab_help ):
206
237
systems = {"siso_ss1" : siso_ss1 ,
207
238
"siso_ss2" : siso_ss2 ,
208
239
"siso_tf1" : siso_tf1 ,
@@ -220,6 +251,11 @@ def tsystem(self,
220
251
"mimo_dtf1" : mimo_dtf1 ,
221
252
"pole_cancellation" : pole_cancellation ,
222
253
"no_pole_cancellation" : no_pole_cancellation ,
254
+ "siso_tf_type1" : siso_tf_type1 ,
255
+ "siso_tf_kpos" : siso_tf_kpos ,
256
+ "siso_tf_kneg" : siso_tf_kneg ,
257
+ "tf1_matlab_help" : tf1_matlab_help ,
258
+ "tf2_matlab_help" : tf2_matlab_help ,
223
259
}
224
260
return systems [request .param ]
225
261
@@ -303,6 +339,73 @@ def test_step_info(self):
303
339
[Strue [k ] for k in Sktrue ],
304
340
rtol = rtol )
305
341
342
+ # tolerance for all parameters could be wrong for some systems
343
+ # discrete systems time parameters tolerance could be +/-dt
344
+ @pytest .mark .parametrize (
345
+ "tsystem, info_true, tolerance" ,
346
+ [("tf1_matlab_help" , {
347
+ 'RiseTime' : 3.8456 ,
348
+ 'SettlingTime' : 27.9762 ,
349
+ 'SettlingMin' : 2.0689 ,
350
+ 'SettlingMax' : 2.6873 ,
351
+ 'Overshoot' : 7.4915 ,
352
+ 'Undershoot' : 0 ,
353
+ 'Peak' : 2.6873 ,
354
+ 'PeakTime' : 8.0530 ,
355
+ 'SteadyStateValue' : 2.5 }, 2e-2 ),
356
+ ("tf2_matlab_help" , {
357
+ 'RiseTime' : 0.4000 ,
358
+ 'SettlingTime' : 2.8000 ,
359
+ 'SettlingMin' : - 0.6724 ,
360
+ 'SettlingMax' : - 0.5188 ,
361
+ 'Overshoot' : 24.6476 ,
362
+ 'Undershoot' : 11.1224 ,
363
+ 'Peak' : 0.6724 ,
364
+ 'PeakTime' : 1 ,
365
+ 'SteadyStateValue' : - 0.5394 }, .2 ),
366
+ ("siso_tf_kpos" , {
367
+ 'RiseTime' : 1.242 ,
368
+ 'SettlingTime' : 9.110 ,
369
+ 'SettlingMin' : 0.950 ,
370
+ 'SettlingMax' : 1.208 ,
371
+ 'Overshoot' : 20.840 ,
372
+ 'Undershoot' : 27.840 ,
373
+ 'Peak' : 1.208 ,
374
+ 'PeakTime' : 4.282 ,
375
+ 'SteadyStateValue' : 1.0 }, 2e-2 ),
376
+ ("siso_tf_kneg" , {
377
+ 'RiseTime' : 1.242 ,
378
+ 'SettlingTime' : 9.110 ,
379
+ 'SettlingMin' : - 1.208 ,
380
+ 'SettlingMax' : - 0.950 ,
381
+ 'Overshoot' : 20.840 ,
382
+ 'Undershoot' : 27.840 ,
383
+ 'Peak' : 1.208 ,
384
+ 'PeakTime' : 4.282 ,
385
+ 'SteadyStateValue' : - 1.0 }, 2e-2 ),
386
+ ("siso_tf_type1" , {'RiseTime' : np .NaN ,
387
+ 'SettlingTime' : np .NaN ,
388
+ 'SettlingMin' : np .NaN ,
389
+ 'SettlingMax' : np .NaN ,
390
+ 'Overshoot' : np .NaN ,
391
+ 'Undershoot' : np .NaN ,
392
+ 'Peak' : np .Inf ,
393
+ 'PeakTime' : np .Inf ,
394
+ 'SteadyStateValue' : np .NaN }, 2e-2 )],
395
+ indirect = ["tsystem" ])
396
+ def test_step_info (self , tsystem , info_true , tolerance ):
397
+ """ """
398
+ info = step_info (tsystem )
399
+
400
+ info_true_sorted = sorted (info_true .keys ())
401
+ info_sorted = sorted (info .keys ())
402
+
403
+ assert info_sorted == info_true_sorted
404
+
405
+ np .testing .assert_allclose ([info_true [k ] for k in info_true_sorted ],
406
+ [info [k ] for k in info_sorted ],
407
+ rtol = tolerance )
408
+
306
409
def test_step_pole_cancellation (self , pole_cancellation ,
307
410
no_pole_cancellation ):
308
411
# confirm that pole-zero cancellation doesn't perturb results
0 commit comments