61
61
Initial Author: Eike Welk
62
62
Date: 12 May 2011
63
63
64
- Modified: Sawyer B. Fuller (minster@uw.edu) to add discrete-time
64
+ Modified: Sawyer B. Fuller (minster@uw.edu) to add discrete-time
65
65
capability and better automatic time vector creation
66
66
Date: June 2020
67
67
@@ -463,14 +463,14 @@ def step_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
463
463
LTI system to simulate
464
464
465
465
T: array-like or number, optional
466
- Time vector, or simulation time duration if a number. If T is not
467
- provided, an attempt is made to create it automatically from the
468
- dynamics of sys. If sys is continuous-time, the time increment dt
469
- is chosen small enough to show the fastest mode, and the simulation
470
- time period tfinal long enough to show the slowest mode, excluding
466
+ Time vector, or simulation time duration if a number. If T is not
467
+ provided, an attempt is made to create it automatically from the
468
+ dynamics of sys. If sys is continuous-time, the time increment dt
469
+ is chosen small enough to show the fastest mode, and the simulation
470
+ time period tfinal long enough to show the slowest mode, excluding
471
471
poles at the origin. If this results in too many time steps (>5000),
472
- dt is reduced. If sys is discrete-time, only tfinal is computed, and
473
- tfinal is reduced if it requires too many simulation steps.
472
+ dt is reduced. If sys is discrete-time, only tfinal is computed, and
473
+ tfinal is reduced if it requires too many simulation steps.
474
474
475
475
X0: array-like or number, optional
476
476
Initial condition (default = 0)
@@ -483,10 +483,10 @@ def step_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
483
483
output: int
484
484
Index of the output that will be used in this simulation. Set to None
485
485
to not trim outputs
486
-
486
+
487
487
T_num: number, optional
488
- Number of time steps to use in simulation if T is not provided as an
489
- array (autocomputed if not given); ignored if sys is discrete-time.
488
+ Number of time steps to use in simulation if T is not provided as an
489
+ array (autocomputed if not given); ignored if sys is discrete-time.
490
490
491
491
transpose: bool
492
492
If True, transpose all input and output arrays (for backward
@@ -550,12 +550,12 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
550
550
LTI system to simulate
551
551
552
552
T: array-like or number, optional
553
- Time vector, or simulation time duration if a number (time vector is
553
+ Time vector, or simulation time duration if a number (time vector is
554
554
autocomputed if not given, see :func:`step_response` for more detail)
555
555
556
556
T_num: number, optional
557
- Number of time steps to use in simulation if T is not provided as an
558
- array (autocomputed if not given); ignored if sys is discrete-time.
557
+ Number of time steps to use in simulation if T is not provided as an
558
+ array (autocomputed if not given); ignored if sys is discrete-time.
559
559
560
560
SettlingTimeThreshold: float value, optional
561
561
Defines the error to compute settling time (default = 0.02)
@@ -588,7 +588,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
588
588
sys = _get_ss_simo (sys )
589
589
if T is None or np .asarray (T ).size == 1 :
590
590
T = _default_time_vector (sys ,N = T_num ,tfinal = T )
591
-
591
+
592
592
T ,yout = step_response (sys ,T )
593
593
594
594
# Steady state value
@@ -640,7 +640,7 @@ def initial_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
640
640
LTI system to simulate
641
641
642
642
T: array-like or number, optional
643
- Time vector, or simulation time duration if a number (time vector is
643
+ Time vector, or simulation time duration if a number (time vector is
644
644
autocomputed if not given; see :func:`step_response` for more detail)
645
645
646
646
X0: array-like or number, optional
@@ -655,10 +655,10 @@ def initial_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
655
655
output: int
656
656
Index of the output that will be used in this simulation. Set to None
657
657
to not trim outputs
658
-
658
+
659
659
T_num: number, optional
660
- Number of time steps to use in simulation if T is not provided as an
661
- array (autocomputed if not given); ignored if sys is discrete-time.
660
+ Number of time steps to use in simulation if T is not provided as an
661
+ array (autocomputed if not given); ignored if sys is discrete-time.
662
662
663
663
transpose: bool
664
664
If True, transpose all input and output arrays (for backward
@@ -730,7 +730,7 @@ def impulse_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
730
730
LTI system to simulate
731
731
732
732
T: array-like or number, optional
733
- Time vector, or simulation time duration if a number (time vector is
733
+ Time vector, or simulation time duration if a number (time vector is
734
734
autocomputed if not given; see :func:`step_response` for more detail)
735
735
736
736
X0: array-like or number, optional
@@ -746,8 +746,8 @@ def impulse_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
746
746
to not trim outputs
747
747
748
748
T_num: number, optional
749
- Number of time steps to use in simulation if T is not provided as an
750
- array (autocomputed if not given); ignored if sys is discrete-time.
749
+ Number of time steps to use in simulation if T is not provided as an
750
+ array (autocomputed if not given); ignored if sys is discrete-time.
751
751
752
752
transpose: bool
753
753
If True, transpose all input and output arrays (for backward
@@ -830,56 +830,55 @@ def _ideal_tfinal_and_dt(sys):
830
830
constant = 7.0
831
831
tolerance = 1e-10
832
832
A = ssdata (sys )[0 ]
833
- if A .shape == (0 ,0 ):
833
+ if A .shape == (0 ,0 ):
834
834
# no dynamics
835
- tfinal = constant * 1.0
835
+ tfinal = constant * 1.0
836
836
dt = sys .dt if isdtime (sys ,strict = True )else 1.0
837
837
else :
838
838
poles = sp .linalg .eigvals (A )
839
- if isdtime (sys ,strict = True ):
840
- poles = np .log (poles )/ sys .dt # z-poles to s-plane using s=(lnz)/dt
841
-
842
839
# calculate ideal dt
843
840
if isdtime (sys ,strict = True ):
841
+ # z-poles to s-plane using s=(lnz)/dt, no ln(0)
842
+ poles = np .log (poles [abs (poles )> 0 ])/ sys .dt
844
843
dt = sys .dt
845
844
else :
846
845
fastest_natural_frequency = max (abs (poles ))
847
846
dt = 1 / constant / fastest_natural_frequency
848
-
847
+
849
848
# calculate ideal tfinal
850
849
poles = poles [abs (poles .real )> tolerance ]# ignore poles near im axis
851
- if poles .size == 0 :
850
+ if poles .size == 0 :
852
851
slowest_decay_rate = 1.0
853
852
else :
854
853
slowest_decay_rate = min (abs (poles .real ))
855
- tfinal = constant / slowest_decay_rate
854
+ tfinal = constant / slowest_decay_rate
856
855
857
856
return tfinal ,dt
858
857
859
- # test below: ct with pole at the origin is 7 seconds, ct with pole at .5 is 14 s long,
858
+ # test below: ct with pole at the origin is 7 seconds, ct with pole at .5 is 14 s long,
860
859
def _default_time_vector (sys ,N = None ,tfinal = None ):
861
- """Returns a time vector suitable for observing the response of the
862
- both the slowest poles and fastest resonant modes. if system is
860
+ """Returns a time vector suitable for observing the response of the
861
+ both the slowest poles and fastest resonant modes. if system is
863
862
discrete-time, N is ignored """
864
-
863
+
865
864
N_max = 5000
866
865
N_min_ct = 100
867
866
N_min_dt = 7 # more common to see just a few samples in discrete-time
868
-
867
+
869
868
ideal_tfinal ,ideal_dt = _ideal_tfinal_and_dt (sys )
870
-
869
+
871
870
if isdtime (sys ,strict = True ):
872
- if tfinal is None :
871
+ if tfinal is None :
873
872
# for discrete time, change from ideal_tfinal if N too large/small
874
873
N = int (np .clip (ideal_tfinal / sys .dt ,N_min_dt ,N_max ))# [N_min, N_max]
875
874
tfinal = sys .dt * N
876
- else :
875
+ else :
877
876
N = int (tfinal / sys .dt )
878
- else :
879
- if tfinal is None :
877
+ else :
878
+ if tfinal is None :
880
879
# for continuous time, simulate to ideal_tfinal but limit N
881
880
tfinal = ideal_tfinal
882
- if N is None :
881
+ if N is None :
883
882
N = int (np .clip (tfinal / ideal_dt ,N_min_ct ,N_max ))# N<-[N_min, N_max]
884
-
883
+
885
884
return np .linspace (0 ,tfinal ,N ,endpoint = False )