L indZddlZddlmZddlmZddlmZddl m Z m Z m Z m Z mZmZmZddlmZmZmZmZmZmZmZddlZdd lmZmZmZmZmZm Z m!Z!m"Z"m#Z#ddl$Z$gd Z%Gd d Z&Gd de&Z'Gdde&Z(Gdde&Z)Gdde)e'Z*Gdde)e(Z+Gdde&Z,Gdde,e'Z-Gdde,e(Z.Gdde&Z/Gdd e/e'Z0Gd!d"e/e(Z1d8d#Z2d$Z3d9d%Z4d9d&Z5d:d'Z6d;d(Z7Gd)d*Z8d+Z9d,Z:d-Z;d.Zd1Z?dd6ZDd:d7ZEy)?z] ltisys -- a collection of classes and functions for modeling linear time invariant systems. N)qr)linalg)make_interp_spline)tf2zpkzpk2tf normalizefreqsfreqz freqs_zpk freqz_zpk)tf2ssabcd_normalizess2tfzpk2ssss2zpk cont2discrete_atleast_2d_or_none) real atleast_1dsqueezeasarrayzerosdot transposeoneslinspace)ltidltiTransferFunctionZerosPolesGain StateSpacelsimimpulsestepbodefreqresp place_polesdlsimdstepdimpulse dfreqrespdbodeczeZdZfdZfdZedZedZedZedZ dZ dZ d Z xZ S) LinearTimeInvariantcH|tur tdt| |S)z2Create a new object, don't allow direct instances.z\The LinearTimeInvariant class is not meant to be used directly, use `lti` or `dlti` instead.)r/NotImplementedErrorsuper__new__clssystemkwargs __class__s Z/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/scipy/signal/_ltisys.pyr3zLinearTimeInvariant.__new__/s/ % %%';< <ws##cLt|d|_d|_d|_yg Initialize the `lti` baseclass. The heavy lifting is done by the subclasses. N)r2__init__inputsoutputs_dt)selfr8s r9r>zLinearTimeInvariant.__init__7s%   r:c|jS)zAReturn the sampling time of the system, `None` for `lti` systems.rArBs r9dtzLinearTimeInvariant.dtC xxr:c:|jiSd|jiS)NrF)rFrEs r9_dt_dictzLinearTimeInvariant._dt_dictHs 77?I$''? "r:c6|jjS)zZeros of the system.)to_zpkrrEs r9rzLinearTimeInvariant.zerosO{{}"""r:c6|jjS)zPoles of the system.)rKpolesrEs r9rNzLinearTimeInvariant.polesTrLr:cFt|tr|S|jS)zConvert to `StateSpace` system, without copying. Returns ------- sys: StateSpace The `StateSpace` system. If the class is already an instance of `StateSpace` then this instance is returned. ) isinstancer"to_ssrEs r9_as_sszLinearTimeInvariant._as_ssYs dJ 'K::< r:cFt|tr|S|jS)aConvert to `ZerosPolesGain` system, without copying. Returns ------- sys: ZerosPolesGain The `ZerosPolesGain` system. If the class is already an instance of `ZerosPolesGain` then this instance is returned. )rPr!rKrEs r9_as_zpkzLinearTimeInvariant._as_zpkgs dN +K;;= r:cFt|tr|S|jS)a Convert to `TransferFunction` system, without copying. Returns ------- sys: ZerosPolesGain The `TransferFunction` system. If the class is already an instance of `TransferFunction` then this instance is returned. )rPr to_tfrEs r9_as_tfzLinearTimeInvariant._as_tfus  d, -K::< r:)__name__ __module__ __qualname__r3r>propertyrFrIrrNrRrTrW __classcell__r8s@r9r/r/.sl$ ## ####   !  r:r/c\eZdZdZfdZfdZd dZd dZd dZd dZ d dZ dd Z xZ S)ra  Continuous-time linear time invariant system base class. Parameters ---------- *system : arguments The `lti` class can be instantiated with either 2, 3 or 4 arguments. The following gives the number of arguments and the corresponding continuous-time subclass that is created: * 2: `TransferFunction`: (numerator, denominator) * 3: `ZerosPolesGain`: (zeros, poles, gain) * 4: `StateSpace`: (A, B, C, D) Each argument can be an array or a sequence. See Also -------- ZerosPolesGain, StateSpace, TransferFunction, dlti Notes ----- `lti` instances do not exist directly. Instead, `lti` creates an instance of one of its subclasses: `StateSpace`, `TransferFunction` or `ZerosPolesGain`. If (numerator, denominator) is passed in for ``*system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g., ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``). Changing the value of properties that are not directly part of the current system representation (such as the `zeros` of a `StateSpace` system) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain. Examples -------- >>> from scipy import signal >>> signal.lti(1, 2, 3, 4) StateSpaceContinuous( array([[1]]), array([[2]]), array([[3]]), array([[4]]), dt: None ) Construct the transfer function :math:`H(s) = \frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`: >>> signal.lti([1, 2], [3, 4], 5) ZerosPolesGainContinuous( array([1, 2]), array([3, 4]), 5, dt: None ) Construct the transfer function :math:`H(s) = \frac{3s + 4}{1s + 2}`: >>> signal.lti([3, 4], [1, 2]) TransferFunctionContinuous( array([3., 4.]), array([1., 2.]), dt: None ) c|turst|}|dk(rtjtg|S|dk(rt jtg|S|dk(rt jt g|St dt| |S)/Create an instance of the appropriate subclass.zF`system` needs to be an instance of `lti` or have 2, 3 or 4 arguments.)rlenTransferFunctionContinuousr3ZerosPolesGainContinuousStateSpaceContinuous ValueErrorr2)r5r6Nr8s r9r3z lti.__new__s #:F AAv199.91799a/77,7/577a+334H=5;==!"@AAws##r:ct||yr<)r2r>)rBr6r8s r9r>z lti.__init__s &!r:c t||||S)zm Return the impulse response of a continuous-time system. See `impulse` for details. X0Tri)r$rBrmrnris r9r$z lti.impulses ta1--r:c t||||S)zg Return the step response of a continuous-time system. See `step` for details. rl)r%ros r9r%zlti.steps DR1**r:c t||||S)zo Return the response of a continuous-time system to input `U`. See `lsim` for details. )rm)r#)rBUrnrms r9outputz lti.outputs D!Q2&&r:ct|||S)ai Calculate Bode magnitude and phase data of a continuous-time system. Returns a 3-tuple containing arrays of frequencies [rad/s], magnitude [dB] and phase [deg]. See `bode` for details. Examples -------- >>> from scipy import signal >>> import matplotlib.pyplot as plt >>> sys = signal.TransferFunction([1], [1, 1]) >>> w, mag, phase = sys.bode() >>> plt.figure() >>> plt.semilogx(w, mag) # Bode magnitude plot >>> plt.figure() >>> plt.semilogx(w, phase) # Bode phase plot >>> plt.show() wn)r&rBrvrws r9r&zlti.bodes,DA##r:ct|||S)z Calculate the frequency response of a continuous-time system. Returns a 2-tuple containing arrays of frequencies [rad/s] and complex magnitude. See `freqresp` for details. ru)r'rxs r9r'z lti.freqrespsQ''r:ctd)zReturn a discretized version of the current system. Parameters: See `cont2discrete` for details. Returns ------- sys: instance of `dlti` z5to_discrete is not implemented for this system class.)r1rBrFmethodalphas r9 to_discretezlti.to_discretes"#23 3r:NNNNNdN'zohN) rXrYrZ__doc__r3r>r$r%rsr&r'r~r\r]s@r9rrs2FN$&".+'$0( 3r:rceZdZdZfdZfdZedZejdZd dZ d dZ d dZ d d Z dd Z xZS)ra Discrete-time linear time invariant system base class. Parameters ---------- *system: arguments The `dlti` class can be instantiated with either 2, 3 or 4 arguments. The following gives the number of arguments and the corresponding discrete-time subclass that is created: * 2: `TransferFunction`: (numerator, denominator) * 3: `ZerosPolesGain`: (zeros, poles, gain) * 4: `StateSpace`: (A, B, C, D) Each argument can be an array or a sequence. dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to ``True`` (unspecified sampling time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- ZerosPolesGain, StateSpace, TransferFunction, lti Notes ----- `dlti` instances do not exist directly. Instead, `dlti` creates an instance of one of its subclasses: `StateSpace`, `TransferFunction` or `ZerosPolesGain`. Changing the value of properties that are not directly part of the current system representation (such as the `zeros` of a `StateSpace` system) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain. If (numerator, denominator) is passed in for ``*system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g., ``z^2 + 3z + 5`` would be represented as ``[1, 3, 5]``). .. versionadded:: 0.18.0 Examples -------- >>> from scipy import signal >>> signal.dlti(1, 2, 3, 4) StateSpaceDiscrete( array([[1]]), array([[2]]), array([[3]]), array([[4]]), dt: True ) >>> signal.dlti(1, 2, 3, 4, dt=0.1) StateSpaceDiscrete( array([[1]]), array([[2]]), array([[3]]), array([[4]]), dt: 0.1 ) Construct the transfer function :math:`H(z) = \frac{5(z - 1)(z - 2)}{(z - 3)(z - 4)}` with a sampling time of 0.1 seconds: >>> signal.dlti([1, 2], [3, 4], 5, dt=0.1) ZerosPolesGainDiscrete( array([1, 2]), array([3, 4]), 5, dt: 0.1 ) Construct the transfer function :math:`H(z) = \frac{3z + 4}{1z + 2}` with a sampling time of 0.1 seconds: >>> signal.dlti([3, 4], [1, 2], dt=0.1) TransferFunctionDiscrete( array([3., 4.]), array([1., 2.]), dt: 0.1 ) c*|tur|t|}|dk(rtjtg|i|S|dk(rt jtg|i|S|dk(rt jt g|i|St dt| |S)r`rarbrczG`system` needs to be an instance of `dlti` or have 2, 3 or 4 arguments.)rrdTransferFunctionDiscreter3ZerosPolesGainDiscreteStateSpaceDiscreterhr2)r5r6r7rir8s r9r3z dlti.__new__s $;F AAv/77,A/5A9?AAa-556LI7=IAGIIa)112DrF)rBr6r7rFr8s r9r>z dlti.__init__s. ZZd # &+F+r:c|jS)z'Return the sampling time of the system.rDrEs r9rFzdlti.dtrGr:c||_yrrD)rBrFs r9rFzdlti.dts r:c t||||S)zu Return the impulse response of the discrete-time `dlti` system. See `dimpulse` for details. x0trw)r+rBrrrws r9r$z dlti.impulses qA..r:c t||||S)zo Return the step response of the discrete-time `dlti` system. See `dstep` for details. r)r*rs r9r%z dlti.steps TbA++r:c t||||S)zp Return the response of the discrete-time system to input `u`. See `dlsim` for details. )r)r))rBurrs r9rsz dlti.outputs T1aB''r:ct|||S)a  Calculate Bode magnitude and phase data of a discrete-time system. Returns a 3-tuple containing arrays of frequencies [rad/s], magnitude [dB] and phase [deg]. See `dbode` for details. Examples -------- >>> from scipy import signal >>> import matplotlib.pyplot as plt Construct the transfer function :math:`H(z) = \frac{1}{z^2 + 2z + 3}` with sampling time 0.5s: >>> sys = signal.TransferFunction([1], [1, 2, 3], dt=0.5) Equivalent: signal.dbode(sys) >>> w, mag, phase = sys.bode() >>> plt.figure() >>> plt.semilogx(w, mag) # Bode magnitude plot >>> plt.figure() >>> plt.semilogx(w, phase) # Bode phase plot >>> plt.show() ru)r-rxs r9r&z dlti.bodes8TQ!$$r:c t||||S)z Calculate the frequency response of a discrete-time system. Returns a 2-tuple containing arrays of frequencies [rad/s] and complex magnitude. See `dfreqresp` for details. )rvrwwhole)r,)rBrvrwrs r9r'z dlti.freqrespsau55r:rrrNrF)rXrYrZrr3r>r[rFsetterr$r%rsr&r'r\r]s@r9rr+sYWp$& YY/,(%< 6r:rceZdZdZfdZfdZdZedZejdZedZ e jdZ d Z d Z d Z d Zed ZedZxZS)r aJ Linear Time Invariant system class in transfer function form. Represents the system as the continuous-time transfer function :math:`H(s)=\sum_{i=0}^N b[N-i] s^i / \sum_{j=0}^M a[M-j] s^j` or the discrete-time transfer function :math:`H(z)=\sum_{i=0}^N b[N-i] z^i / \sum_{j=0}^M a[M-j] z^j`, where :math:`b` are elements of the numerator `num`, :math:`a` are elements of the denominator `den`, and ``N == len(b) - 1``, ``M == len(a) - 1``. `TransferFunction` systems inherit additional functionality from the `lti`, respectively the `dlti` classes, depending on which system representation is used. Parameters ---------- *system: arguments The `TransferFunction` class can be instantiated with 1 or 2 arguments. The following gives the number of input arguments and their interpretation: * 1: `lti` or `dlti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 2: array_like: (numerator, denominator) dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to `None` (continuous-time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- ZerosPolesGain, StateSpace, lti, dlti tf2ss, tf2zpk, tf2sos Notes ----- Changing the value of properties that are not part of the `TransferFunction` system representation (such as the `A`, `B`, `C`, `D` state-space matrices) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_ss()`` before accessing/changing the A, B, C, D system matrices. If (numerator, denominator) is passed in for ``*system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` or ``z^2 + 3z + 5`` would be represented as ``[1, 3, 5]``) Examples -------- Construct the transfer function :math:`H(s) = \frac{s^2 + 3s + 3}{s^2 + 2s + 1}`: >>> from scipy import signal >>> num = [1, 3, 3] >>> den = [1, 2, 1] >>> signal.TransferFunction(num, den) TransferFunctionContinuous( array([1., 3., 3.]), array([1., 2., 1.]), dt: None ) Construct the transfer function :math:`H(z) = \frac{z^2 + 3z + 3}{z^2 + 2z + 1}` with a sampling time of 0.1 seconds: >>> signal.TransferFunction(num, den, dt=0.1) TransferFunctionDiscrete( array([1., 3., 3.]), array([1., 2., 1.]), dt: 0.1 ) c0t|dk(r&t|dtr|djS|turK|j dt jt g|i|Stjtg|i|St||S)z8Handle object conversion if input is an instance of lti.rrrF) rdrPr/rVr getrer3rr2r4s r9r3zTransferFunction.__new__6s v;!  6!96I J!9??$ $ " "zz$'199. 077, ws##r:ct|dtryt| di|d|_d|_t |\|_|_y)z&Initialize the state space LTI system.rN) rPr/r2r>_num_denr numdenrBr6r7r8s r9r>zTransferFunction.__init__KsJ fQi!4 5  "6"  &/$(r:c |jjdt|jdt|jdt|j dS)z7Return representation of the system's transfer function( , , dt:  ))r8rXreprrrrFrEs r9__repr__zTransferFunction.__repr__YsR~~&&'sDHH~cDHH~=/ & r:c|jS)z+Numerator of the `TransferFunction` system.)rrEs r9rzTransferFunction.numbyyr:ct||_t|jjdkDr$|jj\|_|_yd|_d|_yNr)rrrdrshaper@r?)rBrs r9rzTransferFunction.numgsHsO  txx~~  "(, %DL$+DLDKr:c|jS)z-Denominator of the `TransferFunction` system.)rrEs r9rzTransferFunction.denrrr:c$t||_yr)rr)rBrs r9rzTransferFunction.denws sO r:cH|j|_|j|_y)z Copy the parameters of another `TransferFunction` object Parameters ---------- system : `TransferFunction` The `StateSpace` system that is to be copied N)rrrBr6s r9_copyzTransferFunction._copy{s::::r:c,tj|S)z Return a copy of the current `TransferFunction` system. Returns ------- sys : instance of `TransferFunction` The current system (copy) copydeepcopyrEs r9rVzTransferFunction.to_tf}}T""r:chtt|j|ji|jS)z Convert system representation to `ZerosPolesGain`. Returns ------- sys : instance of `ZerosPolesGain` Zeros, poles, gain representation of the current system )r!rrrrIrEs r9rKzTransferFunction.to_zpks.vdhh9/ $ / /r:chtt|j|ji|jSz Convert system representation to `StateSpace`. Returns ------- sys : instance of `StateSpace` State space model of the current system )r"rrrrIrEs r9rQzTransferFunction.to_sss.54884+ MM+ +r:ct|t|z }|dkDr.tjtj||f}||fS|dkr+tjtj| |f}||fS)aChange a transfer function from the variable `z` to `z**-1`. Parameters ---------- num, den: 1d array_like Sequences representing the coefficients of the numerator and denominator polynomials, in order of descending degree of 'z'. That is, ``5z**2 + 3z + 2`` is presented as ``[5, 3, 2]``. Returns ------- num, den: 1d array_like Sequences representing the coefficients of the numerator and denominator polynomials, in order of ascending degree of 'z**-1'. That is, ``5 + 3 z**-1 + 2 z**-2`` is presented as ``[5, 3, 2]``. rrdnphstackrrrdiffs r9 _z_to_zinvzTransferFunction._z_to_zinvsr$3x#c(" !8))RXXd^S12CCxAX))RXXte_c23CCxr:ct|t|z }|dkDr.tj|tj|f}||fS|dkr+tj|tj| f}||fS)aChange a transfer function from the variable `z` to `z**-1`. Parameters ---------- num, den: 1d array_like Sequences representing the coefficients of the numerator and denominator polynomials, in order of ascending degree of 'z**-1'. That is, ``5 + 3 z**-1 + 2 z**-2`` is presented as ``[5, 3, 2]``. Returns ------- num, den: 1d array_like Sequences representing the coefficients of the numerator and denominator polynomials, in order of descending degree of 'z'. That is, ``5z**2 + 3z + 2`` is presented as ``[5, 3, 2]``. rrrs r9 _zinv_to_zzTransferFunction._zinv_to_zsr$3x#c(" !8))S"((4.12CCxAX))S"((D5/23CCxr:)rXrYrZrr3r>rr[rrrrrVrKrQ staticmethodrrr\r]s@r9r r sJV$* 0  ZZ ZZ$$  # / +0r:r ceZdZdZddZy)rea Continuous-time Linear Time Invariant system in transfer function form. Represents the system as the transfer function :math:`H(s)=\sum_{i=0}^N b[N-i] s^i / \sum_{j=0}^M a[M-j] s^j`, where :math:`b` are elements of the numerator `num`, :math:`a` are elements of the denominator `den`, and ``N == len(b) - 1``, ``M == len(a) - 1``. Continuous-time `TransferFunction` systems inherit additional functionality from the `lti` class. Parameters ---------- *system: arguments The `TransferFunction` class can be instantiated with 1 or 2 arguments. The following gives the number of input arguments and their interpretation: * 1: `lti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 2: array_like: (numerator, denominator) See Also -------- ZerosPolesGain, StateSpace, lti tf2ss, tf2zpk, tf2sos Notes ----- Changing the value of properties that are not part of the `TransferFunction` system representation (such as the `A`, `B`, `C`, `D` state-space matrices) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_ss()`` before accessing/changing the A, B, C, D system matrices. If (numerator, denominator) is passed in for ``*system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``) Examples -------- Construct the transfer function :math:`H(s) = \frac{s^2 + 3s + 3}{s^2 + 2s + 1}`: >>> from scipy import signal >>> num = [1, 3, 3] >>> den = [1, 2, 1] >>> signal.TransferFunction(num, den) TransferFunctionContinuous( array([ 1., 3., 3.]), array([ 1., 2., 1.]), dt: None ) Ncdtt|j|jf|||ddd|iS)z Returns the discretized `TransferFunction` system. Parameters: See `cont2discrete` for details. Returns ------- sys: instance of `dlti` and `StateSpace` r|r}NrF)r rrrr{s r9r~z&TransferFunctionContinuous.to_discretesH $((/C/16<5:"<=@R"A'$& ' 'r:rrXrYrZrr~rr:r9reres 9v'r:receZdZdZy)ra Discrete-time Linear Time Invariant system in transfer function form. Represents the system as the transfer function :math:`H(z)=\sum_{i=0}^N b[N-i] z^i / \sum_{j=0}^M a[M-j] z^j`, where :math:`b` are elements of the numerator `num`, :math:`a` are elements of the denominator `den`, and ``N == len(b) - 1``, ``M == len(a) - 1``. Discrete-time `TransferFunction` systems inherit additional functionality from the `dlti` class. Parameters ---------- *system: arguments The `TransferFunction` class can be instantiated with 1 or 2 arguments. The following gives the number of input arguments and their interpretation: * 1: `dlti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 2: array_like: (numerator, denominator) dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to `True` (unspecified sampling time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- ZerosPolesGain, StateSpace, dlti tf2ss, tf2zpk, tf2sos Notes ----- Changing the value of properties that are not part of the `TransferFunction` system representation (such as the `A`, `B`, `C`, `D` state-space matrices) is very inefficient and may lead to numerical inaccuracies. If (numerator, denominator) is passed in for ``*system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g., ``z^2 + 3z + 5`` would be represented as ``[1, 3, 5]``). Examples -------- Construct the transfer function :math:`H(z) = \frac{z^2 + 3z + 3}{z^2 + 2z + 1}` with a sampling time of 0.5 seconds: >>> from scipy import signal >>> num = [1, 3, 3] >>> den = [1, 2, 1] >>> signal.TransferFunction(num, den, dt=0.5) TransferFunctionDiscrete( array([ 1., 3., 3.]), array([ 1., 2., 1.]), dt: 0.5 ) NrXrYrZrrr:r9rr.s <z r:rceZdZdZfdZfdZdZedZejdZedZ e jdZ ed Z e jd Z d Z d Z d ZdZxZS)r!az Linear Time Invariant system class in zeros, poles, gain form. Represents the system as the continuous- or discrete-time transfer function :math:`H(s)=k \prod_i (s - z[i]) / \prod_j (s - p[j])`, where :math:`k` is the `gain`, :math:`z` are the `zeros` and :math:`p` are the `poles`. `ZerosPolesGain` systems inherit additional functionality from the `lti`, respectively the `dlti` classes, depending on which system representation is used. Parameters ---------- *system : arguments The `ZerosPolesGain` class can be instantiated with 1 or 3 arguments. The following gives the number of input arguments and their interpretation: * 1: `lti` or `dlti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 3: array_like: (zeros, poles, gain) dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to `None` (continuous-time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- TransferFunction, StateSpace, lti, dlti zpk2ss, zpk2tf, zpk2sos Notes ----- Changing the value of properties that are not part of the `ZerosPolesGain` system representation (such as the `A`, `B`, `C`, `D` state-space matrices) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_ss()`` before accessing/changing the A, B, C, D system matrices. Examples -------- Construct the transfer function :math:`H(s) = \frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`: >>> from scipy import signal >>> signal.ZerosPolesGain([1, 2], [3, 4], 5) ZerosPolesGainContinuous( array([1, 2]), array([3, 4]), 5, dt: None ) Construct the transfer function :math:`H(z) = \frac{5(z - 1)(z - 2)}{(z - 3)(z - 4)}` with a sampling time of 0.1 seconds: >>> signal.ZerosPolesGain([1, 2], [3, 4], 5, dt=0.1) ZerosPolesGainDiscrete( array([1, 2]), array([3, 4]), 5, dt: 0.1 ) c0t|dk(r&t|dtr|djS|turK|j dt jt g|i|Stjtg|i|St||S)z9Handle object conversion if input is an instance of `lti`rrrF) rdrPr/rKr!rrfr3rr2r4s r9r3zZerosPolesGain.__new__s v;!  6!96I J!9##% % . zz$'/77, .55*ws##r:ct|dtryt| di|d|_d|_d|_|\|_|_|_ y)z)Initialize the zeros, poles, gain system.rNr) rPr/r2r>_zeros_poles_gainrrNgainrs r9r>zZerosPolesGain.__init__sN fQi!4 5  "6"   ,2) DJ r:c |jjdt|jdt|jdt|j dt|j d S)z5Return representation of the `ZerosPolesGain` system.rrrr)r8rXrrrNrrFrEs r9rzZerosPolesGain.__repr__sd~~&&'sDJJ DJJ DII =/  & r:c|jS)z%Zeros of the `ZerosPolesGain` system.)rrEs r9rzZerosPolesGain.zeros{{r:ct||_t|jjdkDr$|jj\|_|_yd|_d|_yr)rrrdrrr@r?)rBrs r9rzZerosPolesGain.zerossM '  tzz 1 $(, (8(8 %DL$+DLDKr:c|jS)z%Poles of the `ZerosPolesGain` system.)rrEs r9rNzZerosPolesGain.polesrr:c$t||_yr)rr)rBrNs r9rNzZerosPolesGain.poless ' r:c|jS)z$Gain of the `ZerosPolesGain` system.rrEs r9rzZerosPolesGain.gainszzr:c||_yrr)rBrs r9rzZerosPolesGain.gains  r:cj|j|_|j|_|j|_y)z Copy the parameters of another `ZerosPolesGain` system. Parameters ---------- system : instance of `ZerosPolesGain` The zeros, poles gain system that is to be copied N)rNrrrs r9rzZerosPolesGain._copys%\\ \\ KK r:c~tt|j|j|ji|j S)z Convert system representation to `TransferFunction`. Returns ------- sys : instance of `TransferFunction` Transfer function of the current system )r rrrNrrIrEs r9rVzZerosPolesGain.to_tfs4  DJJ !J1"&--1 1r:c,tj|S)z Return a copy of the current 'ZerosPolesGain' system. Returns ------- sys : instance of `ZerosPolesGain` The current system (copy) rrEs r9rKzZerosPolesGain.to_zpkrr:c~tt|j|j|ji|j Sr)r"rrrNrrIrEs r9rQzZerosPolesGain.to_ss+s46$**djj$))D+ MM+ +r:)rXrYrZrr3r>rr[rrrNrrrVrKrQr\r]s@r9r!r!osCH$, 3  \\ \\(( [[   1 # +r:r!ceZdZdZddZy)rfa> Continuous-time Linear Time Invariant system in zeros, poles, gain form. Represents the system as the continuous time transfer function :math:`H(s)=k \prod_i (s - z[i]) / \prod_j (s - p[j])`, where :math:`k` is the `gain`, :math:`z` are the `zeros` and :math:`p` are the `poles`. Continuous-time `ZerosPolesGain` systems inherit additional functionality from the `lti` class. Parameters ---------- *system : arguments The `ZerosPolesGain` class can be instantiated with 1 or 3 arguments. The following gives the number of input arguments and their interpretation: * 1: `lti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 3: array_like: (zeros, poles, gain) See Also -------- TransferFunction, StateSpace, lti zpk2ss, zpk2tf, zpk2sos Notes ----- Changing the value of properties that are not part of the `ZerosPolesGain` system representation (such as the `A`, `B`, `C`, `D` state-space matrices) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_ss()`` before accessing/changing the A, B, C, D system matrices. Examples -------- Construct the transfer function :math:`H(s)=\frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`: >>> from scipy import signal >>> signal.ZerosPolesGain([1, 2], [3, 4], 5) ZerosPolesGainContinuous( array([1, 2]), array([3, 4]), 5, dt: None ) Ncztt|j|j|jf|||ddd|iS)z Returns the discretized `ZerosPolesGain` system. Parameters: See `cont2discrete` for details. Returns ------- sys: instance of `dlti` and `ZerosPolesGain` rNrrF)r!rrrNrr{s r9r~z$ZerosPolesGainContinuous.to_discretemsM DJJ DII>"(!&(),-   r:rrrr:r9rfrf9s 1fr:rfceZdZdZy)ra, Discrete-time Linear Time Invariant system in zeros, poles, gain form. Represents the system as the discrete-time transfer function :math:`H(z)=k \prod_i (z - q[i]) / \prod_j (z - p[j])`, where :math:`k` is the `gain`, :math:`q` are the `zeros` and :math:`p` are the `poles`. Discrete-time `ZerosPolesGain` systems inherit additional functionality from the `dlti` class. Parameters ---------- *system : arguments The `ZerosPolesGain` class can be instantiated with 1 or 3 arguments. The following gives the number of input arguments and their interpretation: * 1: `dlti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 3: array_like: (zeros, poles, gain) dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to `True` (unspecified sampling time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- TransferFunction, StateSpace, dlti zpk2ss, zpk2tf, zpk2sos Notes ----- Changing the value of properties that are not part of the `ZerosPolesGain` system representation (such as the `A`, `B`, `C`, `D` state-space matrices) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_ss()`` before accessing/changing the A, B, C, D system matrices. Examples -------- Construct the transfer function :math:`H(s) = \frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`: >>> from scipy import signal >>> signal.ZerosPolesGain([1, 2], [3, 4], 5) ZerosPolesGainContinuous( array([1, 2]), array([3, 4]), 5, dt: None ) Construct the transfer function :math:`H(z) = \frac{5(z - 1)(z - 2)}{(z - 3)(z - 4)}` with a sampling time of 0.1 seconds: >>> signal.ZerosPolesGain([1, 2], [3, 4], 5, dt=0.1) ZerosPolesGainDiscrete( array([1, 2]), array([3, 4]), 5, dt: 0.1 ) Nrrr:r9rrsAD r:rcXeZdZdZdZdZfdZfdZdZdZ dZ d Z d Z d Z d Zd ZdZdZedZej(dZedZej(dZedZej(dZedZej(dZdZdZdZdZxZS)r"ar Linear Time Invariant system in state-space form. Represents the system as the continuous-time, first order differential equation :math:`\dot{x} = A x + B u` or the discrete-time difference equation :math:`x[k+1] = A x[k] + B u[k]`. `StateSpace` systems inherit additional functionality from the `lti`, respectively the `dlti` classes, depending on which system representation is used. Parameters ---------- *system: arguments The `StateSpace` class can be instantiated with 1 or 4 arguments. The following gives the number of input arguments and their interpretation: * 1: `lti` or `dlti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 4: array_like: (A, B, C, D) dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to `None` (continuous-time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- TransferFunction, ZerosPolesGain, lti, dlti ss2zpk, ss2tf, zpk2sos Notes ----- Changing the value of properties that are not part of the `StateSpace` system representation (such as `zeros` or `poles`) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain. Examples -------- >>> from scipy import signal >>> import numpy as np >>> a = np.array([[0, 1], [0, 0]]) >>> b = np.array([[0], [1]]) >>> c = np.array([[1, 0]]) >>> d = np.array([[0]]) >>> sys = signal.StateSpace(a, b, c, d) >>> print(sys) StateSpaceContinuous( array([[0, 1], [0, 0]]), array([[0], [1]]), array([[1, 0]]), array([[0]]), dt: None ) >>> sys.to_discrete(0.1) StateSpaceDiscrete( array([[1. , 0.1], [0. , 1. ]]), array([[0.005], [0.1 ]]), array([[1, 0]]), array([[0]]), dt: 0.1 ) >>> a = np.array([[1, 0.1], [0, 1]]) >>> b = np.array([[0.005], [0.1]]) >>> signal.StateSpace(a, b, c, d, dt=0.1) StateSpaceDiscrete( array([[1. , 0.1], [0. , 1. ]]), array([[0.005], [0.1 ]]), array([[1, 0]]), array([[0]]), dt: 0.1 ) gY@Nc0t|dk(r&t|dtr|djS|turK|j dt jt g|i|Stjtg|i|St||S)z4Create new StateSpace object and settle inheritance.rrrF) rdrPr/rQr"rrgr3rr2r4s r9r3zStateSpace.__new__s v;!  6!96I J!9??$ $ * zz$'+334HG5;G?EGG*112DE39E=CEEws##r:ct|dtryt| di|d|_d|_d|_d|_t|\|_ |_ |_ |_ y)z+Initialize the state space lti/dlti system.rNr) rPr/r2r>_A_B_C_DrABCDrs r9r>zStateSpace.__init__1s` fQi!4 5  "6")7)@&r:c |jjdt|jdt|jdt|j dt|j dt|jd S)z1Return representation of the `StateSpace` system.rrrr)r8rXrrrrrrFrEs r9rzStateSpace.__repr__Asn~~&&'sDFF|nCDFF|nCDFF|nCDFF|n=/  & r:ct|ttjztzt ztj ztzSr)rPr"rndarrayfloatcomplexnumberintrBothers r9_check_binop_otherzStateSpace._check_binop_otherLs:%bjj!85!@7!J"$))",.1"23 3r:c |j|stSt|trt |t |urtS|j |j k7r t d|jjd}|jjd}tjtj|jtj|j|jftjt||f|jff}tjtj|j|j |jf}tj|jtj|j |jf}tj|j |j }nX|j}tj|j|}|j}tj|j |}tj"|j$|j$|j$|j$}ttj&||tj&||tj&||tj&||fi|j(S)a] Post-multiply another system or a scalar Handles multiplication of systems in the sense of a frequency domain multiplication. That means, given two systems E1(s) and E2(s), their multiplication, H(s) = E1(s) * E2(s), means that applying H(s) to U(s) is equivalent to first applying E2(s), and then E1(s). Notes ----- For SISO systems the order of system application does not matter. However, for MIMO systems, where the two systems are matrices, the order above ensures standard Matrix multiplication rules apply. z,Cannot multiply systems with different `dt`.rdtype)rNotImplementedrPr"typerF TypeErrorrrrvstackrrrrrr result_typerrrI) rBrn1n2abcd common_dtypes r9__mul__zStateSpace.__mul__Ps&&u-! ! eZ (E{$t*,%%ww%((" NOOaBq!B 299dffbffTVVUWW.E%FG99eRHouww%?@BCA 266$&&%''2EGG<=A 466266$&&%''#:;rrr rrrrrrr!r[rrrrrrrVrKrQr\r]s@r9r"r"sSlO$$A  3:+x+$M/+b$ # & %XX))XX''XX''XX)) C$B$ #r:r"ceZdZdZddZy)rga, Continuous-time Linear Time Invariant system in state-space form. Represents the system as the continuous-time, first order differential equation :math:`\dot{x} = A x + B u`. Continuous-time `StateSpace` systems inherit additional functionality from the `lti` class. Parameters ---------- *system: arguments The `StateSpace` class can be instantiated with 1 or 3 arguments. The following gives the number of input arguments and their interpretation: * 1: `lti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 4: array_like: (A, B, C, D) See Also -------- TransferFunction, ZerosPolesGain, lti ss2zpk, ss2tf, zpk2sos Notes ----- Changing the value of properties that are not part of the `StateSpace` system representation (such as `zeros` or `poles`) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain. Examples -------- >>> import numpy as np >>> from scipy import signal >>> a = np.array([[0, 1], [0, 0]]) >>> b = np.array([[0], [1]]) >>> c = np.array([[1, 0]]) >>> d = np.array([[0]]) >>> sys = signal.StateSpace(a, b, c, d) >>> print(sys) StateSpaceContinuous( array([[0, 1], [0, 0]]), array([[0], [1]]), array([[1, 0]]), array([[0]]), dt: None ) Nctt|j|j|j|j f|||ddd|iS)z Returns the discretized `StateSpace` system. Parameters: See `cont2discrete` for details. Returns ------- sys: instance of `dlti` and `StateSpace` rNrrF)r"rrrrrr{s r9r~z StateSpaceContinuous.to_discretesR=$&&$&&$&&$&&)I)+06/467:r;! ! !r:rrrr:r9rgrgYs 6p!r:rgceZdZdZy)ra Discrete-time Linear Time Invariant system in state-space form. Represents the system as the discrete-time difference equation :math:`x[k+1] = A x[k] + B u[k]`. `StateSpace` systems inherit additional functionality from the `dlti` class. Parameters ---------- *system: arguments The `StateSpace` class can be instantiated with 1 or 3 arguments. The following gives the number of input arguments and their interpretation: * 1: `dlti` system: (`StateSpace`, `TransferFunction` or `ZerosPolesGain`) * 4: array_like: (A, B, C, D) dt: float, optional Sampling time [s] of the discrete-time systems. Defaults to `True` (unspecified sampling time). Must be specified as a keyword argument, for example, ``dt=0.1``. See Also -------- TransferFunction, ZerosPolesGain, dlti ss2zpk, ss2tf, zpk2sos Notes ----- Changing the value of properties that are not part of the `StateSpace` system representation (such as `zeros` or `poles`) is very inefficient and may lead to numerical inaccuracies. It is better to convert to the specific system representation first. For example, call ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain. Examples -------- >>> import numpy as np >>> from scipy import signal >>> a = np.array([[1, 0.1], [0, 1]]) >>> b = np.array([[0.005], [0.1]]) >>> c = np.array([[1, 0]]) >>> d = np.array([[0]]) >>> signal.StateSpace(a, b, c, d, dt=0.1) StateSpaceDiscrete( array([[ 1. , 0.1], [ 0. , 1. ]]), array([[ 0.005], [ 0.1 ]]), array([[1, 0]]), array([[0]]), dt: 0.1 ) Nrrr:r9rrs 9t r:rc x t|tr|j}n1t|tr t dt|j}t |}t |jdk7r tdttj|j|j|j|jf\}}}} |jd} |jd} |j } | t#| |jj$}tj&| | f|jj$} |ddk(r|| d<nE|ddkDr2t)|t+j,t/||dz| d<n td|duxs6t|t0t2zxr|dk(xstj4| }| dk(rCt7| |j8z}|s|t7|| j8zz }||t7| fS|d|dz }tj:tj<||s td|rgt+j,|j8|z}t?d| D]}| |dz |z| |<t7| |j8z}||t7| fSt |}|j@dk(r|ddtjBf}|jd| k7r td |jd| k7r td |stjDtjF||z||zgtj"| | | zfg}t+j,|j8}|d| d| f}|| dd| f}t?d| D]}| |dz |z||dz |zz| |<n!tjDtjF||z||ztj"| | fgtjFtj"| | | zftjH| gtj"| | d | zzfg}t+j,|j8}|d| d| f}|| | zdd| f}|| | | zd| f|z }t?d| D]%}| |dz |z||dz |zz|||zz| |<'t7| |j8zt7|| j8zz}||t7| fS) al Simulate output of a continuous-time linear system. Parameters ---------- system : an instance of the LTI class or a tuple describing the system. The following gives the number of elements in the tuple and the interpretation: * 1: (instance of `lti`) * 2: (num, den) * 3: (zeros, poles, gain) * 4: (A, B, C, D) U : array_like An input array describing the input at each time `T` (interpolation is assumed between given times). If there are multiple inputs, then each column of the rank-2 array represents an input. If U = 0 or None, a zero input is used. T : array_like The time steps at which the input is defined and at which the output is desired. Must be nonnegative, increasing, and equally spaced. X0 : array_like, optional The initial conditions on the state vector (zero by default). interp : bool, optional Whether to use linear (True, the default) or zero-order-hold (False) interpolation for the input array. Returns ------- T : 1D ndarray Time values for the output. yout : 1D ndarray System response. xout : ndarray Time evolution of the state vector. Notes ----- If (num, den) is passed in for ``system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``). Examples -------- We'll use `lsim` to simulate an analog Bessel filter applied to a signal. >>> import numpy as np >>> from scipy.signal import bessel, lsim >>> import matplotlib.pyplot as plt Create a low-pass Bessel filter with a cutoff of 12 Hz. >>> b, a = bessel(N=5, Wn=2*np.pi*12, btype='lowpass', analog=True) Generate data to which the filter is applied. >>> t = np.linspace(0, 1.25, 500, endpoint=False) The input signal is the sum of three sinusoidal curves, with frequencies 4 Hz, 40 Hz, and 80 Hz. The filter should mostly eliminate the 40 Hz and 80 Hz components, leaving just the 4 Hz signal. >>> u = (np.cos(2*np.pi*4*t) + 0.6*np.sin(2*np.pi*40*t) + ... 0.5*np.cos(2*np.pi*80*t)) Simulate the filter with `lsim`. >>> tout, yout, xout = lsim((b, a), U=u, T=t) Plot the result. >>> plt.plot(t, u, 'r', alpha=0.5, linewidth=1, label='input') >>> plt.plot(tout, yout, 'k', linewidth=1.5, label='output') >>> plt.legend(loc='best', shadow=True, framealpha=1) >>> plt.grid(alpha=0.3) >>> plt.xlabel('t') >>> plt.show() In a second example, we simulate a double integrator ``y'' = u``, with a constant input ``u = 1``. We'll use the state space representation of the integrator. >>> from scipy.signal import lti >>> A = np.array([[0.0, 1.0], [0.0, 0.0]]) >>> B = np.array([[0.0], [1.0]]) >>> C = np.array([[1.0, 0.0]]) >>> D = 0.0 >>> system = lti(A, B, C, D) `t` and `u` define the time and input signal for the system to be simulated. >>> t = np.linspace(0, 5, num=50) >>> u = np.ones_like(t) Compute the simulation, and then plot `y`. As expected, the plot shows the curve ``y = 0.5*t**2``. >>> tout, y, x = lsim(system, u, t) >>> plt.plot(t, y) >>> plt.grid(alpha=0.3) >>> plt.xlabel('t') >>> plt.show() z3lsim can only be used with continuous-time systems.rzT must be a rank-1 array.rNz Initial time must be nonnegativez"Time steps are not equally spaced.z5U must have the same number of rows as elements in T.z(System does not define that many inputs.ra)%rPrrRrAttributeErrorrrdrrhmaprrrrrrsizerremptyrrexpmrrranyrrnallcloserranger newaxisrridentity)r6rrrnrminterpsysrrrrn_statesn_inputsn_stepsxoutno_inputyoutrFexpAT_dtiMexpMTAdBdBd1Bd0s r9r#r#sX&#mmo FD !() )6l!!#1 A 177|q455RZZ#%%suu!=>JAq!QwwqzHwwqzHffG z 8SUU[[ ) 88Wh' 5DtqyQ 1b&++ilQqT&9:;Q;<<T AsU{+7RFF1I  !|taccz" GAG$ $D$ %% 1!B ;;rwwqz2 &=>>;;qssRx(q'" +A1Q3i(*DG +taccz"$ %% 1 Avv{ am wwqzW-. . wwqzXCDD  IIryy!b&!b&!12xx8h+> ?@B C ACC  9H9ixi' ( 89ixi' (q'" 3A1Q3i"nq1v{2DG 3 IIryy!b&!b&"$((Hh+?"@"BCyy"((Hh6I+J"K"$++h"7"9:xx8a(l+B CD F G  ACC  9H9ixi' (HX%&  12HX00)8);>! D CT OACx  qBa"fa A Hr:ct|tr|j}n1t|tr t dt|j}|t |j }nt |j |z}|d}|t|j|}n t|}t|d||d\}}}||fS)aImpulse response of continuous-time system. Parameters ---------- system : an instance of the LTI class or a tuple of array_like describing the system. The following gives the number of elements in the tuple and the interpretation: * 1 (instance of `lti`) * 2 (num, den) * 3 (zeros, poles, gain) * 4 (A, B, C, D) X0 : array_like, optional Initial state-vector. Defaults to zero. T : array_like, optional Time points. Computed if not given. N : int, optional The number of time points to compute (if `T` is not given). Returns ------- T : ndarray A 1-D array of time points. yout : ndarray A 1-D array containing the impulse response of the system (except for singularities at zero). Notes ----- If (num, den) is passed in for ``system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``). Examples -------- Compute the impulse response of a second order system with a repeated root: ``x''(t) + 2*x'(t) + x(t) = u(t)`` >>> from scipy import signal >>> system = ([1.0], [1.0, 2.0, 1.0]) >>> t, y = signal.impulse(system) >>> import matplotlib.pyplot as plt >>> plt.plot(t, y) z6impulse can only be used with continuous-time systems.rr7F)rB) rPrrRrr8rrr[rrr#)r6rmrnrirCX_hs r9r$r$s`&#mmo FD !() )6l!!# z CEEN CEEBJ y y #CEE1 - AJ3Aq/GAq! a4Kr:c~t|tr|j}n1t|tr t dt|j}|d}|t |j |}n t|}t|j|j j}t||||d}|d|dfS)a?Step response of continuous-time system. Parameters ---------- system : an instance of the LTI class or a tuple of array_like describing the system. The following gives the number of elements in the tuple and the interpretation: * 1 (instance of `lti`) * 2 (num, den) * 3 (zeros, poles, gain) * 4 (A, B, C, D) X0 : array_like, optional Initial state-vector (default is zero). T : array_like, optional Time points (computed if not given). N : int, optional Number of time points to compute if `T` is not given. Returns ------- T : 1D ndarray Output time points. yout : 1D ndarray Step response of system. Notes ----- If (num, den) is passed in for ``system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``). Examples -------- >>> from scipy import signal >>> import matplotlib.pyplot as plt >>> lti = signal.lti([1.0], [1.0, 1.0]) >>> t, y = signal.step(lti) >>> plt.plot(t, y) >>> plt.xlabel('Time [s]') >>> plt.ylabel('Amplitude') >>> plt.title('Step response for 1. Order Lowpass') >>> plt.grid() z3step can only be used with continuous-time systems.rF)rmrBrr) rPrrRrr8r[rrrrrr#)r6rmrnrirCrrrXs r9r%r%sb&#mmo FD !() )6l!!#y y #CEE1 - AJ QWWceekk"A Qb /D 7DG r:ct|||\}}dtjt|z}tjtj |j |jdztjz }|||fS)a| Calculate Bode magnitude and phase data of a continuous-time system. Parameters ---------- system : an instance of the LTI class or a tuple describing the system. The following gives the number of elements in the tuple and the interpretation: * 1 (instance of `lti`) * 2 (num, den) * 3 (zeros, poles, gain) * 4 (A, B, C, D) w : array_like, optional Array of frequencies (in rad/s). Magnitude and phase data is calculated for every value in this array. If not given a reasonable set will be calculated. n : int, optional Number of frequency points to compute if `w` is not given. The `n` frequencies are logarithmically spaced in an interval chosen to include the influence of the poles and zeros of the system. Returns ------- w : 1D ndarray Frequency array [rad/s] mag : 1D ndarray Magnitude array [dB] phase : 1D ndarray Phase array [deg] Notes ----- If (num, den) is passed in for ``system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``). .. versionadded:: 0.11.0 Examples -------- >>> from scipy import signal >>> import matplotlib.pyplot as plt >>> sys = signal.TransferFunction([1], [1, 1]) >>> w, mag, phase = signal.bode(sys) >>> plt.figure() >>> plt.semilogx(w, mag) # Bode magnitude plot >>> plt.figure() >>> plt.semilogx(w, phase) # Bode phase plot >>> plt.show() ru4@gf@) r'rlog10rWunwraparctan2imagrpi)r6rvrwymagphases r9r&r&`sip Fa1 %DAq #a&! !C IIbjj0 1E 9BEE AE c5=r:cPt|tr+t|ttzr|}nB|j }n1t|t r t dt|j }|jdk7s|jdk7r td||}n|}t|tr7t|jj|j|\}}||fSt|tr0t|j|j |j"|\}}|fS)a|Calculate the frequency response of a continuous-time system. Parameters ---------- system : an instance of the `lti` class or a tuple describing the system. The following gives the number of elements in the tuple and the interpretation: * 1 (instance of `lti`) * 2 (num, den) * 3 (zeros, poles, gain) * 4 (A, B, C, D) w : array_like, optional Array of frequencies (in rad/s). Magnitude and phase data is calculated for every value in this array. If not given, a reasonable set will be calculated. n : int, optional Number of frequency points to compute if `w` is not given. The `n` frequencies are logarithmically spaced in an interval chosen to include the influence of the poles and zeros of the system. Returns ------- w : 1D ndarray Frequency array [rad/s] H : 1D ndarray Array of complex magnitude values Notes ----- If (num, den) is passed in for ``system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``). Examples -------- Generating the Nyquist plot of a transfer function >>> from scipy import signal >>> import matplotlib.pyplot as plt Construct the transfer function :math:`H(s) = \frac{5}{(s-1)^3}`: >>> s1 = signal.ZerosPolesGain([], [1, 1, 1], [5]) >>> w, H = signal.freqresp(s1) >>> plt.figure() >>> plt.plot(H.real, H.imag, "b") >>> plt.plot(H.real, -H.imag, "r") >>> plt.show() z7freqresp can only be used with continuous-time systems.rz@freqresp() requires a SISO (single input, single output) system.)worN)rPrr r!rTrr8r?r@rhr rravelrr rrNr)r6rvrwrCrlr_s r9r'r'sl&# f.? @C.."C FD !() )6l""$ zzQ#++*+, , }#'(SWW]]_cggD91 a4K C (CIIsxxdC1 a4Kr:ceZdZdZy)Bunchc :|jj|yr)__dict__update)rBkwdss r9r>zBunch.__init__s T"r:N)rXrYrZr>rr:r9roros#r:roctj|}|jdkDr tdt |}|jdkDr td|jdkDr td|j d|j dk7r tdt ||j dkDr'td|j dd t |t ||j dkr'td t |d |j dtjj|}|D]}t||k(|kDstd t}|d vr td|dk(r/t}ttj|s td|dkr td|dkDr td||fS)z Check the poles come in complex conjugate pairs Check shapes of A, B and poles are compatible. Check the method chosen is compatible with provided poles Return update method to use and ordered poles rzPoles must be a 1D array like.razA must be a 2D array/matrix.zB must be a 2D array/matrixrzA must be squarezmaximum number of poles is z but you asked for znumber of poles is z but you should provide zFat least one of the requested pole is repeated more than rank(B) times)KNV0YTz0The method keyword must be one of 'YT' or 'KNV0'ruz'Complex poles are not supported by KNV0z#maxiter must be at least equal to 1zrtol can not be greater than 1)rrr rh_order_complex_polesrrdr matrix_ranksum_YT_loop _KNV0_loopallisreal) rrrNr|rtolmaxiterrYp update_loops r9 _valid_inputsrs JJu E zzA~9::  'Evvz788vvz677wwqzQWWQZ+,, 5zAGGAJ)!''!*5HU U   5zAGGAJ!#e*-Eaggaj\ R   a A 8 qEz?Q 78 88 K ]"KLL  299U#$FG G{>?? ax9::  r:ctj|tj|}g}tj|tj|dkD]@}tj||vs|j |tj|fBtj ||f}|jdt|k7r td|S)z Check we have complex conjugates pairs and reorder P according to YT, ie real_poles, complex_i, conjugate complex_i, .... The lexicographic sort on the complex poles is added to help the user to compare sets of poles. rz-Complex poles must come with their conjugates) rsortr}rfconjextendrrrdrh)rN ordered_polesim_polesrs r9rwrw1 sGGE"))E"234MH WWU2775>A-. /- 771:  OOQ O ,-II}h78M {{1~]++HII r:c^tj||d}t|d\}}tj||||j}tj||dddf} tj | ds,| tj j| z } | |dd|f<yy)z Algorithm "KNV0" Kautsky et Al. Robust pole assignment in linear state feedback, Int journal of Control 1985, vol 41 p 1129->1155 https://la.epfl.ch/files/content/sites/la/files/ users/105941/public/KautskyNicholsDooren raxisfullmodeNrr)rdeletes_qrrrnr>rnorm) rker_poletransfer_matrixjrNtransfer_matrix_not_jQR mat_ker_pjyjxjs r9_KNV0rE sIIoqqA %F 3DAq Xa[]]3J  AaeH %B ;;r1   r" " "1 r:c X|dddtjf}|dddtjf}tjtj||jtj||jtj||jz ||}tjj |\}} } |jddddtjf\} } | ddddtjf\} }tj |dd|tjf|dd|tjff}tj| d| dsJtj||| }tj||| }tj ||f}ntj tj||tj||jftjtj||j||ff}tj tj| | ftj| |ff}tj||}tjtj||j|}tj|dstjd|ztjj|z }|d|dd|fjddf|dd|f<||dd|fjdddf|dd|f<y|d|dd|fjddf|dd|f<||dd|fjdddf|dd|f<y)zM Applies algorithm from YT section 6.1 page 19 related to real pairs Nrrarr) rr@rrnrsvdrr>rrrsqrtr)rrrrKrrvmumsmvmmu1mu2nu1nu2&transfer_matrix_j_mo_transfer_matrix_jker_pole_imo_mu1ker_pole_i_nu1ker_pole_mu_nu ker_pole_ij mu_nu_matrixtransfer_matrix_ijs r9_YT_realrt sP !R A !R A rvvhqkmmRVVAqss^ q!##&!! &Aq!JBBttBQB2::%&HC"1"a#$HC.0YY Aq"**, - Aq"**, -8/.0* ;;r!ube $66(1+s3 S1$4n#EFii " 8A;+-88HQK4E4E+F+H!I " 288HQK4E4E+F4rrrrf)rrrrKruruirrre_vale_vec e_val_idxrrr ker_pole_mumu1_mu2_matrixtransfer_matrix_i_js r9 _YT_complexr s AaRZZ'( (B AaRZZ'( (B RU A1+K rvvbggkmm,bffQ .Evvbggaj!##&/'()4 6A99==#LE5 266%=)I 9R="**, -C 9R="**, -C 1bjj() ?1a+ ,, -+ ;;rvveIbM23 ffU9R=%9: <ff[#. C:.ff[.9 && RWW[]]5K!LDF ;;*A .2 IINN. / 0 "(;AqD(A B1 "(;AqD(A B1!# AqD(9 :1 " AqD(9 :1r:cP |tj|jd}|dz}|dkDr|gdgg}nggg}tj|dzt |dzd} tjd||dzz} |dj d| z|dj d| zdz|dj | |dj | dztjd|dz} |dj d| zdz |dj d| z|dk(r@tj|dr(|dj d|dj d|dj | |dj | dztjd||dzz} | D]A} td|dzD]-} |dj | |dj | | z/C|dk(r@tj|dr(|dj d|dj d|dj | |dj | dztjd||dzz} | D]S} t|dz|dzD]<} | | z}||kDr| | z|z }|dj | |dj |>U|dk(r@tj|dr(|dj d|dj d|dj | |dj | dztd|dzD]-} |dj | |dj | |z/|dk(r@tj|dr(|dj d|dj d|dj | |dj | dztj|jdz }d}d}||kr|stjtjj|}|D]\} } | | k(r;| dk(sJdtj|| sJdt|||| |Ftj|| | fd}t|d \}}tj|| r;tj|| sJd t!|zt#|||| | tj|| sJd t!|zt%|||| | tj&tj(tj*dtjtjj|f}tj||z |z }||kr-|tj(tj*dkDrd }|dz }||kr|s||fS) z Algorithm "YT" Tits, Yang. Globally Convergent Algorithms for Robust Pole Assignment by State Feedback https://hdl.handle.net/1903/5598 The poles P have to be sorted accordingly to section 6.2 page 20 rrarFzi!=0 for KNV call in YTzcalling KNV on a complex polerrrz"mixing real and complex in YT_realT)rr}rarangerdrappendr?arrayrnrWrdetrrrstrrrmaxrspacing)rrrNrrr~nb_realhnb update_orderr_compr_pr_jrrKidx_1stopnb_trydet_transfer_matrixbtransfer_matrix_not_i_jrr^det_transfer_matrixcur_rtols r9rzrz sBIIe$%++A.G Q,C { A3' 2w YYwqy#e*Q, 2F ))As7Q; 'CO1S5!O1S57#O6"O6!8$ ))As1u CO1S57#O1S5! axBIIeAh'Qq!Qq!O6"O6!8$ ))As7Q; 'C (q#a% (A O " "1 % O " "1Q3 ' ((  axBIIeAh'Qq!Qq!O6"O6!8$ ))As7Q; 'C *s1ugai( *AaCEw!G  O " "1 % O " "5 )  ** axBIIeAh'Qq!Qq!O6"O6!8$ 1c!e_&Qq!Qqu%& axBIIeAh'Qq!Qq!O6"O6!8$88L)++A-L D F 7 4!vvbiimmO&DE  DDAqAvAv888vyyq*K,KK*a?Au=*,))OaV9:+<'3&A199U1X&99U1X.21%'*5z122.Xq/1a@IIeAh//22%'*5z222/!_aC- D0!ffbggbjjm&<"$&&)G"H&JK66 !"  ! d?2RWWRZZ]5KKD! G 7 4H 6 !!r:crd}d}||kr)|s&tjtjj|}t |j dD]} t |||| |tjtjtjdtjtjj|f} tj| |z | z } | |kr-| tjtjdkDrd}|dz }||kr|s&| |fS)zI Loop over all poles one by one and apply KNV method 0 algorithm FrrT) rrWrrr?rrrrr) rrrNrrr~rrrrrrs r9r{r{c s  D F 7 4!vvbiimmO&DEqwwqz" :A !X5 9 :!ffbggbjjm&<"$&&)G"H&JK66.1EE*+, d?2RWWRZZ]5KKD!  7 4 6 !!r:c B t||||||\}}d}d}t|d\} } tjj |} | ddd| f} | dd| df} | d| ddf} |j d| k(rLtj |j }d}||j dkr||}tj||||f<tj|r`tj| |||dzf<tj|||dz|dzf<tj|||dz|f<|dz }|dz }||j dkrtjj|||z dd}tj|j d}tj}tj}ng}d}t|j dD]n}|rd} tj| j|||tj|j dzz j}t|d\}}|dd|j ddf}tj |d ddtj"f}|tjj%|z }tj||rStj&tj|tj|g}|j)||gd }n|j+||dk(r|}Xtj&|f}q| dkDr8||||||\}}}|s%|dkDr d |d |d }t-j.|dj1t2}d}||j ddz kr}tj||rI|dd|fj5}|dd|dzf}|d|zz |dd|f<|d|zz|dd|dzf<|dz }|dz }||j ddz kr} tjj7|jtjtj8||jj}tjj7| tj| j||z }| }tj|}t?}!||!_ tCtjjE|tj||z d|!_#||!_$||!_%||!_&||!_'|!S#tjj:$r} t=d| d} ~ wwxYw)a Compute K such that eigenvalues (A - dot(B, K))=poles. K is the gain matrix such as the plant described by the linear system ``AX+BU`` will have its closed-loop poles, i.e the eigenvalues ``A - B*K``, as close as possible to those asked for in poles. SISO, MISO and MIMO systems are supported. Parameters ---------- A, B : ndarray State-space representation of linear system ``AX + BU``. poles : array_like Desired real poles and/or complex conjugates poles. Complex poles are only supported with ``method="YT"`` (default). method: {'YT', 'KNV0'}, optional Which method to choose to find the gain matrix K. One of: - 'YT': Yang Tits - 'KNV0': Kautsky, Nichols, Van Dooren update method 0 See References and Notes for details on the algorithms. rtol: float, optional After each iteration the determinant of the eigenvectors of ``A - B*K`` is compared to its previous value, when the relative error between these two values becomes lower than `rtol` the algorithm stops. Default is 1e-3. maxiter: int, optional Maximum number of iterations to compute the gain matrix. Default is 30. Returns ------- full_state_feedback : Bunch object full_state_feedback is composed of: gain_matrix : 1-D ndarray The closed loop matrix K such as the eigenvalues of ``A-BK`` are as close as possible to the requested poles. computed_poles : 1-D ndarray The poles corresponding to ``A-BK`` sorted as first the real poles in increasing order, then the complex conjugates in lexicographic order. requested_poles : 1-D ndarray The poles the algorithm was asked to place sorted as above, they may differ from what was achieved. X : 2-D ndarray The transfer matrix such as ``X * diag(poles) = (A - B*K)*X`` (see Notes) rtol : float The relative tolerance achieved on ``det(X)`` (see Notes). `rtol` will be NaN if it is possible to solve the system ``diag(poles) = (A - B*K)``, or 0 when the optimization algorithms can't do anything i.e when ``B.shape[1] == 1``. nb_iter : int The number of iterations performed before converging. `nb_iter` will be NaN if it is possible to solve the system ``diag(poles) = (A - B*K)``, or 0 when the optimization algorithms can't do anything i.e when ``B.shape[1] == 1``. Notes ----- The Tits and Yang (YT), [2]_ paper is an update of the original Kautsky et al. (KNV) paper [1]_. KNV relies on rank-1 updates to find the transfer matrix X such that ``X * diag(poles) = (A - B*K)*X``, whereas YT uses rank-2 updates. This yields on average more robust solutions (see [2]_ pp 21-22), furthermore the YT algorithm supports complex poles whereas KNV does not in its original version. Only update method 0 proposed by KNV has been implemented here, hence the name ``'KNV0'``. KNV extended to complex poles is used in Matlab's ``place`` function, YT is distributed under a non-free licence by Slicot under the name ``robpole``. It is unclear and undocumented how KNV0 has been extended to complex poles (Tits and Yang claim on page 14 of their paper that their method can not be used to extend KNV to complex poles), therefore only YT supports them in this implementation. As the solution to the problem of pole placement is not unique for MIMO systems, both methods start with a tentative transfer matrix which is altered in various way to increase its determinant. Both methods have been proven to converge to a stable solution, however depending on the way the initial transfer matrix is chosen they will converge to different solutions and therefore there is absolutely no guarantee that using ``'KNV0'`` will yield results similar to Matlab's or any other implementation of these algorithms. Using the default method ``'YT'`` should be fine in most cases; ``'KNV0'`` is only provided because it is needed by ``'YT'`` in some specific cases. Furthermore ``'YT'`` gives on average more robust results than ``'KNV0'`` when ``abs(det(X))`` is used as a robustness indicator. [2]_ is available as a technical report on the following URL: https://hdl.handle.net/1903/5598 References ---------- .. [1] J. Kautsky, N.K. Nichols and P. van Dooren, "Robust pole assignment in linear state feedback", International Journal of Control, Vol. 41 pp. 1129-1155, 1985. .. [2] A.L. Tits and Y. Yang, "Globally convergent algorithms for robust pole assignment by state feedback", IEEE Transactions on Automatic Control, Vol. 41, pp. 1432-1452, 1996. Examples -------- A simple example demonstrating real pole placement using both KNV and YT algorithms. This is example number 1 from section 4 of the reference KNV publication ([1]_): >>> import numpy as np >>> from scipy import signal >>> import matplotlib.pyplot as plt >>> A = np.array([[ 1.380, -0.2077, 6.715, -5.676 ], ... [-0.5814, -4.290, 0, 0.6750 ], ... [ 1.067, 4.273, -6.654, 5.893 ], ... [ 0.0480, 4.273, 1.343, -2.104 ]]) >>> B = np.array([[ 0, 5.679 ], ... [ 1.136, 1.136 ], ... [ 0, 0, ], ... [-3.146, 0 ]]) >>> P = np.array([-0.2, -0.5, -5.0566, -8.6659]) Now compute K with KNV method 0, with the default YT method and with the YT method while forcing 100 iterations of the algorithm and print some results after each call. >>> fsf1 = signal.place_poles(A, B, P, method='KNV0') >>> fsf1.gain_matrix array([[ 0.20071427, -0.96665799, 0.24066128, -0.10279785], [ 0.50587268, 0.57779091, 0.51795763, -0.41991442]]) >>> fsf2 = signal.place_poles(A, B, P) # uses YT method >>> fsf2.computed_poles array([-8.6659, -5.0566, -0.5 , -0.2 ]) >>> fsf3 = signal.place_poles(A, B, P, rtol=-1, maxiter=100) >>> fsf3.X array([[ 0.52072442+0.j, -0.08409372+0.j, -0.56847937+0.j, 0.74823657+0.j], [-0.04977751+0.j, -0.80872954+0.j, 0.13566234+0.j, -0.29322906+0.j], [-0.82266932+0.j, -0.19168026+0.j, -0.56348322+0.j, -0.43815060+0.j], [ 0.22267347+0.j, 0.54967577+0.j, -0.58387806+0.j, -0.40271926+0.j]]) The absolute value of the determinant of X is a good indicator to check the robustness of the results, both ``'KNV0'`` and ``'YT'`` aim at maximizing it. Below a comparison of the robustness of the results above: >>> abs(np.linalg.det(fsf1.X)) < abs(np.linalg.det(fsf2.X)) True >>> abs(np.linalg.det(fsf2.X)) < abs(np.linalg.det(fsf3.X)) True Now a simple example for complex poles: >>> A = np.array([[ 0, 7/3., 0, 0 ], ... [ 0, 0, 0, 7/9. ], ... [ 0, 0, 0, 0 ], ... [ 0, 0, 0, 0 ]]) >>> B = np.array([[ 0, 0 ], ... [ 0, 0 ], ... [ 1, 0 ], ... [ 0, 1 ]]) >>> P = np.array([-3, -1, -2-1j, -2+1j]) / 3. >>> fsf = signal.place_poles(A, B, P, method='YT') We can plot the desired and computed poles in the complex plane: >>> t = np.linspace(0, 2*np.pi, 401) >>> plt.plot(np.cos(t), np.sin(t), 'k--') # unit circle >>> plt.plot(fsf.requested_poles.real, fsf.requested_poles.imag, ... 'wo', label='Desired') >>> plt.plot(fsf.computed_poles.real, fsf.computed_poles.imag, 'bx', ... label='Placed') >>> plt.grid() >>> plt.axis('image') >>> plt.axis([-1.1, 1.1, -1.1, 1.1]) >>> plt.legend(bbox_to_anchor=(1.05, 1), loc=2, numpoints=1) rrrNrr)rcondFrTzSConvergence was not reached after maxiter iterations. You asked for a tolerance of z , we got .ra) stacklevelrzfThe poles you've chosen can't be placed. Check the controllability matrix and try another set of poles)(rrrrrxrrrr}rflstsqeyenanr?rrnryr@rrrrwarningswarnastyperrsolvediag LinAlgErrorrhro gain_matrixrwrcomputed_polesrequested_polesr]r~nb_iter)"rrrNr|r~rrrrrzrankBu0u1 diag_polesidxrrrrskip_conjugater pole_space_jrr^ ker_pole_jtransfer_matrix_jrerr_msgrelimgrefull_state_feedbacks" r9r(r(} sXj'q!UFD'JKHG  DAq II ! !! $E 1fuf9B 1ef9B &5&!) A wwqzU(XXagg& EKKN"c A#%771:JsCx  ! }*,''!* 3A:&+-771: 3q5#a%<()+ 3q5#:&q 1HCEKKN"iiooaARo@C &&,66&& qwwqz"2 RA!&66"$$%(266!''!*3E*E(EFHHL 62DAq1l003445J$!#z :1bjj= I !2!#0A!B"C  %(##$&IIrww7H/I/1ww7H/I/K%L!Z 89"& +Av"3"$))_>O,P"Qe2 Rh 19&1(O27GT'K #D(GD1H44868*AO g!4 *009EKKN1$$ %*%%%af-224%aQh/+.bf*3',/3J3q5)q 1HCEKKN1$$ <  1 1266"''%.:I:K:K4MNNOa ))//!RVVBDD!A#->?K,K''+&K'&1#)= a"&&K001!4* &+0'+'") )yy$$ <45:; < >> import numpy as np >>> from scipy import signal >>> tf = ([1.0,], [1.0, -1.0], 1.0) >>> t_in = [0.0, 1.0, 2.0, 3.0] >>> u = np.asarray([0.0, 0.0, 1.0, 1.0]) >>> t_out, y = signal.dlsim(tf, u, t=t_in) >>> y.T array([[ 0., 0., 0., 1.]]) z7dlsim can only be used with discrete-time dlti systems.NrrFrrr7)r)k)rPrr8rr"rRrrr rrnrdrFrfloorrrrrrrr@rr?rrr) r6rrr is_ss_input out_samplesstoptimerGrItoutu_dtrKs r9r)r) sz&#() )  %vcr{2vbz2VZ0K ]]_F aAvv{ MM!   y!f !Ovyy0R5"((8fii#789A=  88[&((.."34 5D 88[&((.."34 5D ;;sH+ 6D zXXvxx~~a023QT ZZ^QT  y qww<1 !RZZ- A,!!Q!,T21kAo &4vxxad4vxxad45QqS!V ffVXXtAqDz2ffVXXtAqDz23QT 4!ffVXXtKM14D/EF ffVXXtKM14D/EFGDQ T4Tzr:c4t|tr|j}n:t|tr t dt|ddd|dij}|d}|'t j d||jz|d}nt j|}d}td|jD]]}t j|jd|jf}d |d|f<t|||| }||d f}n ||d fz}|d}_|fS) uImpulse response of discrete-time system. Parameters ---------- system : dlti | tuple An instance of the LTI class `dlti` or a tuple describing the system. The number of elements in the tuple determine the interpretation. I.e.: * ``system``: Instance of LTI class `dlti`. Note that derived instances, such as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are allowed as well. * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`. The coefficients of the polynomials should be specified in descending exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``. * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described in `ZerosPolesGain`. * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`. x0 : array_like, optional Initial state-vector. Defaults to zero. t : array_like, optional Time points. Computed if not given. n : int, optional The number of time points to compute (if `t` is not given). Returns ------- tout : ndarray Time values for the output, as a 1-D array. yout : tuple of ndarray Impulse response of system. Each element of the tuple represents the output of the system based on an impulse in each input. See Also -------- impulse, dstep, dlsim, cont2discrete Examples -------- >>> import numpy as np >>> from scipy import signal >>> import matplotlib.pyplot as plt ... >>> dt = 1 # sampling interval is one => time unit is sample number >>> bb, aa = signal.butter(3, 0.25, fs=1/dt) >>> t, y = signal.dimpulse((bb, aa, dt), n=25) ... >>> fig0, ax0 = plt.subplots() >>> ax0.step(t, np.squeeze(y), '.-', where='post') >>> ax0.set_title(r"Impulse Response of a $3^\text{rd}$ Order Butterworth Filter") >>> ax0.set(xlabel='Sample number', ylabel='Amplitude') >>> ax0.grid() >>> plt.show() z:dimpulse can only be used with discrete-time dlti systems.NrrFrrFendpointrSrrr)rPrrRrr8rrrFrr?r?rrr) r6rrrwrIrKr one_outputrs r9r+r+T s*p&$ FC -. .vcr{2vbz299; y  y KK1vyy=!e < JJqM D 1fmm $  HHaggaj&--0 1!Q$61b1 <qM#D:a=**D!}  :r:czt|tr|j}n:t|tr t dt|ddd|dij}|d}|'t j d||jz|d}nt j|}d}td|jD]}t j|jd|jf}t j|jdf|dd|f<t|||| }||d f}n ||d fz}|d}|fS) uStep response of discrete-time system. Parameters ---------- system : dlti | tuple An instance of the LTI class `dlti` or a tuple describing the system. The number of elements in the tuple determine the interpretation. I.e.: * ``system``: Instance of LTI class `dlti`. Note that derived instances, such as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are allowed as well. * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`. The coefficients of the polynomials should be specified in descending exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``. * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described in `ZerosPolesGain`. * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`. x0 : array_like, optional Initial state-vector. Defaults to zero. t : array_like, optional Time points. Computed if not given. n : int, optional The number of time points to compute (if `t` is not given). Returns ------- tout : ndarray Output time points, as a 1-D array. yout : tuple of ndarray Step response of system. Each element of the tuple represents the output of the system based on a step response to each input. See Also -------- step, dimpulse, dlsim, cont2discrete Examples -------- The following example illustrates how to create a digital Butterworth filer and plot its step response: >>> import numpy as np >>> from scipy import signal >>> import matplotlib.pyplot as plt ... >>> dt = 1 # sampling interval is one => time unit is sample number >>> bb, aa = signal.butter(3, 0.25, fs=1/dt) >>> t, y = signal.dstep((bb, aa, dt), n=25) ... >>> fig0, ax0 = plt.subplots() >>> ax0.step(t, np.squeeze(y), '.-', where='post') >>> ax0.set_title(r"Step Response of a $3^\text{rd}$ Order Butterworth Filter") >>> ax0.set(xlabel='Sample number', ylabel='Amplitude', ylim=(0, 1.1*np.max(y))) >>> ax0.grid() >>> plt.show() z7dstep can only be used with discrete-time dlti systems.NrrFrrFrrr)rPrrRrr8rrrFrr?r?rrrr)rs r9r*r* s=v&$ FC () )vcr{2vbz299; y  y KK1vyy=!e < JJqM D 1fmm $  HHaggaj&--0 1''1771:-(!Q$61b1 <qM#D:a=**D!}  :r:ct|ts,t|tr tdt|ddd|di}t|tr|j }t|t tzs td|jdk7s|jdk7r td||}n|}t|t rQt j|jj|j\}}t||||\}}||fSt|tr1t!|j"|j$|j&||\}}|fS) u Calculate the frequency response of a discrete-time system. Parameters ---------- system : dlti | tuple An instance of the LTI class `dlti` or a tuple describing the system. The number of elements in the tuple determine the interpretation. I.e.: * ``system``: Instance of LTI class `dlti`. Note that derived instances, such as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are allowed as well. * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`. The coefficients of the polynomials should be specified in descending exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``. * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described in `ZerosPolesGain`. * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`. w : array_like, optional Array of frequencies (in radians/sample). Magnitude and phase data is calculated for every value in this array. If not given a reasonable set will be calculated. n : int, optional Number of frequency points to compute if `w` is not given. The `n` frequencies are logarithmically spaced in an interval chosen to include the influence of the poles and zeros of the system. whole : bool, optional Normally, if 'w' is not given, frequencies are computed from 0 to the Nyquist frequency, pi radians/sample (upper-half of unit-circle). If `whole` is True, compute frequencies from 0 to 2*pi radians/sample. Returns ------- w : 1D ndarray Frequency array [radians/sample] H : 1D ndarray Array of complex magnitude values Notes ----- If (num, den) is passed in for ``system``, coefficients for both the numerator and denominator should be specified in descending exponent order (e.g. ``z^2 + 3z + 5`` would be represented as ``[1, 3, 5]``). .. versionadded:: 0.18.0 Examples -------- The following example generates the Nyquist plot of the transfer function :math:`H(z) = \frac{1}{z^2 + 2z + 3}` with a sampling time of 0.05 seconds: >>> from scipy import signal >>> import matplotlib.pyplot as plt >>> sys = signal.TransferFunction([1], [1, 2, 3], dt=0.05) # construct H(z) >>> w, H = signal.dfreqresp(sys) ... >>> fig0, ax0 = plt.subplots() >>> ax0.plot(H.real, H.imag, label=r"$H(z=e^{+j\omega})$") >>> ax0.plot(H.real, -H.imag, label=r"$H(z=e^{-j\omega})$") >>> ax0.set_title(r"Nyquist Plot of $H(z) = 1 / (z^2 + 2z + 3)$") >>> ax0.set(xlabel=r"$\text{Re}\{z\}$", ylabel=r"$\text{Im}\{z\}$", ... xlim=(-0.2, 0.65), aspect='equal') >>> ax0.plot(H[0].real, H[0].imag, 'k.') # mark H(exp(1j*w[0])) >>> ax0.text(0.2, 0, r"$H(e^{j0})$") >>> ax0.grid(True) >>> ax0.legend() >>> plt.show() z6dfreqresp can only be used with discrete-time systems.NrrFzUnknown system typerz?dfreqresp requires a SISO (single input, single output) system.)rlr)rPrrr8r"rWr r!rhr?r@rrrmrr r rrNr)r6rvrwrrlrrr_s r9r,r, s@L fd # fc " ":; ;vcr{2vbz2&*% f.? @.// }}V^^q0+, , }&*+$..vzz/?/?/A6::NSS#D61 a4K FN +v||V[[t$&1 a4Kr:c0t|||\}}t|tr |j}n|d}dt j t |z}t jt jt j|}||z ||fS)uCalculate Bode magnitude and phase data of a discrete-time system. Parameters ---------- system : dlti | tuple An instance of the LTI class `dlti` or a tuple describing the system. The number of elements in the tuple determine the interpretation. I.e.: * ``system``: Instance of LTI class `dlti`. Note that derived instances, such as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are allowed as well. * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`. The coefficients of the polynomials should be specified in descending exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``. * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described in `ZerosPolesGain`. * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`. w : array_like, optional Array of frequencies normalized to the Nyquist frequency being π, i.e., having unit radiant / sample. Magnitude and phase data is calculated for every value in this array. If not given, a reasonable set will be calculated. n : int, optional Number of frequency points to compute if `w` is not given. The `n` frequencies are logarithmically spaced in an interval chosen to include the influence of the poles and zeros of the system. Returns ------- w : 1D ndarray Array of frequencies normalized to the Nyquist frequency being ``np.pi/dt`` with ``dt`` being the sampling interval of the `system` parameter. The unit is rad/s assuming ``dt`` is in seconds. mag : 1D ndarray Magnitude array in dB phase : 1D ndarray Phase array in degrees Notes ----- This function is a convenience wrapper around `dfreqresp` for extracting magnitude and phase from the calculated complex-valued amplitude of the frequency response. .. versionadded:: 0.18.0 See Also -------- dfreqresp, dlti, TransferFunction, ZerosPolesGain, StateSpace Examples -------- The following example shows how to create a Bode plot of a 5-th order Butterworth lowpass filter with a corner frequency of 100 Hz: >>> import matplotlib.pyplot as plt >>> import numpy as np >>> from scipy import signal ... >>> T = 1e-4 # sampling interval in s >>> f_c, o = 1e2, 5 # corner frequency in Hz (i.e., -3 dB value) and filter order >>> bb, aa = signal.butter(o, f_c, 'lowpass', fs=1/T) ... >>> w, mag, phase = signal.dbode((bb, aa, T)) >>> w /= 2*np.pi # convert unit of frequency into Hertz ... >>> fg, (ax0, ax1) = plt.subplots(2, 1, sharex='all', figsize=(5, 4), ... tight_layout=True) >>> ax0.set_title("Bode Plot of Butterworth Lowpass Filter " + ... rf"($f_c={f_c:g}\,$Hz, order={o})") >>> ax0.set_ylabel(r"Magnitude in dB") >>> ax1.set(ylabel=r"Phase in Degrees", ... xlabel="Frequency $f$ in Hertz", xlim=(w[1], w[-1])) >>> ax0.semilogx(w, mag, 'C0-', label=r"$20\,\log_{10}|G(f)|$") # Magnitude plot >>> ax1.semilogx(w, phase, 'C1-', label=r"$\angle G(f)$") # Phase plot ... >>> for ax_ in (ax0, ax1): ... ax_.axvline(f_c, color='m', alpha=0.25, label=rf"${f_c=:g}\,$Hz") ... ax_.grid(which='both', axis='x') # plot major & minor vertical grid lines ... ax_.grid(which='major', axis='y') ... ax_.legend() >>> plt.show() rurrb) r,rPrrFrrcrWrad2degrdangle)r6rvrwrhrFrirjs r9r-r-{ szj VqA &DAq&$ YY BZ #a&! !C JJryy!- .E r63 r:)NTrrr)rvgMbP?)NNr)Frr scipy.linalgrrscipyrscipy.interpolater_filter_designrrr r r r r _lti_conversionrrrrrrrnumpyrrrrrrrrrrr__all__r/rrr rerr!rfrr"rgrr#r[r$r%r&r'rorrwrrrrzr{r(r)r+r*r,r-rr:r9rs* $0'''AAA333  ! S S ld3 d3N|6 |6~t*tnJ'!13J'Z> /> BG+(G+TC~sCLC ^TC LQ#$Q#h G!:sG!T; T; |T"n >CL@F=@Rn## 2j(!#^>B0;fx"v"4\~ upZz]@gT_r: