Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit258c9c2

Browse files
authored
Merge pull request#567 from juanodecc/step_info_improve_jpp
Step info improve jpp
2 parents0f951e1 +81ae64f commit258c9c2

File tree

2 files changed

+172
-29
lines changed

2 files changed

+172
-29
lines changed

‎control/tests/timeresp_test.py

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,35 @@ def pole_cancellation(self):
193193
defno_pole_cancellation(self):
194194
returnTransferFunction([1.881e+06],
195195
[188.1,1.881e+06])
196+
197+
@pytest.fixture
198+
defsiso_tf_type1(self):
199+
# System Type 1 - Step response not stationary: G(s)=1/s(s+1)
200+
returnTransferFunction(1, [1,1,0])
201+
202+
@pytest.fixture
203+
defsiso_tf_kpos(self):
204+
# SISO under shoot response and positive final value G(s)=(-s+1)/(s²+s+1)
205+
returnTransferFunction([-1,1], [1,1,1])
206+
207+
@pytest.fixture
208+
defsiso_tf_kneg(self):
209+
# SISO under shoot response and negative final value k=-1 G(s)=-(-s+1)/(s²+s+1)
210+
returnTransferFunction([1,-1], [1,1,1])
211+
212+
@pytest.fixture
213+
deftf1_matlab_help(self):
214+
# example from matlab online help https://www.mathworks.com/help/control/ref/stepinfo.html
215+
returnTransferFunction([1,5,5], [1,1.65,5,6.5,2])
216+
217+
@pytest.fixture
218+
deftf2_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+
returnsys
196225

197226
@pytest.fixture
198227
deftsystem(self,
@@ -202,7 +231,9 @@ def tsystem(self,
202231
siso_dtf0,siso_dtf1,siso_dtf2,
203232
siso_dss1,siso_dss2,
204233
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):
206237
systems= {"siso_ss1":siso_ss1,
207238
"siso_ss2":siso_ss2,
208239
"siso_tf1":siso_tf1,
@@ -220,6 +251,11 @@ def tsystem(self,
220251
"mimo_dtf1":mimo_dtf1,
221252
"pole_cancellation":pole_cancellation,
222253
"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,
223259
}
224260
returnsystems[request.param]
225261

@@ -303,6 +339,73 @@ def test_step_info(self):
303339
[Strue[k]forkinSktrue],
304340
rtol=rtol)
305341

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+
deftest_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+
assertinfo_sorted==info_true_sorted
404+
405+
np.testing.assert_allclose([info_true[k]forkininfo_true_sorted],
406+
[info[k]forkininfo_sorted],
407+
rtol=tolerance)
408+
306409
deftest_step_pole_cancellation(self,pole_cancellation,
307410
no_pole_cancellation):
308411
# confirm that pole-zero cancellation doesn't perturb results

‎control/timeresp.py

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,8 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
746746
747747
Parameters
748748
----------
749-
sys : StateSpace or TransferFunction
749+
sys : SISO dynamic system model. Dynamic systems that you can use include:
750+
StateSpace or TransferFunction
750751
LTI system to simulate
751752
752753
T : array_like or float, optional
@@ -785,43 +786,82 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
785786
--------
786787
>>> info = step_info(sys, T)
787788
'''
788-
_,sys=_get_ss_simo(sys)
789+
790+
ifnotsys.issiso():
791+
sys=_mimo2siso(sys,0,0)
792+
warnings.warn(" Internal conversion from a MIMO system to a SISO system,"
793+
" the first input and the first output were used (u1 -> y1);"
794+
" it may not be the result you are looking for")
795+
789796
ifTisNoneornp.asarray(T).size==1:
790797
T=_default_time_vector(sys,N=T_num,tfinal=T,is_step=True)
791798

792799
T,yout=step_response(sys,T)
793800

794801
# Steady state value
795-
InfValue=sys.dcgain()
796-
797-
# RiseTime
798-
tr_lower_index= (np.where(yout>=RiseTimeLimits[0]*InfValue)[0])[0]
799-
tr_upper_index= (np.where(yout>=RiseTimeLimits[1]*InfValue)[0])[0]
800-
RiseTime=T[tr_upper_index]-T[tr_lower_index]
801-
802-
# SettlingTime
803-
sup_margin= (1.+SettlingTimeThreshold)*InfValue
804-
inf_margin= (1.-SettlingTimeThreshold)*InfValue
805-
# find Steady State looking for the first point out of specified limits
806-
foriinreversed(range(T.size)):
807-
if((yout[i]<=inf_margin)| (yout[i]>=sup_margin)):
808-
SettlingTime=T[i+1]
809-
break
802+
InfValue=sys.dcgain().real
803+
804+
# TODO: this could be a function step_info4data(t,y,yfinal)
805+
rise_time:float=np.NaN
806+
settling_time:float=np.NaN
807+
settling_min:float=np.NaN
808+
settling_max:float=np.NaN
809+
peak_value:float=np.Inf
810+
peak_time:float=np.Inf
811+
undershoot:float=np.NaN
812+
overshoot:float=np.NaN
813+
steady_state_value:float=np.NaN
814+
815+
ifnotnp.isnan(InfValue)andnotnp.isinf(InfValue):
816+
# SteadyStateValue
817+
steady_state_value=InfValue
818+
# Peak
819+
peak_index=np.abs(yout).argmax()
820+
peak_value=np.abs(yout[peak_index])
821+
peak_time=T[peak_index]
822+
823+
sup_margin= (1.+SettlingTimeThreshold)*InfValue
824+
inf_margin= (1.-SettlingTimeThreshold)*InfValue
825+
826+
# RiseTime
827+
tr_lower_index= (np.where(np.sign(InfValue.real)* (yout-RiseTimeLimits[0]*InfValue)>=0 )[0])[0]
828+
tr_upper_index= (np.where(np.sign(InfValue.real)*yout>=np.sign(InfValue.real)*RiseTimeLimits[1]*InfValue)[0])[0]
829+
830+
# SettlingTime
831+
settling_time=T[np.where(np.abs(yout-InfValue)>=np.abs(SettlingTimeThreshold*InfValue))[0][-1]+1]
832+
# Overshoot and Undershoot
833+
y_os= (np.sign(InfValue.real)*yout).max()
834+
dy_os=np.abs(y_os)-np.abs(InfValue)
835+
ifdy_os>0:
836+
overshoot=np.abs(100.*dy_os/InfValue)
837+
else:
838+
overshoot=0
839+
840+
y_us= (np.sign(InfValue.real)*yout).min()
841+
dy_us=np.abs(y_us)
842+
ifdy_us>0:
843+
undershoot=np.abs(100.*dy_us/InfValue)
844+
else:
845+
undershoot=0
846+
847+
# RiseTime
848+
rise_time=T[tr_upper_index]-T[tr_lower_index]
849+
850+
settling_max= (yout[tr_upper_index:]).max()
851+
settling_min= (yout[tr_upper_index:]).min()
810852

811-
PeakIndex=np.abs(yout).argmax()
812853
return {
813-
'RiseTime':RiseTime,
814-
'SettlingTime':SettlingTime,
815-
'SettlingMin':yout[tr_upper_index:].min(),
816-
'SettlingMax':yout.max(),
817-
'Overshoot':100.* (yout.max()-InfValue)/InfValue,
818-
'Undershoot':yout.min(),# not very confident about this
819-
'Peak':yout[PeakIndex],
820-
'PeakTime':T[PeakIndex],
821-
'SteadyStateValue':InfValue
854+
'RiseTime':rise_time,
855+
'SettlingTime':settling_time,
856+
'SettlingMin':settling_min,
857+
'SettlingMax':settling_max,
858+
'Overshoot':overshoot,
859+
'Undershoot':undershoot,
860+
'Peak':peak_value,
861+
'PeakTime':peak_time,
862+
'SteadyStateValue':steady_state_value
822863
}
823864

824-
825865
definitial_response(sys,T=None,X0=0.,input=0,output=None,T_num=None,
826866
transpose=False,return_x=False,squeeze=None):
827867
# pylint: disable=W0622

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp