-
Notifications
You must be signed in to change notification settings - Fork 20
/
matlab.py
1395 lines (1117 loc) · 45.1 KB
/
matlab.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
"""matlab.py
MATLAB emulation functions.
This file contains a number of functions that emulate some of the
functionality of MATLAB. The intent of these functions is to
provide a simple interface to the python control systems library
(python-control) for people who are familiar with the MATLAB Control
Systems Toolbox (tm). Most of the functions are just calls to
python-control functions defined elsewhere. Use 'from
control.matlab import \*' in python to include all of the functions
defined here. Functions that are defined in other libraries that
have the same names as their MATLAB equivalents are automatically
imported here.
"""
"""Copyright (c) 2009 by California Institute of Technology
All rights reserved.
Copyright (c) 2011 by Eike Welk
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the California Institute of Technology nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALTECH
OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Author: Richard M. Murray
Date: 29 May 09
Revised: Kevin K. Chen, Dec 10
$Id: matlab.py 216 2012-11-03 03:23:13Z murrayrm $
"""
# Libraries that we make use of
import scipy as sp # SciPy library (used all over)
import numpy as np # NumPy library
import re # regular expressions
from copy import deepcopy
# Import MATLAB-like functions that are defined in other packages
from scipy.signal import zpk2ss, ss2zpk, tf2zpk, zpk2tf
from numpy import linspace, logspace
# Control system library
import control.ctrlutil as ctrlutil
import control.freqplot as freqplot
import control.timeresp as timeresp
import control.margins as margins
from control.statesp import StateSpace, _rss_generate, _convertToStateSpace
from control.xferfcn import TransferFunction, _convertToTransferFunction
from control.lti import Lti #base class of StateSpace, TransferFunction
from control.dtime import sample_system
from control.exception import ControlArgument
# Import MATLAB-like functions that can be used as-is
from control.ctrlutil import unwrap
from control.freqplot import nyquist, gangof4
from control.nichols import nichols
from control.bdalg import series, parallel, negate, feedback
from control.pzmap import pzmap
from control.statefbk import ctrb, obsv, gram, place, lqr
from control.delay import pade
from control.modelsimp import hsvd, balred, modred
from control.mateqn import lyap, dlyap, dare, care
__doc__ += r"""
The following tables give an overview of the module ``control.matlab``.
They also show the implementation progress and the planned features of the
module.
The symbols in the first column show the current state of a feature:
* ``*`` : The feature is currently implemented.
* ``-`` : The feature is not planned for implementation.
* ``s`` : A similar feature from an other library (Scipy) is imported into
the module, until the feature is implemented here.
Creating linear models
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`tf` create transfer function (TF) models
\ zpk create zero/pole/gain (ZPK) models.
\* :func:`ss` create state-space (SS) models
\ dss create descriptor state-space models
\ delayss create state-space models with delayed terms
\ frd create frequency response data (FRD) models
\ lti/exp create pure continuous-time delays (TF and
ZPK only)
\ filt specify digital filters
\- lti/set set/modify properties of LTI models
\- setdelaymodel specify internal delay model (state space
only)
== ========================== ============================================
Data extraction
----------------------------------------------------------------------------
== ========================== ============================================
\ lti/tfdata extract numerators and denominators
\ lti/zpkdata extract zero/pole/gain data
\ lti/ssdata extract state-space matrices
\ lti/dssdata descriptor version of SSDATA
\ frd/frdata extract frequency response data
\ lti/get access values of LTI model properties
\ ss/getDelayModel access internal delay model (state space)
== ========================== ============================================
Conversions
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`tf` conversion to transfer function
\ zpk conversion to zero/pole/gain
\* :func:`ss` conversion to state space
\ frd conversion to frequency data
\ c2d continuous to discrete conversion
\ d2c discrete to continuous conversion
\ d2d resample discrete-time model
\ upsample upsample discrete-time LTI systems
\* :func:`ss2tf` state space to transfer function
\s ss2zpk transfer function to zero-pole-gain
\* :func:`tf2ss` transfer function to state space
\s tf2zpk transfer function to zero-pole-gain
\s zpk2ss zero-pole-gain to state space
\s zpk2tf zero-pole-gain to transfer function
== ========================== ============================================
System interconnections
----------------------------------------------------------------------------
== ========================== ============================================
\ append group LTI models by appending inputs/outputs
\* :func:`~bdalg.parallel` connect LTI models in parallel
(see also overloaded ``+``)
\* :func:`~bdalg.series` connect LTI models in series
(see also overloaded ``*``)
\* :func:`~bdalg.feedback` connect lti models with a feedback loop
\ lti/lft generalized feedback interconnection
\ lti/connect arbitrary interconnection of lti models
\ sumblk summing junction (for use with connect)
\ strseq builds sequence of indexed strings
(for I/O naming)
== ========================== ============================================
System gain and dynamics
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`dcgain` steady-state (D.C.) gain
\ lti/bandwidth system bandwidth
\ lti/norm h2 and Hinfinity norms of LTI models
\* :func:`pole` system poles
\* :func:`zero` system (transmission) zeros
\ lti/order model order (number of states)
\* :func:`~pzmap.pzmap` pole-zero map (TF only)
\ lti/iopzmap input/output pole-zero map
\ damp natural frequency, damping of system poles
\ esort sort continuous poles by real part
\ dsort sort discrete poles by magnitude
\ lti/stabsep stable/unstable decomposition
\ lti/modsep region-based modal decomposition
== ========================== ============================================
Time-domain analysis
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`step` step response
\ stepinfo step response characteristics
\* :func:`impulse` impulse response
\* :func:`initial` free response with initial conditions
\* :func:`lsim` response to user-defined input signal
\ lsiminfo linear response characteristics
\ gensig generate input signal for LSIM
\ covar covariance of response to white noise
== ========================== ============================================
Frequency-domain analysis
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`bode` Bode plot of the frequency response
\ lti/bodemag Bode magnitude diagram only
\ sigma singular value frequency plot
\* :func:`~freqplot.nyquist` Nyquist plot
\* :func:`~nichols.nichols` Nichols plot
\* :func:`margin` gain and phase margins
\ lti/allmargin all crossover frequencies and margins
\* :func:`freqresp` frequency response over a frequency grid
\* :func:`evalfr` frequency response at single frequency
== ========================== ============================================
Model simplification
----------------------------------------------------------------------------
== ========================== ============================================
\ minreal minimal realization; pole/zero cancellation
\ ss/sminreal structurally minimal realization
\* :func:`~modelsimp.hsvd` hankel singular values (state contributions)
\* :func:`~modelsimp.balred` reduced-order approximations of LTI models
\* :func:`~modelsimp.modred` model order reduction
== ========================== ============================================
Compensator design
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`rlocus` evans root locus
\* :func:`~statefbk.place` pole placement
\ estim form estimator given estimator gain
\ reg form regulator given state-feedback and
estimator gains
== ========================== ============================================
LQR/LQG design
----------------------------------------------------------------------------
== ========================== ============================================
\ ss/lqg single-step LQG design
\* :func:`~statefbk.lqr` linear quadratic (LQ) state-fbk regulator
\ dlqr discrete-time LQ state-feedback regulator
\ lqry LQ regulator with output weighting
\ lqrd discrete LQ regulator for continuous plant
\ ss/lqi Linear-Quadratic-Integral (LQI) controller
\ ss/kalman Kalman state estimator
\ ss/kalmd discrete Kalman estimator for cts plant
\ ss/lqgreg build LQG regulator from LQ gain and Kalman
estimator
\ ss/lqgtrack build LQG servo-controller
\ augstate augment output by appending states
== ========================== ============================================
State-space (SS) models
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`rss` random stable cts-time state-space models
\* :func:`drss` random stable disc-time state-space models
\ ss2ss state coordinate transformation
\ canon canonical forms of state-space models
\* :func:`~statefbk.ctrb` controllability matrix
\* :func:`~statefbk.obsv` observability matrix
\* :func:`~statefbk.gram` controllability and observability gramians
\ ss/prescale optimal scaling of state-space models.
\ balreal gramian-based input/output balancing
\ ss/xperm reorder states.
== ========================== ============================================
Frequency response data (FRD) models
----------------------------------------------------------------------------
== ========================== ============================================
\ frd/chgunits change frequency vector units
\ frd/fcat merge frequency responses
\ frd/fselect select frequency range or subgrid
\ frd/fnorm peak gain as a function of frequency
\ frd/abs entrywise magnitude of frequency response
\ frd/real real part of the frequency response
\ frd/imag imaginary part of the frequency response
\ frd/interp interpolate frequency response data
\ mag2db convert magnitude to decibels (dB)
\ db2mag convert decibels (dB) to magnitude
== ========================== ============================================
Time delays
----------------------------------------------------------------------------
== ========================== ============================================
\ lti/hasdelay true for models with time delays
\ lti/totaldelay total delay between each input/output pair
\ lti/delay2z replace delays by poles at z=0 or FRD phase
shift
\* :func:`~delay.pade` pade approximation of time delays
== ========================== ============================================
Model dimensions and characteristics
----------------------------------------------------------------------------
== ========================== ============================================
\ class model type ('tf', 'zpk', 'ss', or 'frd')
\ isa test if model is of given type
\ tf/size model sizes
\ lti/ndims number of dimensions
\ lti/isempty true for empty models
\ lti/isct true for continuous-time models
\ lti/isdt true for discrete-time models
\ lti/isproper true for proper models
\ lti/issiso true for single-input/single-output models
\ lti/isstable true for models with stable dynamics
\ lti/reshape reshape array of linear models
== ========================== ============================================
Overloaded arithmetic operations
----------------------------------------------------------------------------
== ========================== ============================================
\* \+ and - add, subtract systems (parallel connection)
\* \* multiply systems (series connection)
\ / right divide -- sys1\*inv(sys2)
\- \\ left divide -- inv(sys1)\*sys2
\ ^ powers of a given system
\ ' pertransposition
\ .' transposition of input/output map
\ .\* element-by-element multiplication
\ [..] concatenate models along inputs or outputs
\ lti/stack stack models/arrays along some dimension
\ lti/inv inverse of an LTI system
\ lti/conj complex conjugation of model coefficients
== ========================== ============================================
Matrix equation solvers and linear algebra
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`~mateqn.lyap` solve continuous-time Lyapunov equations
\* :func:`~mateqn.dlyap` solve discrete-time Lyapunov equations
\ lyapchol, dlyapchol square-root Lyapunov solvers
\* :func:`~mateqn.care` solve continuous-time algebraic Riccati
equations
\* :func:`~mateqn.dare` solve disc-time algebraic Riccati equations
\ gcare, gdare generalized Riccati solvers
\ bdschur block diagonalization of a square matrix
== ========================== ============================================
Additional functions
----------------------------------------------------------------------------
== ========================== ============================================
\* :func:`~freqplot.gangof4` generate the Gang of 4 sensitivity plots
\* :func:`~numpy.linspace` generate a set of numbers that are linearly
spaced
\* :func:`~numpy.logspace` generate a set of numbers that are
logarithmically spaced
\* :func:`~ctrlutil.unwrap` unwrap phase angle to give continuous curve
== ========================== ============================================
"""
def ss(*args):
"""
Create a state space system.
The function accepts either 1 or 4 parameters:
``ss(sys)``
Convert a linear system into space system form. Always creates a
new system, even if sys is already a StateSpace object.
``ss(A, B, C, D)``
Create a state space system from the matrices of its state and
output equations:
.. math::
\dot x = A \cdot x + B \cdot u
y = C \cdot x + D \cdot u
The matrices can be given as *array like* data types or strings.
Everything that the constructor of :class:`numpy.matrix` accepts is
permissible here too.
Parameters
----------
sys: Lti (StateSpace or TransferFunction)
A linear system
A: array_like or string
System matrix
B: array_like or string
Control matrix
C: array_like or string
Output matrix
D: array_like or string
Feed forward matrix
Returns
-------
out: StateSpace
The new linear system
Raises
------
ValueError
if matrix sizes are not self-consistent
See Also
--------
tf
ss2tf
tf2ss
Examples
--------
>>> # Create a StateSpace object from four "matrices".
>>> sys1 = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> # Convert a TransferFunction to a StateSpace object.
>>> sys_tf = tf([2.], [1., 3])
>>> sys2 = ss(sys_tf)
"""
if len(args) == 4:
return StateSpace(args[0], args[1], args[2], args[3])
elif len(args) == 1:
sys = args[0]
if isinstance(sys, StateSpace):
return deepcopy(sys)
elif isinstance(sys, TransferFunction):
return tf2ss(sys)
else:
raise TypeError("ss(sys): sys must be a StateSpace or \
TransferFunction object. It is %s." % type(sys))
else:
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))
def tf(*args):
"""
Create a transfer function system. Can create MIMO systems.
The function accepts either 1 or 2 parameters:
``tf(sys)``
Convert a linear system into transfer function form. Always creates
a new system, even if sys is already a TransferFunction object.
``tf(num, den)``
Create a transfer function system from its numerator and denominator
polynomial coefficients.
If `num` and `den` are 1D array_like objects, the function creates a
SISO system.
To create a MIMO system, `num` and `den` need to be 2D nested lists
of array_like objects. (A 3 dimensional data structure in total.)
(For details see note below.)
``tf(num, den, dt)``
Create a discrete time transfer function system; dt can either be a
positive number indicating the sampling time or 'True' if no
specific timebase is given.
Parameters
----------
sys: Lti (StateSpace or TransferFunction)
A linear system
num: array_like, or list of list of array_like
Polynomial coefficients of the numerator
den: array_like, or list of list of array_like
Polynomial coefficients of the denominator
Returns
-------
out: TransferFunction
The new linear system
Raises
------
ValueError
if `num` and `den` have invalid or unequal dimensions
TypeError
if `num` or `den` are of incorrect type
See Also
--------
ss
ss2tf
tf2ss
Notes
--------
.. todo::
The next paragraph contradicts the comment in the example!
Also "input" should come before "output" in the sentence:
"from the (j+1)st output to the (i+1)st input"
``num[i][j]`` contains the polynomial coefficients of the numerator
for the transfer function from the (j+1)st output to the (i+1)st input.
``den[i][j]`` works the same way.
The coefficients ``[2, 3, 4]`` denote the polynomial
:math:`2 \cdot s^2 + 3 \cdot s + 4`.
Examples
--------
>>> # Create a MIMO transfer function object
>>> # The transfer function from the 2nd input to the 1st output is
>>> # (3s + 4) / (6s^2 + 5s + 4).
>>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]]
>>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]]
>>> sys1 = tf(num, den)
>>> # Convert a StateSpace to a TransferFunction object.
>>> sys_ss = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> sys2 = tf(sys1)
"""
if len(args) == 2 or len(args) == 3:
return TransferFunction(*args)
elif len(args) == 1:
sys = args[0]
if isinstance(sys, StateSpace):
return ss2tf(sys)
elif isinstance(sys, TransferFunction):
return deepcopy(sys)
else:
raise TypeError("tf(sys): sys must be a StateSpace or \
TransferFunction object. It is %s." % type(sys))
else:
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))
def ss2tf(*args):
"""
Transform a state space system to a transfer function.
The function accepts either 1 or 4 parameters:
``ss2tf(sys)``
Convert a linear system into space system form. Always creates a
new system, even if sys is already a StateSpace object.
``ss2tf(A, B, C, D)``
Create a state space system from the matrices of its state and
output equations.
For details see: :func:`ss`
Parameters
----------
sys: StateSpace
A linear system
A: array_like or string
System matrix
B: array_like or string
Control matrix
C: array_like or string
Output matrix
D: array_like or string
Feed forward matrix
Returns
-------
out: TransferFunction
New linear system in transfer function form
Raises
------
ValueError
if matrix sizes are not self-consistent, or if an invalid number of
arguments is passed in
TypeError
if `sys` is not a StateSpace object
See Also
--------
tf
ss
tf2ss
Examples
--------
>>> A = [[1., -2], [3, -4]]
>>> B = [[5.], [7]]
>>> C = [[6., 8]]
>>> D = [[9.]]
>>> sys1 = ss2tf(A, B, C, D)
>>> sys_ss = ss(A, B, C, D)
>>> sys2 = ss2tf(sys_ss)
"""
if len(args) == 4 or len(args) == 5:
# Assume we were given the A, B, C, D matrix and (optional) dt
return _convertToTransferFunction(StateSpace(*args))
elif len(args) == 1:
sys = args[0]
if isinstance(sys, StateSpace):
return _convertToTransferFunction(sys)
else:
raise TypeError("ss2tf(sys): sys must be a StateSpace object. It \
is %s." % type(sys))
else:
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))
def tf2ss(*args):
"""
Transform a transfer function to a state space system.
The function accepts either 1 or 2 parameters:
``tf2ss(sys)``
Convert a linear system into transfer function form. Always creates
a new system, even if sys is already a TransferFunction object.
``tf2ss(num, den)``
Create a transfer function system from its numerator and denominator
polynomial coefficients.
For details see: :func:`tf`
Parameters
----------
sys: Lti (StateSpace or TransferFunction)
A linear system
num: array_like, or list of list of array_like
Polynomial coefficients of the numerator
den: array_like, or list of list of array_like
Polynomial coefficients of the denominator
Returns
-------
out: StateSpace
New linear system in state space form
Raises
------
ValueError
if `num` and `den` have invalid or unequal dimensions, or if an
invalid number of arguments is passed in
TypeError
if `num` or `den` are of incorrect type, or if sys is not a
TransferFunction object
See Also
--------
ss
tf
ss2tf
Examples
--------
>>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]]
>>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]]
>>> sys1 = tf2ss(num, den)
>>> sys_tf = tf(num, den)
>>> sys2 = tf2ss(sys_tf)
"""
if len(args) == 2 or len(args) == 3:
# Assume we were given the num, den
return _convertToStateSpace(TransferFunction(*args))
elif len(args) == 1:
sys = args[0]
if not isinstance(sys, TransferFunction):
raise TypeError("tf2ss(sys): sys must be a TransferFunction \
object.")
return _convertToStateSpace(sys)
else:
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))
def rss(states=1, inputs=1, outputs=1):
"""
Create a stable **continuous** random state space object.
Parameters
----------
states: integer
Number of state variables
inputs: integer
Number of system inputs
outputs: integer
Number of system outputs
Returns
-------
sys: StateSpace
The randomly created linear system
Raises
------
ValueError
if any input is not a positive integer
See Also
--------
drss
Notes
-----
If the number of states, inputs, or outputs is not specified, then the
missing numbers are assumed to be 1. The poles of the returned system
will always have a negative real part.
"""
return _rss_generate(states, inputs, outputs, 'c')
def drss(states=1, inputs=1, outputs=1):
"""
Create a stable **discrete** random state space object.
Parameters
----------
states: integer
Number of state variables
inputs: integer
Number of system inputs
outputs: integer
Number of system outputs
Returns
-------
sys: StateSpace
The randomly created linear system
Raises
------
ValueError
if any input is not a positive integer
See Also
--------
rss
Notes
-----
If the number of states, inputs, or outputs is not specified, then the
missing numbers are assumed to be 1. The poles of the returned system
will always have a magnitude less than 1.
"""
return _rss_generate(states, inputs, outputs, 'd')
def pole(sys):
"""
Compute system poles.
Parameters
----------
sys: StateSpace or TransferFunction
Linear system
Returns
-------
poles: ndarray
Array that contains the system's poles.
Raises
------
NotImplementedError
when called on a TransferFunction object
See Also
--------
zero
Notes
-----
This function is a wrapper for StateSpace.pole and
TransferFunction.pole.
"""
return sys.pole()
def zero(sys):
"""
Compute system zeros.
Parameters
----------
sys: StateSpace or TransferFunction
Linear system
Returns
-------
zeros: ndarray
Array that contains the system's zeros.
Raises
------
NotImplementedError
when called on a TransferFunction object or a MIMO StateSpace object
See Also
--------
pole
Notes
-----
This function is a wrapper for StateSpace.zero and
TransferFunction.zero.
"""
return sys.zero()
def evalfr(sys, omega):
"""
Evaluate the transfer function of an LTI system at an angular frequency.
Parameters
----------
sys: StateSpace or TransferFunction
Linear system
omega: scalar
Frequency
Returns
-------
fresp: ndarray
See Also
--------
freqresp
bode
Notes
-----
This function is a wrapper for StateSpace.evalfr and
TransferFunction.evalfr.
Examples
--------
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> evalfr(sys, 1.)
array([[ 44.8-21.4j]])
>>> # This is the transfer function matrix evaluated at s = i.
.. todo:: Add example with MIMO system
"""
return sys.evalfr(omega)
def freqresp(sys, omega):
"""
Frequency response of an LTI system at multiple angular frequencies.
Parameters
----------
sys: StateSpace or TransferFunction
Linear system
omega: array_like
List of frequencies
Returns
-------
mag: ndarray
phase: ndarray
omega: list, tuple, or ndarray
See Also
--------
evalfr
bode
Notes
-----
This function is a wrapper for StateSpace.freqresp and
TransferFunction.freqresp. The output omega is a sorted version of the
input omega.
Examples
--------
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = freqresp(sys, [0.1, 1., 10.])
>>> mag
array([[[ 58.8576682 , 49.64876635, 13.40825927]]])
>>> phase
array([[[-0.05408304, -0.44563154, -0.66837155]]])
.. todo::
Add example with MIMO system
#>>> sys = rss(3, 2, 2)
#>>> mag, phase, omega = freqresp(sys, [0.1, 1., 10.])
#>>> mag[0, 1, :]
#array([ 55.43747231, 42.47766549, 1.97225895])
#>>> phase[1, 0, :]
#array([-0.12611087, -1.14294316, 2.5764547 ])
#>>> # This is the magnitude of the frequency response from the 2nd
#>>> # input to the 1st output, and the phase (in radians) of the
#>>> # frequency response from the 1st input to the 2nd output, for
#>>> # s = 0.1i, i, 10i.
"""
return sys.freqresp(omega)
# Bode plots
def bode(*args, **keywords):
"""Bode plot of the frequency response
Examples
--------
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = bode(sys)
.. todo::
Document these use cases
* >>> bode(sys, w)
* >>> bode(sys1, sys2, ..., sysN)
* >>> bode(sys1, sys2, ..., sysN, w)
* >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN')
"""
# If the first argument is a list, then assume python-control calling format
if (getattr(args[0], '__iter__', False)):
return freqplot.bode(*args, **keywords)
# Otherwise, run through the arguments and collect up arguments
syslist = []; plotstyle=[]; omega=None;
i = 0;
while i < len(args):
# Check to see if this is a system of some sort
if (ctrlutil.issys(args[i])):
# Append the system to our list of systems
syslist.append(args[i])
i += 1
# See if the next object is a plotsytle (string)
if (i < len(args) and isinstance(args[i], str)):
plotstyle.append(args[i])
i += 1
# Go on to the next argument
continue
# See if this is a frequency list
elif (isinstance(args[i], (list, np.ndarray))):
omega = args[i]
i += 1
break
else:
raise ControlArgument("unrecognized argument type")
# Check to make sure that we processed all arguments
if (i < len(args)):
raise ControlArgument("not all arguments processed")
# Check to make sure we got the same number of plotstyles as systems
if (len(plotstyle) != 0 and len(syslist) != len(plotstyle)):
raise ControlArgument("number of systems and plotstyles should be equal")
# Warn about unimplemented plotstyles
#! TODO: remove this when plot styles are implemented in bode()
#! TODO: uncomment unit test code that tests this out
if (len(plotstyle) != 0):
print("Warning (matabl.bode): plot styles not implemented");
# Call the bode command
return freqplot.bode(syslist, omega, **keywords)