Control API¶
lti¶
- sympy.physics.control.lti.create_transfer_function(
- num,
- den,
- var,
- sampling_time=0,
Creates a new transfer function object. sampling_time == 0 means continuous time transfer function. sampling_time > 0 means discrete time transfer function.
- Parameters:
num : Expr, Number
The numerator polynomial of the transfer function.
den : Expr, Number
The denominator polynomial of the transfer function.
var : Symbol
Complex variable of the Laplace or z transform used by the polynomials of the transfer function.
sampling_time : Symbol, Number, optional
Default is 0. Time interval between two consecutive sampling instants. If sampling_time == 0, it is a continuous time transfer function, else it is a discrete time transfer function.
Examples
>>> from sympy.abc import s, z >>> from sympy.physics.control.lti import create_transfer_function >>> num = s + 5 >>> den = 3*s**2 + 2*s + 1 >>> tf = create_transfer_function(num, den, s) >>> tf TransferFunction(s + 5, 3*s**2 + 2*s + 1, s) >>> num = z >>> den = z + 1 >>> dtf = create_transfer_function(num, den, z, 0.1) >>> dtf DiscreteTransferFunction(z, z + 1, z, 0.1)
See also
- class sympy.physics.control.lti.TransferFunctionBase(
- num,
- den,
- var,
- *args,
- **kwargs,
Base class for transfer tunction objects. This class is not meant to be used directly.
- Parameters:
num : Expr, Number
The numerator polynomial of the transfer function.
den : Expr, Number
The denominator polynomial of the transfer function.
var : Symbol
Complex variable of the Laplace transform used by the polynomials of the transfer function.
*args, **kwargs:
Additional arguments and keyword arguments that are passed to the parent class such as sampling time for discrete-time systems.
- Raises:
TypeError
When
varis not a Symbol or whennumordenis not a number or a polynomial.ValueError
When
denis zero.
Explanation
LTI systems can be described by linear differential equations (for continuous-time systems) or linear difference equations (for discrete-time systems). Mathematical transforms are employed to convert these equations into simpler algebraic forms in a complex variable domain. For continuous-time systems, the Laplace transform (using complex variable \(s\)) is used. For discrete-time systems, the z-transform (using complex variable \(z\)) is used.
We will call the generic transformation used as \(\mathcal{T\{\cdot\}}\) and the variable of the transform as \(p\).
Consider a continuous-time LTI system described by a linear ordinary differential equation:
\[b_{m}y^{\left(m\right)}+b_{m-1}y^{\left(m-1\right)}+\dots+b_{1} y^{\left(1\right)}+b_{0}y= a_{n}x^{\left(n\right)}+a_{n-1}x^{\left(n-1\right)}+\dots+a_{1} x^{\left(1\right)}+a_{0}x\]or a discrete-time LTI system described by a linear difference equation:
\[b_{m}y[k-m]+b_{m-1}y[k-m+1]+\dots+b_{1}y[k-1]+b_{0}y[k]= a_{n}x[k-n]+a_{n-1}x[k-n+1]+\dots+a_{1}x[k-1]+a_{0}x[k]\]Here, \(x\) is the input signal and \(y\) is the output signal.
It is not feasible to analyse the properties of such systems in their native form therefore, we use mathematical tools like Laplace transform or z-transform to get a better perspective. Taking the transform \(\mathcal{T}\{\cdot\}\) of both the sides in the equation (at zero initial conditions), we get:
\[\mathcal{T}[b_{m}y^{\left(m\right)}+b_{m-1}y^{\left(m-1\right)}+\dots+ b_{1}y^{\left(1\right)}+b_{0}y]= \mathcal{T}[a_{n}x^{\left(n\right)}+a_{n-1}x^{\left(n-1\right)}+\dots+ a_{1}x^{\left(1\right)}+a_{0}x]\]and using its linearity and differentiation properties (\(\mathcal{L}\{f^{(k)}(t)\} = s^k F(s)\) under zero initial conditions), we get:
\[b_{m}p^{m}\mathcal{T}[y]+\dots+b_{1}p\mathcal{T}[y]+b_{0}\mathcal{T}[y]= a_{n}p^{n}\mathcal{T}[x]+\dots+a_{1}p\mathcal{T}[x]+a_{0}\mathcal{T}[x]\]Note that the zero initial conditions assumption, mentioned above, is very important and cannot be ignored otherwise the dynamical system cannot be considered time-independent and the simplified equation above cannot be reached.
The numerator of the transfer function is, therefore, the transform of the output signal and similarly, the denominator of the transfer function is the transform of the input signal. It is also a convention to denote the input and output signal’s transform with capital alphabets like shown below:
\[H(p) = \frac{Y(p)}{X(p)} = \frac{ \mathcal{T}\left\{y(t)\right\}} {\mathcal{T}\left\{x(t)\right\}}\]Transfer functions are sometimes also referred to as the transform of the system’s impulse response. Transfer function, \(H\), is represented as a rational function like,
\[H(p) =\ \frac{a_{n}p^{n}+a_{n-1}p^{n-1}+\dots+a_{1}p+a_{0}}{b_{m}p^{m}+ b_{m-1}p^{m-1}+\dots+b_{1}p+b_{0}}\]See also
TransferFunction,DiscreteTransferFunction,Feedback,Series,ParallelReferences
- abstractmethod dc_gain()[source]¶
Computes the gain of the response as the frequency approaches zero.
The DC gain is infinite for systems with pure integrators.
Examples
>>> from sympy.abc import s, p, a, b, z >>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> tf1 = TransferFunction(s + 3, s**2 - 9, s) >>> tf1.dc_gain() -1/3 >>> tf2 = TransferFunction(p**2, p - 3 + p**3, p) >>> tf2.dc_gain() 0 >>> tf3 = TransferFunction(a*p**2 - b, s + b, s) >>> tf3.dc_gain() (a*p**2 - b)/b >>> tf4 = TransferFunction(1, s, s) >>> tf4.dc_gain() oo >>> dtf1 = DiscreteTransferFunction(z, z - 1, z, 0.1) >>> dtf1.dc_gain() oo
- property den¶
Returns the denominator polynomial of the transfer function.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction(s + 4, p**3 - 2*p + 4, s) >>> G1.den p**3 - 2*p + 4 >>> G2 = TransferFunction(3, 4, s) >>> G2.den 4
- eval_frequency(other)[source]¶
Returns the system response at any point in the real or complex plane.
Examples
>>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> from sympy import I >>> tf1 = TransferFunction(1, s**2 + 2*s + 1, s) >>> omega = 0.1 >>> tf1.eval_frequency(I*omega) 0.970493088912852 - 0.196059209881384*I >>> tf2 = TransferFunction(s**2, a*s + p, s) >>> tf2.eval_frequency(2) 4/(2*a + p) >>> tf2.eval_frequency(I*2) -4/(2*I*a + p)
- expand()[source]¶
Returns the transfer function with numerator and denominator in expanded form.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> G1 = TransferFunction((a - s)**2, (s**2 + a)**2, s) >>> G1.expand() TransferFunction(a**2 - 2*a*s + s**2, a**2 + 2*a*s**2 + s**4, s) >>> G2 = DiscreteTransferFunction((p + 3*b)*(p - b), (p - b)*(p + 2*b), p, 12) >>> G2.expand() DiscreteTransferFunction(-3*b**2 + 2*b*p + p**2, -2*b**2 + b*p + p**2, p, 12)
- classmethod from_coeff_lists(
- num_list,
- den_list,
- var,
- *args,
- **kwargs,
Creates a new transfer function efficiently from a list of coefficients.
- Parameters:
num_list : Sequence
Sequence comprising of numerator coefficients.
den_list : Sequence
Sequence comprising of denominator coefficients.
var : Symbol
Complex variable used by the polynomials of the transfer function.
*args, **kwargs :
Additional positional and keyword arguments to be passed to the constructor of the
TransferFunctionBase, such as sampling_time.- Raises:
ZeroDivisionError
When the constructed denominator is zero.
Examples
>>> from sympy.abc import s, p, z >>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> num = [1, 0, 2] >>> den = [3, 2, 2, 1] >>> tf = TransferFunction.from_coeff_lists(num, den, s) >>> tf TransferFunction(s**2 + 2, 3*s**3 + 2*s**2 + 2*s + 1, s) >>> #Create a Transfer Function with more than one variable >>> tf1 = TransferFunction.from_coeff_lists([p, 1], [2*p, 0, 4], s) >>> tf1 TransferFunction(p*s + 1, 2*p*s**2 + 4, s) >>> dtf = DiscreteTransferFunction.from_coeff_lists([2, 1, -3], [1, 4, 3, 2], z, sampling_time=0.1) >>> dtf DiscreteTransferFunction(2*z**2 + z - 3, z**3 + 4*z**2 + 3*z + 2, z, 0.1)
- classmethod from_rational_expression(
- expr,
- var=None,
- *args,
- **kwargs,
Creates a new transfer function efficiently from a rational expression.
- Parameters:
expr : Expr, Number
The rational expression representing the transfer function.
var : Symbol, optional
Complex variable used by the polynomials of the transfer function.
*args, **kwargs :
Additional positional and keyword arguments to be passed to the constructor of the
TransferFunctionBase, such as sampling_time.- Raises:
ValueError
When
expris of typeNumberand optional parametervaris not passed.When
exprhas more than one variables and an optional parametervaris not passed.ZeroDivisionError
When denominator of
expris zero or it hasComplexInfinityin its numerator.
Examples
>>> from sympy.abc import s, p, a, z >>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> expr1 = (s + 5)/(3*s**2 + 2*s + 1) >>> tf1 = TransferFunction.from_rational_expression(expr1) >>> tf1 TransferFunction(s + 5, 3*s**2 + 2*s + 1, s) >>> expr2 = (a*p**3 - a*p**2 + s*p)/(p + a**2) # Expr with more than one variables >>> tf2 = TransferFunction.from_rational_expression(expr2, p) >>> tf2 TransferFunction(a*p**3 - a*p**2 + p*s, a**2 + p, p) >>> expr3 = (z + 1)/(z**2 + 2*z + 1) # Discrete time transfer function >>> dtf = DiscreteTransferFunction.from_rational_expression(expr3, z, sampling_time=0.1) >>> dtf DiscreteTransferFunction(z + 1, z**2 + 2*z + 1, z, 0.1)
In case of conflict between two or more variables in a expression, SymPy will raise a
ValueError, ifvaris not passed by the user.>>> tf = TransferFunction.from_rational_expression((a + a*s)/(s**2 + s + 1)) Traceback (most recent call last): ... ValueError: Conflicting values found for positional argument `var` ({a, s}). Specify it manually.
This can be corrected by specifying the
varparameter manually.>>> tf = TransferFunction.from_rational_expression((a + a*s)/(s**2 + s + 1), s) >>> tf TransferFunction(a*s + a, s**2 + s + 1, s)
varalso need to be specified whenexpris aNumber>>> tf3 = TransferFunction.from_rational_expression(10, s) >>> tf3 TransferFunction(10, 1, s)
- classmethod from_zpk(
- zeros,
- poles,
- gain,
- var,
- *args,
- **kwargs,
Creates a new transfer function from given zeros, poles and gain.
- Parameters:
zeros : Sequence
Sequence comprising of zeros of transfer function.
poles : Sequence
Sequence comprising of poles of transfer function.
gain : Number, Symbol, Expression
A scalar value specifying gain of the model.
var : Symbol
Complex variable used by the polynomials of the transfer function.
*args, **kwargs :
Additional positional and keyword arguments to be passed to the constructor of the
TransferFunctionBase, such as sampling_time.
Examples
>>> from sympy.abc import s, p, k >>> from sympy.physics.control.lti import TransferFunction >>> zeros = [1, 2, 3] >>> poles = [6, 5, 4] >>> gain = 7 >>> tf = TransferFunction.from_zpk(zeros, poles, gain, s) >>> tf TransferFunction(7*(s - 3)*(s - 2)*(s - 1), (s - 6)*(s - 5)*(s - 4), s) >>> #Create a Transfer Function with variable poles and zeros >>> tf1 = TransferFunction.from_zpk([p, k], [p + k, p - k], 2, s) >>> tf1 TransferFunction(2*(-k + s)*(-p + s), (-k - p + s)*(k - p + s), s) >>> #Complex poles or zeros are acceptable >>> tf2 = TransferFunction.from_zpk([0], [1-1j, 1+1j, 2], -2, s) >>> tf2 TransferFunction(-2*s, (s - 2)*(s - 1.0 - 1.0*I)*(s - 1.0 + 1.0*I), s)
- abstractmethod get_asymptotic_stability_conditions(
- cancel_poles_zeros=False,
- fast=False,
Returns the asymptotic stability conditions for the transfer function.
This is a convenient shorthand, based on the system type (continuous or discrete), for:
[c > 0 for c in Poly(sys.den, sys.var).hurwitz_conditions()]which gives conditions for stability such that the poles of the transfer function are in the left half of the complex plane.[c > 0 for c in Poly(sys.den, sys.var).schur_conditions()]which gives conditions for stability such that the poles of the transfer function lie inside the unit circle.
For some systems that are larger or have more complicated expressions it might be useful to set
fasttoTrue. The algorithm will use the EXRAW domain which will quickly generate large unsimplified expressions that are mostly only suitable for use with lambdify.- Parameters:
cancel_poles_zeros : Boolean
If True, cancels common factors between numerator and denominator before checking stability.
fast : Boolean
If True, uses the EXRAW domain to quickly generate large unsimplified expressions. If False, uses the default domain which is suitable for symbolic manipulation.
Notes
Also with
cancel_poles_zeros = True, the set generated by the inequalities may be a subset of the real asymptotic stability conditions set due to potentially unaccounted pole-zero cancellations.This method assumes that the leading coefficient is non-zero. In the opposite case, additional verification is required.
In the discrete case, using
fast = Truemay lead to significant precision issues.
Examples
>>> from sympy import symbols, solve, reduce_inequalities >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, Feedback
>>> b1, b2, b3, b4 = symbols('b_1 b_2 b_3 b_4') >>> p1 = b1*s**3 + b2*s**2 + b3*s + b4 >>> tf1 = TransferFunction(1, p1, s) >>> tf1.get_asymptotic_stability_conditions() [b_1*b_2 > 0, -b_1*b_4 + b_2*b_3 > 0, b_1*b_4 > 0]
>>> p2 = s**4 + 3*s**3 + 6*s**2 + 12*s + 8 >>> solve(p2) [-2, -1, -2*I, 2*I] >>> tf2 = TransferFunction(1, p2, s) >>> tf2.get_asymptotic_stability_conditions() [False]
>>> p3 = s**4 + 17*s**3 + 137/2*s**2 + 213/2*s + 54 >>> solve(p3) [-12.0, -1.0, -2.0 - 0.707106781186548*I, -2.0 + 0.707106781186548*I] >>> tf3 = TransferFunction(1, p3, s) >>> tf3.get_asymptotic_stability_conditions() [True, True, True, True]
>>> k = symbols('k') >>> tf4 = TransferFunction(-20*s + 20, s**3 + 2*s**2 + 100*s, s) >>> tf5 = TransferFunction(1, k, s) >>> feedback = Feedback(tf4, tf5).doit() >>> ineq = feedback.get_asymptotic_stability_conditions(cancel_poles_zeros = True) >>> ineq [2*k**2 > 0, 200*k**2 - 60*k > 0, 20*k > 0] >>> reduce_inequalities(ineq) (3/10 < k) & (k < oo)
- property is_biproper¶
Returns True if degree of the numerator polynomial is equal to degree of the denominator polynomial, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf1.is_biproper True >>> tf2 = TransferFunction(p**2, p + a, p) >>> tf2.is_biproper False
- property is_proper¶
Returns True if degree of the numerator polynomial is less than or equal to degree of the denominator polynomial, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) >>> tf1.is_proper False >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*p + 2, p) >>> tf2.is_proper True
- is_stable(
- cancel_poles_zeros=False,
Returns True if the transfer function is asymptotically stable; else False.
This would not check the marginal or conditional stability of the system.
Note: Also with cancel_poles_zeros = True, there could be unaccounted pole-zero cancellations.
- Parameters:
cancel_poles_zeros : Boolean
If True, cancels common factors between numerator and denominator before checking stability.
Examples
>>> from sympy.abc import s, p, a >>> from sympy import symbols >>> from sympy.physics.control.lti import TransferFunction >>> q, r = symbols('q, r', negative=True) >>> tf1 = TransferFunction((1 - s)**2, (s + 1)**2, s) >>> tf1.is_stable() True >>> tf2 = TransferFunction((1 - p)**2, (s**2 + 1)**2, s) >>> tf2.is_stable() False >>> tf3 = TransferFunction(4, q*s - r, s) >>> tf3.is_stable() False >>> tf4 = TransferFunction(p + 1, a*p - s**2, p) >>> tf4.is_stable() is None # Not enough info about the symbols to determine stability True >>> tf5 = TransferFunction((s+1)*(s-1), (s-1)*(s+2)*(s+4), s) >>> tf5.is_stable() False >>> tf5.is_stable(cancel_poles_zeros = True) True
- property is_strictly_proper¶
Returns True if degree of the numerator polynomial is strictly less than degree of the denominator polynomial, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf1.is_strictly_proper False >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf2.is_strictly_proper True
- property num¶
Returns the numerator polynomial of the transfer function.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction(s**2 + p*s + 3, s - 4, s) >>> G1.num p*s + s**2 + 3 >>> G2 = TransferFunction((p + 5)*(p - 3), (p - 3)*(p + 1), p) >>> G2.num (p - 3)*(p + 5)
- poles()[source]¶
Returns the poles of a transfer function.
Examples
>>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) >>> tf1.poles() [-5, 1] >>> tf2 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) >>> tf2.poles() [I, I, -I, -I] >>> tf3 = TransferFunction(s**2, a*s + p, s) >>> tf3.poles() [-p/a]
- to_expr()[source]¶
Converts a
TransferFunctionobject to SymPysympy.core.expr.Expr.Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> from sympy import Expr >>> tf1 = TransferFunction(s, a*s**2 + 1, s) >>> tf1.to_expr() s/(a*s**2 + 1) >>> isinstance(_, Expr) True >>> tf2 = TransferFunction(1, (p + 3*b)*(b - p), p) >>> tf2.to_expr() 1/((b - p)*(3*b + p)) >>> tf3 = TransferFunction((s - 2)*(s - 3), (s - 1)*(s - 2)*(s - 3), s) >>> tf3.to_expr() ((s - 3)*(s - 2))/(((s - 3)*(s - 2)*(s - 1)))
- to_standard_form(
- cancel_poles_zeros=False,
Return the transfer function in its standard form.
Standard form:
\[\frac{a_n s^n + a_{n-1} s^{n-1} + \cdots + a_1 s + a_0} {b_m s^m + b_{m-1} s^{m-1} + \cdots + b_1 s + b_0}\]Note: Also with cancel_poles_zeros = True, there could be unaccounted pole-zero cancellations.
Examples
>>> from sympy import symbols >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> s,k = symbols('s k') >>> tf1 = TransferFunction(-2*s + 12, s**3 + 2*s**2 + 100*s, s) >>> tf2 = TransferFunction(1, k, s) >>> feedback = Feedback(tf1, tf2).doit() >>> feedback TransferFunction(k*(12 - 2*s)*(s**3 + 2*s**2 + 100*s), (s**3 + 2*s**2 + 100*s)*(k*(s**3 + 2*s**2 + 100*s) - 2*s + 12), s) >>> feedback.to_standard_form(cancel_poles_zeros=True) TransferFunction(-2*k*s + 12*k, k*s**3 + 2*k*s**2 + s*(100*k - 2) + 12, s)
- property var¶
Returns the complex variable used by the polynomials of the transfer function.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G1.var p >>> G2 = TransferFunction(0, s - 5, s) >>> G2.var s
- zeros()[source]¶
Returns the zeros of a transfer function.
Examples
>>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) >>> tf1.zeros() [-3, 1] >>> tf2 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) >>> tf2.zeros() [1, 1] >>> tf3 = TransferFunction(s**2, a*s + p, s) >>> tf3.zeros() [0, 0]
- class sympy.physics.control.lti.TransferFunction(num, den, var)[source]¶
A class for representing LTI (Linear, time-invariant) systems that can be strictly described by ratio of polynomials in the Laplace transform complex variable. The arguments are
num,den, andvar, wherenumanddenare numerator and denominator polynomials of theTransferFunctionrespectively, and the third argument is a complex variable of the Laplace transform used by these polynomials of the transfer function.numanddencan be either polynomials or numbers, whereasvarhas to be aSymbol.See
TransferFunctionBasefor more information.- Parameters:
num : Expr, Number
The numerator polynomial of the transfer function.
den : Expr, Number
The denominator polynomial of the transfer function.
var : Symbol
Complex variable of the Laplace transform used by the polynomials of the transfer function.
- Raises:
TypeError
When
varis not a Symbol or whennumordenis not a number or a polynomial.ValueError
When
denis zero.
Examples
>>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(s + a, s**2 + s + 1, s) >>> tf1 TransferFunction(a + s, s**2 + s + 1, s) >>> tf1.num a + s >>> tf1.den s**2 + s + 1 >>> tf1.var s >>> tf1.args (a + s, s**2 + s + 1, s)
Any complex variable can be used for
var.>>> tf2 = TransferFunction(a*p**3 - a*p**2 + s*p, p + a**2, p) >>> tf2 TransferFunction(a*p**3 - a*p**2 + p*s, a**2 + p, p) >>> tf3 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) >>> tf3 TransferFunction((p - 1)*(p + 3), (p - 1)*(p + 5), p)
To negate a transfer function the
-operator can be prepended:>>> tf4 = TransferFunction(-a + s, p**2 + s, p) >>> -tf4 TransferFunction(a - s, p**2 + s, p) >>> tf5 = TransferFunction(s**4 - 2*s**3 + 5*s + 4, s + 4, s) >>> -tf5 TransferFunction(-s**4 + 2*s**3 - 5*s - 4, s + 4, s)
You can use a float or an integer (or other constants) as numerator and denominator:
>>> tf6 = TransferFunction(1/2, 4, s) >>> tf6.num 0.500000000000000 >>> tf6.den 4 >>> tf6.var s >>> tf6.args (0.5, 4, s)
You can take the integer power of a transfer function using the
**operator:>>> tf7 = TransferFunction(s + a, s - a, s) >>> tf7**3 TransferFunction((a + s)**3, (-a + s)**3, s) >>> tf7**0 TransferFunction(1, 1, s) >>> tf8 = TransferFunction(p + 4, p - 3, p) >>> tf8**-1 TransferFunction(p - 3, p + 4, p)
Addition, subtraction, and multiplication of transfer functions can form unevaluated
SeriesorParallelobjects.>>> tf9 = TransferFunction(s + 1, s**2 + s + 1, s) >>> tf10 = TransferFunction(s - p, s + 3, s) >>> tf11 = TransferFunction(4*s**2 + 2*s - 4, s - 1, s) >>> tf12 = TransferFunction(1 - s, s**2 + 4, s) >>> tf9 + tf10 Parallel(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-p + s, s + 3, s)) >>> tf10 - tf11 Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(-4*s**2 - 2*s + 4, s - 1, s)) >>> tf9 * tf10 Series(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-p + s, s + 3, s)) >>> tf10 - (tf9 + tf12) Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(-s - 1, s**2 + s + 1, s), TransferFunction(s - 1, s**2 + 4, s)) >>> tf10 - (tf9 * tf12) Parallel(TransferFunction(-p + s, s + 3, s), Series(TransferFunction(-1, 1, s), TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(1 - s, s**2 + 4, s))) >>> tf11 * tf10 * tf9 Series(TransferFunction(4*s**2 + 2*s - 4, s - 1, s), TransferFunction(-p + s, s + 3, s), TransferFunction(s + 1, s**2 + s + 1, s)) >>> tf9 * tf11 + tf10 * tf12 Parallel(Series(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(4*s**2 + 2*s - 4, s - 1, s)), Series(TransferFunction(-p + s, s + 3, s), TransferFunction(1 - s, s**2 + 4, s))) >>> (tf9 + tf12) * (tf10 + tf11) Series(Parallel(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(1 - s, s**2 + 4, s)), Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(4*s**2 + 2*s - 4, s - 1, s)))
These unevaluated
SeriesorParallelobjects can convert into the resultant transfer function using.doit()method or by.rewrite(TransferFunction).>>> ((tf9 + tf10) * tf12).doit() TransferFunction((1 - s)*((-p + s)*(s**2 + s + 1) + (s + 1)*(s + 3)), (s + 3)*(s**2 + 4)*(s**2 + s + 1), s) >>> (tf9 * tf10 - tf11 * tf12).rewrite(TransferFunction) TransferFunction(-(1 - s)*(s + 3)*(s**2 + s + 1)*(4*s**2 + 2*s - 4) + (-p + s)*(s - 1)*(s + 1)*(s**2 + 4), (s - 1)*(s + 3)*(s**2 + 4)*(s**2 + s + 1), s)
See also
TransferFunctionBase,DiscreteTransferFunction,Feedback,Series,Parallel- get_asymptotic_stability_conditions(
- cancel_poles_zeros=False,
- fast=False,
See
TransferFunctionBase.get_asymptotic_stability_conditions().
- property sampling_time¶
The sampling time of the transfer function is zero.
- class sympy.physics.control.lti.DiscreteTransferFunction(
- num,
- den,
- var,
- sampling_time=1,
A class for representing LTI (Linear, time-invariant) systems that can be strictly described by ratio of polynomials in the z-transform complex variable. The arguments are
num,den,var, andsampling_time, wherenumanddenare numerator and denominator polynomials of theDiscreteTransferFunctionrespectively, the third argument is a complex variable of the z-transform used by these polynomials of the transfer function, and the fourth represents the time interval between two consecutive sampling instants. If not specified, it defaults to 1 and, if it’s set to 0, an instance ofTransferFunctionis returned.numanddencan be either polynomials or numbers,varhas to be aSymbolandsampling_timecan be bothSymbolor numbers.See
TransferFunctionBasefor more information.- Parameters:
num : Expr, Number
The numerator polynomial of the transfer function.
den : Expr, Number
The denominator polynomial of the transfer function.
var : Symbol
Complex variable of the z-transform used by the polynomials of the transfer function.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants Defaults to 1. If sampling_time == 0, an instance of
TransferFunctionis returned.- Raises:
TypeError
When
varis not a Symbol or whennumordenis not a number or a polynomial.ValueError
When
denis zero.
Examples
>>> from sympy.abc import z, p, a, k >>> from sympy.physics.control.lti import DiscreteTransferFunction >>> dtf1 = DiscreteTransferFunction(z**2 + a*z, z**2 + z + 1, z, 0.1) >>> dtf1 DiscreteTransferFunction(a*z + z**2, z**2 + z + 1, z, 0.1) >>> dtf1.num a*z + z**2 >>> dtf1.den z**2 + z + 1 >>> dtf1.var z >>> dtf1.sampling_time 0.1 >>> dtf1.args (a*z + z**2, z**2 + z + 1, z, 0.1)
Any complex variable can be used for
var.>>> dtf2 = DiscreteTransferFunction(a*p**3 - a*p**2 + z*p, p + a**2, p, k) >>> dtf2 DiscreteTransferFunction(a*p**3 - a*p**2 + p*z, a**2 + p, p, k) >>> dtf3 = DiscreteTransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p, k) >>> dtf3 DiscreteTransferFunction((p - 1)*(p + 3), (p - 1)*(p + 5), p, k)
To negate a transfer function the
-operator can be prepended:>>> dtf4 = DiscreteTransferFunction(-a + z, p**2 + z, p, 0.2) >>> -dtf4 DiscreteTransferFunction(a - z, p**2 + z, p, 0.2) >>> dtf5 = DiscreteTransferFunction(z**4 - 2*z**3 + 5*z + 4, z + 4, z, 12) >>> -dtf5 DiscreteTransferFunction(-z**4 + 2*z**3 - 5*z - 4, z + 4, z, 12)
You can use a float or an integer (or other constants) as numerator and denominator:
>>> dtf6 = DiscreteTransferFunction(1/2, 4, z, k) >>> dtf6.num 0.500000000000000 >>> dtf6.den 4 >>> dtf6.var z >>> dtf6.sampling_time k >>> dtf6.args (0.5, 4, z, k)
You can take the integer power of a transfer function using the
**operator:>>> dtf7 = DiscreteTransferFunction(z + a, z - a, z, 0.3) >>> dtf7**3 DiscreteTransferFunction((a + z)**3, (-a + z)**3, z, 0.3) >>> dtf7**0 DiscreteTransferFunction(1, 1, z, 0.3) >>> dtf8 = DiscreteTransferFunction(p + 4, p - 3, p, k) >>> dtf8**-1 DiscreteTransferFunction(p - 3, p + 4, p, k)
Addition, subtraction, and multiplication of transfer functions can form unevaluated
SeriesorParallelobjects.>>> dtf9 = DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k) >>> dtf10 = DiscreteTransferFunction(z - p, z + 3, z, k) >>> dtf11 = DiscreteTransferFunction(4*z**2 + 2*z - 4, z - 1, z, k) >>> dtf12 = DiscreteTransferFunction(1 - z, z**2 + 4, z, k) >>> dtf9 + dtf10 Parallel(DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k), DiscreteTransferFunction(-p + z, z + 3, z, k)) >>> dtf10 - dtf11 Parallel(DiscreteTransferFunction(-p + z, z + 3, z, k), DiscreteTransferFunction(-4*z**2 - 2*z + 4, z - 1, z, k)) >>> dtf9 * dtf10 Series(DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k), DiscreteTransferFunction(-p + z, z + 3, z, k)) >>> dtf10 - (dtf9 + dtf12) Parallel(DiscreteTransferFunction(-p + z, z + 3, z, k), DiscreteTransferFunction(-z - 1, z**2 + z + 1, z, k), DiscreteTransferFunction(z - 1, z**2 + 4, z, k)) >>> dtf10 - (dtf9 * dtf12) Parallel(DiscreteTransferFunction(-p + z, z + 3, z, k), Series(DiscreteTransferFunction(-1, 1, z, k), DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k), DiscreteTransferFunction(1 - z, z**2 + 4, z, k))) >>> dtf11 * dtf10 * dtf9 Series(DiscreteTransferFunction(4*z**2 + 2*z - 4, z - 1, z, k), DiscreteTransferFunction(-p + z, z + 3, z, k), DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k)) >>> dtf9 * dtf11 + dtf10 * dtf12 Parallel(Series(DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k), DiscreteTransferFunction(4*z**2 + 2*z - 4, z - 1, z, k)), Series(DiscreteTransferFunction(-p + z, z + 3, z, k), DiscreteTransferFunction(1 - z, z**2 + 4, z, k))) >>> (dtf9 + dtf12) * (dtf10 + dtf11) Series(Parallel(DiscreteTransferFunction(z + 1, z**2 + z + 1, z, k), DiscreteTransferFunction(1 - z, z**2 + 4, z, k)), Parallel(DiscreteTransferFunction(-p + z, z + 3, z, k), DiscreteTransferFunction(4*z**2 + 2*z - 4, z - 1, z, k)))
These unevaluated
SeriesorParallelobjects can convert into the resultant transfer function using.doit()method or by.rewrite(DiscreteTransferFunction).>>> ((dtf9 + dtf10) * dtf12).doit() DiscreteTransferFunction((1 - z)*((-p + z)*(z**2 + z + 1) + (z + 1)*(z + 3)), (z + 3)*(z**2 + 4)*(z**2 + z + 1), z, k) >>> (dtf9 * dtf10 - dtf11 * dtf12).rewrite(DiscreteTransferFunction) DiscreteTransferFunction(-(1 - z)*(z + 3)*(z**2 + z + 1)*(4*z**2 + 2*z - 4) + (-p + z)*(z - 1)*(z + 1)*(z**2 + 4), (z - 1)*(z + 3)*(z**2 + 4)*(z**2 + z + 1), z, k)
See also
TransferFunctionBase,TransferFunction,Feedback,Series,Parallel- classmethod from_backward_diff(
- cont_tf,
- sampling_time,
- var,
Returns the discretized transfer function H(z) from a continuous transfer function H(s).
- Parameters:
cont_tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
var: Symbol
The complex variable of the z-transform used by the polynomials of the transfer function.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the backward difference transform method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{z-1}{Tz}\) into H(s), where T is the sample time.
Examples
>>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> from sympy.abc import s, z, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> dttf = DiscreteTransferFunction.from_backward_diff(tf, T, z) >>> dttf.num T*z/(L + R*T) >>> dttf.den -L/(L + R*T) + z >>> dttf.sampling_time T
- classmethod from_bilinear(
- cont_tf,
- sampling_time,
- var,
Returns the discretized transfer function H(z) from a continuous transfer function H(s).
- Parameters:
cont_tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
var: Symbol
The complex variable of the z-transform used by the polynomials of the transfer function.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the bilinear transform method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{2}{T}\frac{z-1}{z+1}\) into H(s), where T is the sample time.
Examples
>>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> from sympy.abc import s, z, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> dttf = DiscreteTransferFunction.from_bilinear(tf, T, z) >>> dttf.num T*z/(2*(L + R*T/2)) + T/(2*(L + R*T/2)) >>> dttf.den z + (-L + R*T/2)/(L + R*T/2) >>> dttf.sampling_time T
- classmethod from_forward_diff(
- cont_tf,
- sampling_time,
- var,
Returns the discretized transfer function H(z) from a continuous transfer function H(s).
- Parameters:
cont_tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
var: Symbol
The complex variable of the z-transform used by the polynomials of the transfer function.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the forward difference transform method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{z-1}{T}\) into H(s), where T is the sample time.
Examples
>>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> from sympy.abc import s, z, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> dttf = DiscreteTransferFunction.from_forward_diff(tf, T, z) >>> dttf.num T/L >>> dttf.den z + (-L + R*T)/L >>> dttf.sampling_time T
- classmethod from_gbt(
- cont_tf,
- sampling_time,
- alpha,
- var,
Returns the discretized transfer function H(z) from a continuous transfer function H(s).
- Parameters:
cont_tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
alpha: Symbol, Number
The parameter for the generalised bilinear transformation method.
var: Symbol
The complex variable of the z-transform used by the polynomials of the transfer function.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the generalised bilinear transformation method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{z-1}{T(\alpha z + (1-\alpha))}\) into H(s), where T is the sample time.
Examples
>>> from sympy.physics.control.lti import TransferFunction, DiscreteTransferFunction >>> from sympy.abc import s, z, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> dttf1 = DiscreteTransferFunction.from_gbt(tf, T, 0.5, z) >>> dttf1.num T*z/(2*(L + R*T/2)) + T/(2*(L + R*T/2)) >>> dttf1.den z + (-L + R*T/2)/(L + R*T/2) >>> dttf1.sampling_time T
>>> dttf2 = DiscreteTransferFunction.from_gbt(tf, T, 0, z) >>> dttf2.num T/L >>> dttf2.den z + (-L + R*T)/L >>> dttf2.sampling_time T
>>> dttf3 = DiscreteTransferFunction.from_gbt(tf, T, 1, z) >>> dttf3.num T*z/(L + R*T) >>> dttf3.den -L/(L + R*T) + z >>> dttf3.sampling_time T
>>> dttf4 = DiscreteTransferFunction.from_gbt(tf, T, 0.3, z) >>> dttf4.num 3*T*z/(10*(L + 3*R*T/10)) + 7*T/(10*(L + 3*R*T/10)) >>> dttf4.den z + (-L + 7*R*T/10)/(L + 3*R*T/10) >>> dttf4.sampling_time T
References
- get_asymptotic_stability_conditions(
- cancel_poles_zeros=False,
- fast=False,
See
TransferFunctionBase.get_asymptotic_stability_conditions().
- property sampling_time¶
Returns the sampling time of the DiscreteTransferFunction.
- class sympy.physics.control.lti.Series(*args, evaluate=False)[source]¶
A class for representing a series configuration of SISO systems.
- Parameters:
args : SISOLinearTimeInvariant
SISO systems in a series configuration.
evaluate : Boolean, Keyword
When passed
True, returns the equivalentSeries(*args).doit(). Set toFalseby default.- Raises:
ValueError
When no argument is passed.
varattribute is not same for every system.TypeError
Any of the passed
*argshas unsupported typeA combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed, SISO in this case.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy import Matrix >>> from sympy.physics.control.lti import TransferFunction, Series, Parallel, StateSpace >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf3 = TransferFunction(p**2, p + s, s) >>> S1 = Series(tf1, tf2) >>> S1 Series(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)) >>> S1.var s >>> S2 = Series(tf2, Parallel(tf3, -tf1)) >>> S2 Series(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), Parallel(TransferFunction(p**2, p + s, s), TransferFunction(-a*p**2 - b*s, -p + s, s))) >>> S2.var s >>> S3 = Series(Parallel(tf1, tf2), Parallel(tf2, tf3)) >>> S3 Series(Parallel(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)), Parallel(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), TransferFunction(p**2, p + s, s))) >>> S3.var s
You can get the resultant transfer function by using
.doit()method:>>> S3 = Series(tf1, tf2, -tf3) >>> S3.doit() TransferFunction(-p**2*(s**3 - 2)*(a*p**2 + b*s), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) >>> S4 = Series(tf2, Parallel(tf1, -tf3)) >>> S4.doit() TransferFunction((s**3 - 2)*(-p**2*(-p + s) + (p + s)*(a*p**2 + b*s)), (-p + s)*(p + s)*(s**4 + 5*s + 6), s)
You can also connect StateSpace which results in SISO
>>> A1 = Matrix([[-1]]) >>> B1 = Matrix([[1]]) >>> C1 = Matrix([[-1]]) >>> D1 = Matrix([1]) >>> A2 = Matrix([[0]]) >>> B2 = Matrix([[1]]) >>> C2 = Matrix([[1]]) >>> D2 = Matrix([[0]]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss2 = StateSpace(A2, B2, C2, D2) >>> S5 = Series(ss1, ss2) >>> S5 Series(StateSpace(Matrix([[-1]]), Matrix([[1]]), Matrix([[-1]]), Matrix([[1]])), StateSpace(Matrix([[0]]), Matrix([[1]]), Matrix([[1]]), Matrix([[0]]))) >>> S5.doit() StateSpace(Matrix([ [-1, 0], [-1, 0]]), Matrix([ [1], [1]]), Matrix([[0, 1]]), Matrix([[0]]))
Notes
All the transfer functions should use the same complex variable
varof the Laplace transform.See also
- doit(**hints)[source]¶
Returns the resultant transfer function or state space obtained after evaluating the series interconnection.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> Series(tf2, tf1).doit() TransferFunction((s**3 - 2)*(a*p**2 + b*s), (-p + s)*(s**4 + 5*s + 6), s) >>> Series(-tf1, -tf2).doit() TransferFunction((2 - s**3)*(-a*p**2 - b*s), (-p + s)*(s**4 + 5*s + 6), s)
Notes
If a series connection contains only TransferFunctionBase components, the equivalent system returned will be a transfer function. However, if a StateSpaceBase object is used in any of the arguments, the output will be a state space object.
- property is_biproper¶
Returns True if degree of the numerator polynomial of the resultant transfer function is equal to degree of the denominator polynomial of the same, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(p, s**2, s) >>> tf3 = TransferFunction(s**2, 1, s) >>> S1 = Series(tf1, -tf2) >>> S1.is_biproper False >>> S2 = Series(tf2, tf3) >>> S2.is_biproper True
- property is_proper¶
Returns True if degree of the numerator polynomial of the resultant transfer function is less than or equal to degree of the denominator polynomial of the same, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*s + 2, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> S1 = Series(-tf2, tf1) >>> S1.is_proper False >>> S2 = Series(tf1, tf2, tf3) >>> S2.is_proper True
- property is_strictly_proper¶
Returns True if degree of the numerator polynomial of the resultant transfer function is strictly less than degree of the denominator polynomial of the same, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**2 + 5*s + 6, s) >>> tf3 = TransferFunction(1, s**2 + s + 1, s) >>> S1 = Series(tf1, tf2) >>> S1.is_strictly_proper False >>> S2 = Series(tf1, tf2, tf3) >>> S2.is_strictly_proper True
- property var¶
Returns the complex variable used by all the transfer functions.
Examples
>>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, Series, Parallel >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> Series(G1, G2).var p >>> Series(-G3, Parallel(G1, G2)).var p
- class sympy.physics.control.lti.Parallel(*args, evaluate=False)[source]¶
A class for representing a parallel configuration of SISO systems.
- Parameters:
args : SISOLinearTimeInvariant
SISO systems in a parallel arrangement.
evaluate : Boolean, Keyword
When passed
True, returns the equivalentParallel(*args).doit(). Set toFalseby default.- Raises:
ValueError
When no argument is passed.
varattribute is not same for every system.TypeError
Any of the passed
*argshas unsupported typeA combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed.
Examples
>>> from sympy import Matrix >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel, Series, StateSpace >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf3 = TransferFunction(p**2, p + s, s) >>> P1 = Parallel(tf1, tf2) >>> P1 Parallel(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)) >>> P1.var s >>> P2 = Parallel(tf2, Series(tf3, -tf1)) >>> P2 Parallel(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), Series(TransferFunction(p**2, p + s, s), TransferFunction(-a*p**2 - b*s, -p + s, s))) >>> P2.var s >>> P3 = Parallel(Series(tf1, tf2), Series(tf2, tf3)) >>> P3 Parallel(Series(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)), Series(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), TransferFunction(p**2, p + s, s))) >>> P3.var s
You can get the resultant transfer function by using
.doit()method:>>> Parallel(tf1, tf2, -tf3).doit() TransferFunction(-p**2*(-p + s)*(s**4 + 5*s + 6) + (-p + s)*(p + s)*(s**3 - 2) + (p + s)*(a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) >>> Parallel(tf2, Series(tf1, -tf3)).doit() TransferFunction(-p**2*(a*p**2 + b*s)*(s**4 + 5*s + 6) + (-p + s)*(p + s)*(s**3 - 2), (-p + s)*(p + s)*(s**4 + 5*s + 6), s)
Parallel can be used to connect SISO
StateSpacesystems together.>>> A1 = Matrix([[-1]]) >>> B1 = Matrix([[1]]) >>> C1 = Matrix([[-1]]) >>> D1 = Matrix([1]) >>> A2 = Matrix([[0]]) >>> B2 = Matrix([[1]]) >>> C2 = Matrix([[1]]) >>> D2 = Matrix([[0]]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss2 = StateSpace(A2, B2, C2, D2) >>> P4 = Parallel(ss1, ss2) >>> P4 Parallel(StateSpace(Matrix([[-1]]), Matrix([[1]]), Matrix([[-1]]), Matrix([[1]])), StateSpace(Matrix([[0]]), Matrix([[1]]), Matrix([[1]]), Matrix([[0]])))
doit()can be used to findStateSpaceequivalent for the system containingStateSpaceobjects.>>> P4.doit() StateSpace(Matrix([ [-1, 0], [ 0, 0]]), Matrix([ [1], [1]]), Matrix([[-1, 1]]), Matrix([[1]])) >>> P4.rewrite(TransferFunction) TransferFunction(s*(s + 1) + 1, s*(s + 1), s)
Notes
All the transfer functions should use the same complex variable
varof the Laplace transform.See also
- doit(**hints)[source]¶
Returns the resultant transfer function or state space obtained by parallel connection of transfer functions or state space objects.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> Parallel(tf2, tf1).doit() TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s) >>> Parallel(-tf1, -tf2).doit() TransferFunction((2 - s**3)*(-p + s) + (-a*p**2 - b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s)
- property is_biproper¶
Returns True if degree of the numerator polynomial of the resultant transfer function is equal to degree of the denominator polynomial of the same, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(p**2, p + s, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> P1 = Parallel(tf1, -tf2) >>> P1.is_biproper True >>> P2 = Parallel(tf2, tf3) >>> P2.is_biproper False
- property is_proper¶
Returns True if degree of the numerator polynomial of the resultant transfer function is less than or equal to degree of the denominator polynomial of the same, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*s + 2, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> P1 = Parallel(-tf2, tf1) >>> P1.is_proper False >>> P2 = Parallel(tf2, tf3) >>> P2.is_proper True
- property is_strictly_proper¶
Returns True if degree of the numerator polynomial of the resultant transfer function is strictly less than degree of the denominator polynomial of the same, else False.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> P1 = Parallel(tf1, tf2) >>> P1.is_strictly_proper False >>> P2 = Parallel(tf2, tf3) >>> P2.is_strictly_proper True
- property var¶
Returns the complex variable used by all the transfer functions.
Examples
>>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, Parallel, Series >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> Parallel(G1, G2).var p >>> Parallel(-G3, Series(G1, G2)).var p
- class sympy.physics.control.lti.Feedback(sys1, sys2=None, sign=-1)[source]¶
A class for representing closed-loop feedback interconnection between two SISO input/output systems.
The first argument,
sys1, is the feedforward part of the closed-loop system or in simple words, the dynamical model representing the process to be controlled. The second argument,sys2, is the feedback system and controls the fed back signal tosys1. Bothsys1andsys2can either beSeries, state space or transfer function objects.- Parameters:
sys1 : Series, StateSpaceBase, TransferFunctionBase
The feedforward path system.
sys2 : Series, StateSpaceBase, TransferFunctionBase, optional
The feedback path system (often a feedback controller). It is the model sitting on the feedback path.
If not specified explicitly, the sys2 is assumed to be unit (1.0) transfer function.
sign : int, optional
The sign of feedback. Can either be
1(for positive feedback) or-1(for negative feedback). Default value is \(-1\).- Raises:
ValueError
When
sys1andsys2are not using the same complex variable of the Laplace transform or z-transform.When a combination of
sys1andsys2yields zero denominator.TypeError
When either
sys1orsys2is not aSeries,StateSpaceBaseorTransferFunctionBaseobject.
Examples
>>> from sympy import Matrix >>> from sympy.abc import s >>> from sympy.physics.control.lti import StateSpace, TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1 Feedback(TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s), TransferFunction(5*s - 10, s + 7, s), -1) >>> F1.var s >>> F1.args (TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s), TransferFunction(5*s - 10, s + 7, s), -1)
You can get the feedforward and feedback path systems by using
.sys1and.sys2respectively.>>> F1.sys1 TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> F1.sys2 TransferFunction(5*s - 10, s + 7, s)
You can get the resultant closed loop transfer function obtained by negative feedback interconnection using
.doit()method.>>> F1.doit() TransferFunction((s + 7)*(s**2 - 4*s + 2)*(3*s**2 + 7*s - 3), ((s + 7)*(s**2 - 4*s + 2) + (5*s - 10)*(3*s**2 + 7*s - 3))*(s**2 - 4*s + 2), s) >>> G = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) >>> C = TransferFunction(5*s + 10, s + 10, s) >>> F2 = Feedback(G*C, TransferFunction(1, 1, s)) >>> F2.doit() TransferFunction((s + 10)*(5*s + 10)*(s**2 + 2*s + 3)*(2*s**2 + 5*s + 1), (s + 10)*((s + 10)*(s**2 + 2*s + 3) + (5*s + 10)*(2*s**2 + 5*s + 1))*(s**2 + 2*s + 3), s)
To negate a
Feedbackobject, the-operator can be prepended:>>> -F1 Feedback(TransferFunction(-3*s**2 - 7*s + 3, s**2 - 4*s + 2, s), TransferFunction(10 - 5*s, s + 7, s), -1) >>> -F2 Feedback(Series(TransferFunction(-1, 1, s), TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s), TransferFunction(5*s + 10, s + 10, s)), TransferFunction(-1, 1, s), -1)
Feedbackcan also be used to connect SISOStateSpacesystems together.>>> A1 = Matrix([[-1]]) >>> B1 = Matrix([[1]]) >>> C1 = Matrix([[-1]]) >>> D1 = Matrix([1]) >>> A2 = Matrix([[0]]) >>> B2 = Matrix([[1]]) >>> C2 = Matrix([[1]]) >>> D2 = Matrix([[0]]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss2 = StateSpace(A2, B2, C2, D2) >>> F3 = Feedback(ss1, ss2) >>> F3 Feedback(StateSpace(Matrix([[-1]]), Matrix([[1]]), Matrix([[-1]]), Matrix([[1]])), StateSpace(Matrix([[0]]), Matrix([[1]]), Matrix([[1]]), Matrix([[0]])), -1)
doit()can be used to findStateSpaceequivalent for the system containingStateSpaceobjects.>>> F3.doit() StateSpace(Matrix([ [-1, -1], [-1, -1]]), Matrix([ [1], [1]]), Matrix([[-1, -1]]), Matrix([[1]]))
We can also find the equivalent
TransferFunctionby usingrewrite(TransferFunction)method.>>> F3.rewrite(TransferFunction) TransferFunction(s, s + 2, s)
See also
- property den¶
Returns the denominator of the closed loop feedback model.
- doit(cancel=False, expand=False, **hints)[source]¶
Returns the resultant transfer function or state space obtained by feedback connection of transfer functions or state space objects.
Examples
>>> from sympy.abc import s >>> from sympy import Matrix >>> from sympy.physics.control.lti import TransferFunction, Feedback, StateSpace >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.doit() TransferFunction((s + 7)*(s**2 - 4*s + 2)*(3*s**2 + 7*s - 3), ((s + 7)*(s**2 - 4*s + 2) + (5*s - 10)*(3*s**2 + 7*s - 3))*(s**2 - 4*s + 2), s) >>> G = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) >>> F2 = Feedback(G, TransferFunction(1, 1, s)) >>> F2.doit() TransferFunction((s**2 + 2*s + 3)*(2*s**2 + 5*s + 1), (s**2 + 2*s + 3)*(3*s**2 + 7*s + 4), s)
Use kwarg
expand=Trueto expand the resultant transfer function. Usecancel=Trueto cancel out the common terms in numerator and denominator.>>> F2.doit(cancel=True, expand=True) TransferFunction(2*s**2 + 5*s + 1, 3*s**2 + 7*s + 4, s) >>> F2.doit(expand=True) TransferFunction(2*s**4 + 9*s**3 + 17*s**2 + 17*s + 3, 3*s**4 + 13*s**3 + 27*s**2 + 29*s + 12, s)
If the connection contain any
StateSpaceobject thendoit()will return the equivalentStateSpaceobject.>>> A1 = Matrix([[-1.5, -2], [1, 0]]) >>> B1 = Matrix([0.5, 0]) >>> C1 = Matrix([[0, 1]]) >>> A2 = Matrix([[0, 1], [-5, -2]]) >>> B2 = Matrix([0, 3]) >>> C2 = Matrix([[0, 1]]) >>> ss1 = StateSpace(A1, B1, C1) >>> ss2 = StateSpace(A2, B2, C2) >>> F3 = Feedback(ss1, ss2) >>> F3.doit() StateSpace(Matrix([ [-1.5, -2, 0, -0.5], [ 1, 0, 0, 0], [ 0, 0, 0, 1], [ 0, 3, -5, -2]]), Matrix([ [0.5], [ 0], [ 0], [ 0]]), Matrix([[0, 1, 0, 0]]), Matrix([[0]]))
- property num¶
Returns the numerator of the closed loop feedback system.
- property sensitivity¶
Returns the sensitivity function of the feedback loop.
Sensitivity of a Feedback system is the ratio of change in the open loop gain to the change in the closed loop gain.
Note
This method would not return the complementary sensitivity function.
Examples
>>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - p, p + 2, p) >>> F_1 = Feedback(P, C) >>> F_1.sensitivity 1/((1 - p)*(5*p + 10)/((p + 2)*(p + 10)) + 1)
- property sign¶
Returns the type of MIMO Feedback model.
1for Positive and-1for Negative.
- property sys1¶
Returns the feedforward system of the feedback interconnection.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.sys1 TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - s, p + 2, p) >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) >>> F2.sys1 TransferFunction(1, 1, p)
- property sys2¶
Returns the feedback controller of the feedback interconnection.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.sys2 TransferFunction(5*s - 10, s + 7, s) >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - s, p + 2, p) >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) >>> F2.sys2 Series(TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p), TransferFunction(5*p + 10, p + 10, p), TransferFunction(1 - s, p + 2, p))
- to_expr()[source]¶
Converts a
Feedbackobject to SymPy Expr.Examples
>>> from sympy.abc import s, a, b >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> from sympy import Expr >>> tf1 = TransferFunction(a+s, 1, s) >>> tf2 = TransferFunction(b+s, 1, s) >>> fd1 = Feedback(tf1, tf2) >>> fd1.to_expr() (a + s)/((a + s)*(b + s) + 1) >>> isinstance(_, Expr) True
- property var¶
Returns the complex variable of the Laplace transform used by all the transfer functions involved in the feedback interconnection.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.var s >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - s, p + 2, p) >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) >>> F2.var p
- class sympy.physics.control.lti.TransferFunctionMatrix(arg)[source]¶
A class for representing the MIMO (multiple-input and multiple-output) generalization of the SISO (single-input and single-output) transfer function.
It is a matrix of transfer functions (
TransferFunction, SISO-Seriesor SISO-Parallel). There is only one argument,argwhich is also the compulsory argument.argis expected to be strictly of the type list of lists which holds the transfer functions or reducible to transfer functions.- Parameters:
arg : Nested
List(strictly).Users are expected to input a nested list of
TransferFunction,Seriesand/orParallelobjects.
Examples
Note
pprint()can be used for better visualization ofTransferFunctionMatrixobjects.>>> from sympy.abc import s, p, a >>> from sympy import pprint >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, Series, Parallel >>> tf_1 = TransferFunction(s + a, s**2 + s + 1, s) >>> tf_2 = TransferFunction(p**4 - 3*p + 2, s + p, s) >>> tf_3 = TransferFunction(3, s + 2, s) >>> tf_4 = TransferFunction(-a + p, 9*s - 9, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1], [tf_2], [tf_3]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(3, s + 2, s),))) >>> tfm_1.var s >>> tfm_1.num_inputs 1 >>> tfm_1.num_outputs 3 >>> tfm_1.shape (3, 1) >>> tfm_1.args (((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(3, s + 2, s),)),) >>> tfm_2 = TransferFunctionMatrix([[tf_1, -tf_3], [tf_2, -tf_1], [tf_3, -tf_2]]) >>> tfm_2 TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(p**4 - 3*p + 2, p + s, s), TransferFunction(-a - s, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)))) >>> pprint(tfm_2, use_unicode=False) # pretty-printing for better visualization [ a + s -3 ] [ ---------- ----- ] [ 2 s + 2 ] [ s + s + 1 ] [ ] [ 4 ] [p - 3*p + 2 -a - s ] [------------ ---------- ] [ p + s 2 ] [ s + s + 1 ] [ ] [ 4 ] [ 3 - p + 3*p - 2] [ ----- --------------] [ s + 2 p + s ]{t}
TransferFunctionMatrix can be transposed, if user wants to switch the input and output transfer functions
>>> tfm_2.transpose() TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(p**4 - 3*p + 2, p + s, s), TransferFunction(3, s + 2, s)), (TransferFunction(-3, s + 2, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)))) >>> pprint(_, use_unicode=False) [ 4 ] [ a + s p - 3*p + 2 3 ] [---------- ------------ ----- ] [ 2 p + s s + 2 ] [s + s + 1 ] [ ] [ 4 ] [ -3 -a - s - p + 3*p - 2] [ ----- ---------- --------------] [ s + 2 2 p + s ] [ s + s + 1 ]{t}
>>> tf_5 = TransferFunction(5, s, s) >>> tf_6 = TransferFunction(5*s, (2 + s**2), s) >>> tf_7 = TransferFunction(5, (s*(2 + s**2)), s) >>> tf_8 = TransferFunction(5, 1, s) >>> tfm_3 = TransferFunctionMatrix([[tf_5, tf_6], [tf_7, tf_8]]) >>> tfm_3 TransferFunctionMatrix(((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)), (TransferFunction(5, s*(s**2 + 2), s), TransferFunction(5, 1, s)))) >>> pprint(tfm_3, use_unicode=False) [ 5 5*s ] [ - ------] [ s 2 ] [ s + 2] [ ] [ 5 5 ] [---------- - ] [ / 2 \ 1 ] [s*\s + 2/ ]{t} >>> tfm_3.var s >>> tfm_3.shape (2, 2) >>> tfm_3.num_outputs 2 >>> tfm_3.num_inputs 2 >>> tfm_3.args (((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)), (TransferFunction(5, s*(s**2 + 2), s), TransferFunction(5, 1, s))),)
To access the
TransferFunctionat any index in theTransferFunctionMatrix, use the index notation.>>> tfm_3[1, 0] # gives the TransferFunction present at 2nd Row and 1st Col. Similar to that in Matrix classes TransferFunction(5, s*(s**2 + 2), s) >>> tfm_3[0, 0] # gives the TransferFunction present at 1st Row and 1st Col. TransferFunction(5, s, s) >>> tfm_3[:, 0] # gives the first column TransferFunctionMatrix(((TransferFunction(5, s, s),), (TransferFunction(5, s*(s**2 + 2), s),))) >>> pprint(_, use_unicode=False) [ 5 ] [ - ] [ s ] [ ] [ 5 ] [----------] [ / 2 \] [s*\s + 2/]{t} >>> tfm_3[0, :] # gives the first row TransferFunctionMatrix(((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)),)) >>> pprint(_, use_unicode=False) [5 5*s ] [- ------] [s 2 ] [ s + 2]{t}
To negate a transfer function matrix,
-operator can be prepended:>>> tfm_4 = TransferFunctionMatrix([[tf_2], [-tf_1], [tf_3]]) >>> -tfm_4 TransferFunctionMatrix(((TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(-3, s + 2, s),))) >>> tfm_5 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, -tf_1]]) >>> -tfm_5 TransferFunctionMatrix(((TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)), (TransferFunction(-3, s + 2, s), TransferFunction(a + s, s**2 + s + 1, s))))
subs()returns theTransferFunctionMatrixobject with the value substituted in the expression. This will not mutate your originalTransferFunctionMatrix.>>> tfm_2.subs(p, 2) # substituting p everywhere in tfm_2 with 2. TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(12, s + 2, s), TransferFunction(-a - s, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-12, s + 2, s)))) >>> pprint(_, use_unicode=False) [ a + s -3 ] [---------- ----- ] [ 2 s + 2 ] [s + s + 1 ] [ ] [ 12 -a - s ] [ ----- ----------] [ s + 2 2 ] [ s + s + 1] [ ] [ 3 -12 ] [ ----- ----- ] [ s + 2 s + 2 ]{t} >>> pprint(tfm_2, use_unicode=False) # State of tfm_2 is unchanged after substitution [ a + s -3 ] [ ---------- ----- ] [ 2 s + 2 ] [ s + s + 1 ] [ ] [ 4 ] [p - 3*p + 2 -a - s ] [------------ ---------- ] [ p + s 2 ] [ s + s + 1 ] [ ] [ 4 ] [ 3 - p + 3*p - 2] [ ----- --------------] [ s + 2 p + s ]{t}
subs()also supports multiple substitutions.>>> tfm_2.subs({p: 2, a: 1}) # substituting p with 2 and a with 1 TransferFunctionMatrix(((TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(12, s + 2, s), TransferFunction(-s - 1, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-12, s + 2, s)))) >>> pprint(_, use_unicode=False) [ s + 1 -3 ] [---------- ----- ] [ 2 s + 2 ] [s + s + 1 ] [ ] [ 12 -s - 1 ] [ ----- ----------] [ s + 2 2 ] [ s + s + 1] [ ] [ 3 -12 ] [ ----- ----- ] [ s + 2 s + 2 ]{t}
Users can reduce the
SeriesandParallelelements of the matrix toTransferFunctionby usingdoit().>>> tfm_6 = TransferFunctionMatrix([[Series(tf_3, tf_4), Parallel(tf_3, tf_4)]]) >>> tfm_6 TransferFunctionMatrix(((Series(TransferFunction(3, s + 2, s), TransferFunction(-a + p, 9*s - 9, s)), Parallel(TransferFunction(3, s + 2, s), TransferFunction(-a + p, 9*s - 9, s))),)) >>> pprint(tfm_6, use_unicode=False) [-a + p 3 -a + p 3 ] [-------*----- ------- + -----] [9*s - 9 s + 2 9*s - 9 s + 2]{t} >>> tfm_6.doit() TransferFunctionMatrix(((TransferFunction(-3*a + 3*p, (s + 2)*(9*s - 9), s), TransferFunction(27*s + (-a + p)*(s + 2) - 27, (s + 2)*(9*s - 9), s)),)) >>> pprint(_, use_unicode=False) [ -3*a + 3*p 27*s + (-a + p)*(s + 2) - 27] [----------------- ----------------------------] [(s + 2)*(9*s - 9) (s + 2)*(9*s - 9) ]{t} >>> tf_9 = TransferFunction(1, s, s) >>> tf_10 = TransferFunction(1, s**2, s) >>> tfm_7 = TransferFunctionMatrix([[Series(tf_9, tf_10), tf_9], [tf_10, Parallel(tf_9, tf_10)]]) >>> tfm_7 TransferFunctionMatrix(((Series(TransferFunction(1, s, s), TransferFunction(1, s**2, s)), TransferFunction(1, s, s)), (TransferFunction(1, s**2, s), Parallel(TransferFunction(1, s, s), TransferFunction(1, s**2, s))))) >>> pprint(tfm_7, use_unicode=False) [ 1 1 ] [---- - ] [ 2 s ] [s*s ] [ ] [ 1 1 1] [ -- -- + -] [ 2 2 s] [ s s ]{t} >>> tfm_7.doit() TransferFunctionMatrix(((TransferFunction(1, s**3, s), TransferFunction(1, s, s)), (TransferFunction(1, s**2, s), TransferFunction(s**2 + s, s**3, s)))) >>> pprint(_, use_unicode=False) [1 1 ] [-- - ] [ 3 s ] [s ] [ ] [ 2 ] [1 s + s] [-- ------] [ 2 3 ] [s s ]{t}
Addition, subtraction, and multiplication of transfer function matrices can form unevaluated
SeriesorParallelobjects.For addition and subtraction: All the transfer function matrices must have the same shape.
For multiplication (C = A * B): The number of inputs of the first transfer function matrix (A) must be equal to the number of outputs of the second transfer function matrix (B).
Also, use pretty-printing (
pprint) to analyse better.>>> tfm_8 = TransferFunctionMatrix([[tf_3], [tf_2], [-tf_1]]) >>> tfm_9 = TransferFunctionMatrix([[-tf_3]]) >>> tfm_10 = TransferFunctionMatrix([[tf_1], [tf_2], [tf_4]]) >>> tfm_11 = TransferFunctionMatrix([[tf_4], [-tf_1]]) >>> tfm_12 = TransferFunctionMatrix([[tf_4, -tf_1, tf_3], [-tf_2, -tf_4, -tf_3]]) >>> tfm_8 + tfm_10 MIMOParallel(TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a + p, 9*s - 9, s),)))) >>> pprint(_, use_unicode=False) [ 3 ] [ a + s ] [ ----- ] [ ---------- ] [ s + 2 ] [ 2 ] [ ] [ s + s + 1 ] [ 4 ] [ ] [p - 3*p + 2] [ 4 ] [------------] + [p - 3*p + 2] [ p + s ] [------------] [ ] [ p + s ] [ -a - s ] [ ] [ ---------- ] [ -a + p ] [ 2 ] [ ------- ] [ s + s + 1 ]{t} [ 9*s - 9 ]{t} >>> -tfm_10 - tfm_8 MIMOParallel(TransferFunctionMatrix(((TransferFunction(-a - s, s**2 + s + 1, s),), (TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a - p, 9*s - 9, s),))), TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),), (TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a + s, s**2 + s + 1, s),)))) >>> pprint(_, use_unicode=False) [ -a - s ] [ -3 ] [ ---------- ] [ ----- ] [ 2 ] [ s + 2 ] [ s + s + 1 ] [ ] [ ] [ 4 ] [ 4 ] [- p + 3*p - 2] [- p + 3*p - 2] + [--------------] [--------------] [ p + s ] [ p + s ] [ ] [ ] [ a + s ] [ a - p ] [ ---------- ] [ ------- ] [ 2 ] [ 9*s - 9 ]{t} [ s + s + 1 ]{t} >>> tfm_12 * tfm_8 MIMOSeries(TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(-a + p, 9*s - 9, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(3, s + 2, s)), (TransferFunction(-p**4 + 3*p - 2, p + s, s), TransferFunction(a - p, 9*s - 9, s), TransferFunction(-3, s + 2, s))))) >>> pprint(_, use_unicode=False) [ 3 ] [ ----- ] [ -a + p -a - s 3 ] [ s + 2 ] [ ------- ---------- -----] [ ] [ 9*s - 9 2 s + 2] [ 4 ] [ s + s + 1 ] [p - 3*p + 2] [ ] *[------------] [ 4 ] [ p + s ] [- p + 3*p - 2 a - p -3 ] [ ] [-------------- ------- -----] [ -a - s ] [ p + s 9*s - 9 s + 2]{t} [ ---------- ] [ 2 ] [ s + s + 1 ]{t} >>> tfm_12 * tfm_8 * tfm_9 MIMOSeries(TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),),)), TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(-a + p, 9*s - 9, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(3, s + 2, s)), (TransferFunction(-p**4 + 3*p - 2, p + s, s), TransferFunction(a - p, 9*s - 9, s), TransferFunction(-3, s + 2, s))))) >>> pprint(_, use_unicode=False) [ 3 ] [ ----- ] [ -a + p -a - s 3 ] [ s + 2 ] [ ------- ---------- -----] [ ] [ 9*s - 9 2 s + 2] [ 4 ] [ s + s + 1 ] [p - 3*p + 2] [ -3 ] [ ] *[------------] *[-----] [ 4 ] [ p + s ] [s + 2]{t} [- p + 3*p - 2 a - p -3 ] [ ] [-------------- ------- -----] [ -a - s ] [ p + s 9*s - 9 s + 2]{t} [ ---------- ] [ 2 ] [ s + s + 1 ]{t} >>> tfm_10 + tfm_8*tfm_9 MIMOParallel(TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a + p, 9*s - 9, s),))), MIMOSeries(TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),),)), TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))))) >>> pprint(_, use_unicode=False) [ a + s ] [ 3 ] [ ---------- ] [ ----- ] [ 2 ] [ s + 2 ] [ s + s + 1 ] [ ] [ ] [ 4 ] [ 4 ] [p - 3*p + 2] [ -3 ] [p - 3*p + 2] + [------------] *[-----] [------------] [ p + s ] [s + 2]{t} [ p + s ] [ ] [ ] [ -a - s ] [ -a + p ] [ ---------- ] [ ------- ] [ 2 ] [ 9*s - 9 ]{t} [ s + s + 1 ]{t}
These unevaluated
SeriesorParallelobjects can convert into the resultant transfer function matrix using.doit()method or by.rewrite(TransferFunctionMatrix).>>> (-tfm_8 + tfm_10 + tfm_8*tfm_9).doit() TransferFunctionMatrix(((TransferFunction((a + s)*(s + 2)**3 - 3*(s + 2)**2*(s**2 + s + 1) - 9*(s + 2)*(s**2 + s + 1), (s + 2)**3*(s**2 + s + 1), s),), (TransferFunction((p + s)*(-3*p**4 + 9*p - 6), (p + s)**2*(s + 2), s),), (TransferFunction((-a + p)*(s + 2)*(s**2 + s + 1)**2 + (a + s)*(s + 2)*(9*s - 9)*(s**2 + s + 1) + (3*a + 3*s)*(9*s - 9)*(s**2 + s + 1), (s + 2)*(9*s - 9)*(s**2 + s + 1)**2, s),))) >>> (-tfm_12 * -tfm_8 * -tfm_9).rewrite(TransferFunctionMatrix) TransferFunctionMatrix(((TransferFunction(3*(-3*a + 3*p)*(p + s)*(s + 2)*(s**2 + s + 1)**2 + 3*(-3*a - 3*s)*(p + s)*(s + 2)*(9*s - 9)*(s**2 + s + 1) + 3*(a + s)*(s + 2)**2*(9*s - 9)*(-p**4 + 3*p - 2)*(s**2 + s + 1), (p + s)*(s + 2)**3*(9*s - 9)*(s**2 + s + 1)**2, s),), (TransferFunction(3*(-a + p)*(p + s)*(s + 2)**2*(-p**4 + 3*p - 2)*(s**2 + s + 1) + 3*(3*a + 3*s)*(p + s)**2*(s + 2)*(9*s - 9) + 3*(p + s)*(s + 2)*(9*s - 9)*(-3*p**4 + 9*p - 6)*(s**2 + s + 1), (p + s)**2*(s + 2)**3*(9*s - 9)*(s**2 + s + 1), s),)))
- elem_poles()[source]¶
Returns the poles of each element of the
TransferFunctionMatrix.Note
Actual poles of a MIMO system are NOT the poles of individual elements.
Examples
>>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> tf_1 = TransferFunction(3, (s + 1), s) >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) >>> tf_4 = TransferFunction(s + 2, s**2 + 5*s - 10, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s + 2, s**2 + 5*s - 10, s)))) >>> tfm_1.elem_poles() [[[-1], [-2, -1]], [[-2, -1], [-5/2 + sqrt(65)/2, -sqrt(65)/2 - 5/2]]]
See also
- elem_zeros()[source]¶
Returns the zeros of each element of the
TransferFunctionMatrix.Note
Actual zeros of a MIMO system are NOT the zeros of individual elements.
Examples
>>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> tf_1 = TransferFunction(3, (s + 1), s) >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) >>> tf_4 = TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s)))) >>> tfm_1.elem_zeros() [[[], [-6]], [[-3], [4, 5]]]
See also
- eval_frequency(other)[source]¶
Evaluates system response of each transfer function in the
TransferFunctionMatrixat any point in the real or complex plane.Examples
>>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> from sympy import I >>> tf_1 = TransferFunction(3, (s + 1), s) >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) >>> tf_4 = TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s)))) >>> tfm_1.eval_frequency(2) Matrix([ [ 1, 2/3], [5/12, 3/2]]) >>> tfm_1.eval_frequency(I*2) Matrix([ [ 3/5 - 6*I/5, -I], [3/20 - 11*I/20, -101/74 + 23*I/74]])
- classmethod from_Matrix(
- matrix,
- var,
- sampling_time=0,
Creates a new
TransferFunctionMatrixefficiently from a SymPy Matrix ofExprobjects.- Parameters:
matrix :
ImmutableMatrixhavingExpr/Numberelements.var : Symbol
Complex variable of the Laplace transform or z-transform which will be used by the all the transfer function objects in the
TransferFunctionMatrix.sampling_time : Number, Symbol, optional
Sampling time for the discrete-time transfer function matrix. Default is 0, which means that the transfer function matrix will be treated as a continuous-time transfer function matrix.
Examples
>>> from sympy.abc import s, z >>> from sympy.physics.control.lti import TransferFunctionMatrix >>> from sympy import Matrix, pprint >>> M = Matrix([[s, 1/s], [1/(s+1), s]]) >>> M_tf = TransferFunctionMatrix.from_Matrix(M, s) >>> pprint(M_tf, use_unicode=False) [ s 1] [ - -] [ 1 s] [ ] [ 1 s] [----- -] [s + 1 1]{t} >>> M_tf.elem_poles() [[[], [0]], [[-1], []]] >>> M_tf.elem_zeros() [[[0], []], [[], [0]]] >>> M_2 = Matrix([[z/(z-1), z/(z-8)], [z**2/(z**2-2+1), z]]) >>> M2_tf = TransferFunctionMatrix.from_Matrix(M_2, z, 0.1) >>> pprint(M2_tf, use_unicode=False) [ z z ] [----- -----] [z - 1 z - 8] [ ] [ 2 ] [ z z ] [------ - ] [ 2 1 ] [z - 1 ]{k} [st: 0.100000000000000]
- property num_inputs¶
Returns the number of inputs of the system.
Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> G1 = TransferFunction(s + 3, s**2 - 3, s) >>> G2 = TransferFunction(4, s**2, s) >>> G3 = TransferFunction(p**2 + s**2, p - 3, s) >>> tfm_1 = TransferFunctionMatrix([[G2, -G1, G3], [-G2, -G1, -G3]]) >>> tfm_1.num_inputs 3
See also
- property num_outputs¶
Returns the number of outputs of the system.
Examples
>>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunctionMatrix >>> from sympy import Matrix >>> M_1 = Matrix([[s], [1/s]]) >>> TFM = TransferFunctionMatrix.from_Matrix(M_1, s) >>> print(TFM) TransferFunctionMatrix(((TransferFunction(s, 1, s),), (TransferFunction(1, s, s),))) >>> TFM.num_outputs 2
See also
- property shape¶
Returns the shape of the transfer function matrix, that is,
(# of outputs, # of inputs).Examples
>>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> tf1 = TransferFunction(p**2 - 1, s**4 + s**3 - p, p) >>> tf2 = TransferFunction(1 - p, p**2 - 3*p + 7, p) >>> tf3 = TransferFunction(3, 4, p) >>> tfm1 = TransferFunctionMatrix([[tf1, -tf2]]) >>> tfm1.shape (1, 2) >>> tfm2 = TransferFunctionMatrix([[-tf2, tf3], [tf1, -tf1]]) >>> tfm2.shape (2, 2)
- transpose()[source]¶
Returns the transpose of the
TransferFunctionMatrix(switched input and output layers).
- property var¶
Returns the complex variable used by all the transfer functions or
Series/Parallelobjects in a transfer function matrix.Examples
>>> from sympy.abc import p, s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, Series, Parallel >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> G4 = TransferFunction(s + 1, s**2 + s + 1, s) >>> S1 = Series(G1, G2) >>> S2 = Series(-G3, Parallel(G2, -G1)) >>> tfm1 = TransferFunctionMatrix([[G1], [G2], [G3]]) >>> tfm1.var p >>> tfm2 = TransferFunctionMatrix([[-S1, -S2], [S1, S2]]) >>> tfm2.var p >>> tfm3 = TransferFunctionMatrix([[G4]]) >>> tfm3.var s
- class sympy.physics.control.lti.PIDController(kp=kp, ki=ki, kd=kd, tf=0, var=s)[source]¶
A class for representing PID (Proportional-Integral-Derivative) controllers in control systems. The PIDController class is a subclass of TransferFunction, representing the controller’s transfer function in the Laplace domain. The arguments are
kp,ki,kd,tf, andvar, wherekp,ki, andkdare the proportional, integral, and derivative gains respectively.``tf`` is the derivative filter time constant, which can be used to filter out the noise andvaris the complex variable used in the transfer function.- Parameters:
kp : Expr, Number
Proportional gain. Defaults to
Symbol('kp')if not specified.ki : Expr, Number
Integral gain. Defaults to
Symbol('ki')if not specified.kd : Expr, Number
Derivative gain. Defaults to
Symbol('kd')if not specified.tf : Expr, Number
Derivative filter time constant. Defaults to
0if not specified.var : Symbol
The complex frequency variable. Defaults to
sif not specified.
Examples
>>> from sympy import symbols >>> from sympy.physics.control.lti import PIDController >>> kp, ki, kd = symbols('kp ki kd') >>> p1 = PIDController(kp, ki, kd) >>> print(p1) PIDController(kp, ki, kd, 0, s) >>> p1.doit() TransferFunction(kd*s**2 + ki + kp*s, s, s) >>> p1.kp kp >>> p1.ki ki >>> p1.kd kd >>> p1.tf 0 >>> p1.var s >>> p1.to_expr() (kd*s**2 + ki + kp*s)/s
See also
References
- property kd¶
Returns the Derivative gain (kd) of the PIDController.
- property ki¶
Returns the Integral gain (ki) of the PIDController.
- property kp¶
Returns the Proportional gain (kp) of the PIDController.
- property tf¶
Returns the Derivative filter time constant (tf) of the PIDController.
- class sympy.physics.control.lti.MIMOSeries(*args, evaluate=False)[source]¶
A class for representing a series configuration of MIMO systems.
- Parameters:
args : MIMOLinearTimeInvariant
MIMO systems in a series configuration.
evaluate : Boolean, Keyword
When passed
True, returns the equivalentMIMOSeries(*args).doit(). Set toFalseby default.- Raises:
ValueError
When no argument is passed.
varattribute is not same for every system.num_outputsof the MIMO system is not equal to thenum_inputsof its adjacent MIMO system. (Matrix multiplication constraint, basically)TypeError
Any of the passed
*argshas unsupported typeA combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed, MIMO in this case.
Examples
>>> from sympy.abc import s >>> from sympy.physics.control.lti import MIMOSeries, TransferFunctionMatrix, StateSpace >>> from sympy import Matrix, pprint >>> mat_a = Matrix([[5*s], [5]]) # 2 Outputs 1 Input >>> mat_b = Matrix([[5, 1/(6*s**2)]]) # 1 Output 2 Inputs >>> mat_c = Matrix([[1, s], [5/s, 1]]) # 2 Outputs 2 Inputs >>> tfm_a = TransferFunctionMatrix.from_Matrix(mat_a, s) >>> tfm_b = TransferFunctionMatrix.from_Matrix(mat_b, s) >>> tfm_c = TransferFunctionMatrix.from_Matrix(mat_c, s) >>> MIMOSeries(tfm_c, tfm_b, tfm_a) MIMOSeries(TransferFunctionMatrix(((TransferFunction(1, 1, s), TransferFunction(s, 1, s)), (TransferFunction(5, s, s), TransferFunction(1, 1, s)))), TransferFunctionMatrix(((TransferFunction(5, 1, s), TransferFunction(1, 6*s**2, s)),)), TransferFunctionMatrix(((TransferFunction(5*s, 1, s),), (TransferFunction(5, 1, s),)))) >>> pprint(_, use_unicode=False) # For Better Visualization [5*s] [1 s] [---] [5 1 ] [- -] [ 1 ] [- ----] [1 1] [ ] *[1 2] *[ ] [ 5 ] [ 6*s ]{t} [5 1] [ - ] [- -] [ 1 ]{t} [s 1]{t} >>> MIMOSeries(tfm_c, tfm_b, tfm_a).doit() TransferFunctionMatrix(((TransferFunction(150*s**4 + 25*s, 6*s**3, s), TransferFunction(150*s**4 + 5*s, 6*s**2, s)), (TransferFunction(150*s**3 + 25, 6*s**3, s), TransferFunction(150*s**3 + 5, 6*s**2, s)))) >>> pprint(_, use_unicode=False) # (2 Inputs -A-> 2 Outputs) -> (2 Inputs -B-> 1 Output) -> (1 Input -C-> 2 Outputs) is equivalent to (2 Inputs -Series Equivalent-> 2 Outputs). [ 4 4 ] [150*s + 25*s 150*s + 5*s] [------------- ------------] [ 3 2 ] [ 6*s 6*s ] [ ] [ 3 3 ] [ 150*s + 25 150*s + 5 ] [ ----------- ---------- ] [ 3 2 ] [ 6*s 6*s ]{t} >>> a1 = Matrix([[4, 1], [2, -3]]) >>> b1 = Matrix([[5, 2], [-3, -3]]) >>> c1 = Matrix([[2, -4], [0, 1]]) >>> d1 = Matrix([[3, 2], [1, -1]]) >>> a2 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) >>> b2 = Matrix([[1, 4], [-3, -3], [-2, 1]]) >>> c2 = Matrix([[4, 2, -3], [1, 4, 3]]) >>> d2 = Matrix([[-2, 4], [0, 1]]) >>> ss1 = StateSpace(a1, b1, c1, d1) #2 inputs, 2 outputs >>> ss2 = StateSpace(a2, b2, c2, d2) #2 inputs, 2 outputs >>> S1 = MIMOSeries(ss1, ss2) #(2 inputs, 2 outputs) -> (2 inputs, 2 outputs) >>> S1 MIMOSeries(StateSpace(Matrix([ [4, 1], [2, -3]]), Matrix([ [ 5, 2], [-3, -3]]), Matrix([ [2, -4], [0, 1]]), Matrix([ [3, 2], [1, -1]])), StateSpace(Matrix([ [-3, 4, 2], [-1, -3, 0], [ 2, 5, 3]]), Matrix([ [ 1, 4], [-3, -3], [-2, 1]]), Matrix([ [4, 2, -3], [1, 4, 3]]), Matrix([ [-2, 4], [ 0, 1]]))) >>> S1.doit() StateSpace(Matrix([ [ 4, 1, 0, 0, 0], [ 2, -3, 0, 0, 0], [ 2, 0, -3, 4, 2], [-6, 9, -1, -3, 0], [-4, 9, 2, 5, 3]]), Matrix([ [ 5, 2], [ -3, -3], [ 7, -2], [-12, -3], [ -5, -5]]), Matrix([ [-4, 12, 4, 2, -3], [ 0, 1, 1, 4, 3]]), Matrix([ [-2, -8], [ 1, -1]]))
Notes
All the transfer function matrices should use the same complex variable
varof the Laplace transform.MIMOSeries(A, B)is not equivalent toA*B. It is always in the reverse order, that isB*A.See also
- doit(cancel=False, **kwargs)[source]¶
Returns the resultant obtained after evaluating the MIMO systems arranged in a series configuration. For transfer function systems it returns a TransferFunctionMatrix and for state space systems it returns the resultant state space system.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, MIMOSeries, TransferFunctionMatrix >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tfm1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf2]]) >>> tfm2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf1]]) >>> MIMOSeries(tfm2, tfm1).doit() TransferFunctionMatrix(((TransferFunction(2*(-p + s)*(s**3 - 2)*(a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)**2*(s**4 + 5*s + 6)**2, s), TransferFunction((-p + s)**2*(s**3 - 2)*(a*p**2 + b*s) + (-p + s)*(a*p**2 + b*s)**2*(s**4 + 5*s + 6), (-p + s)**3*(s**4 + 5*s + 6), s)), (TransferFunction((-p + s)*(s**3 - 2)**2*(s**4 + 5*s + 6) + (s**3 - 2)*(a*p**2 + b*s)*(s**4 + 5*s + 6)**2, (-p + s)*(s**4 + 5*s + 6)**3, s), TransferFunction(2*(s**3 - 2)*(a*p**2 + b*s), (-p + s)*(s**4 + 5*s + 6), s))))
- property num_inputs¶
Returns the number of input signals of the series system.
- property num_outputs¶
Returns the number of output signals of the series system.
- property shape¶
Returns the shape of the equivalent MIMO system.
- property var¶
Returns the complex variable used by all the transfer functions.
Examples
>>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, MIMOSeries, TransferFunctionMatrix >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> tfm_1 = TransferFunctionMatrix([[G1, G2, G3]]) >>> tfm_2 = TransferFunctionMatrix([[G1], [G2], [G3]]) >>> MIMOSeries(tfm_2, tfm_1).var p
- class sympy.physics.control.lti.MIMOParallel(*args, evaluate=False)[source]¶
A class for representing a parallel configuration of MIMO systems.
- Parameters:
args : MIMOLinearTimeInvariant
MIMO Systems in a parallel arrangement.
evaluate : Boolean, Keyword
When passed
True, returns the equivalentMIMOParallel(*args).doit(). Set toFalseby default.- Raises:
ValueError
When no argument is passed.
varattribute is not same for every system.All MIMO systems passed do not have same shape.
TypeError
Any of the passed
*argshas unsupported typeA combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed, MIMO in this case.
Examples
>>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunctionMatrix, MIMOParallel, StateSpace >>> from sympy import Matrix, pprint >>> expr_1 = 1/s >>> expr_2 = s/(s**2-1) >>> expr_3 = (2 + s)/(s**2 - 1) >>> expr_4 = 5 >>> tfm_a = TransferFunctionMatrix.from_Matrix(Matrix([[expr_1, expr_2], [expr_3, expr_4]]), s) >>> tfm_b = TransferFunctionMatrix.from_Matrix(Matrix([[expr_2, expr_1], [expr_4, expr_3]]), s) >>> tfm_c = TransferFunctionMatrix.from_Matrix(Matrix([[expr_3, expr_4], [expr_1, expr_2]]), s) >>> MIMOParallel(tfm_a, tfm_b, tfm_c) MIMOParallel(TransferFunctionMatrix(((TransferFunction(1, s, s), TransferFunction(s, s**2 - 1, s)), (TransferFunction(s + 2, s**2 - 1, s), TransferFunction(5, 1, s)))), TransferFunctionMatrix(((TransferFunction(s, s**2 - 1, s), TransferFunction(1, s, s)), (TransferFunction(5, 1, s), TransferFunction(s + 2, s**2 - 1, s)))), TransferFunctionMatrix(((TransferFunction(s + 2, s**2 - 1, s), TransferFunction(5, 1, s)), (TransferFunction(1, s, s), TransferFunction(s, s**2 - 1, s))))) >>> pprint(_, use_unicode=False) # For Better Visualization [ 1 s ] [ s 1 ] [s + 2 5 ] [ - ------] [------ - ] [------ - ] [ s 2 ] [ 2 s ] [ 2 1 ] [ s - 1] [s - 1 ] [s - 1 ] [ ] + [ ] + [ ] [s + 2 5 ] [ 5 s + 2 ] [ 1 s ] [------ - ] [ - ------] [ - ------] [ 2 1 ] [ 1 2 ] [ s 2 ] [s - 1 ]{t} [ s - 1]{t} [ s - 1]{t} >>> MIMOParallel(tfm_a, tfm_b, tfm_c).doit() TransferFunctionMatrix(((TransferFunction(s**2 + s*(2*s + 2) - 1, s*(s**2 - 1), s), TransferFunction(2*s**2 + 5*s*(s**2 - 1) - 1, s*(s**2 - 1), s)), (TransferFunction(s**2 + s*(s + 2) + 5*s*(s**2 - 1) - 1, s*(s**2 - 1), s), TransferFunction(5*s**2 + 2*s - 3, s**2 - 1, s)))) >>> pprint(_, use_unicode=False) [ 2 2 / 2 \ ] [ s + s*(2*s + 2) - 1 2*s + 5*s*\s - 1/ - 1] [ -------------------- -----------------------] [ / 2 \ / 2 \ ] [ s*\s - 1/ s*\s - 1/ ] [ ] [ 2 / 2 \ 2 ] [s + s*(s + 2) + 5*s*\s - 1/ - 1 5*s + 2*s - 3 ] [--------------------------------- -------------- ] [ / 2 \ 2 ] [ s*\s - 1/ s - 1 ]{t}
MIMOParallelcan also be used to connect MIMOStateSpacesystems.>>> A1 = Matrix([[4, 1], [2, -3]]) >>> B1 = Matrix([[5, 2], [-3, -3]]) >>> C1 = Matrix([[2, -4], [0, 1]]) >>> D1 = Matrix([[3, 2], [1, -1]]) >>> A2 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) >>> B2 = Matrix([[1, 4], [-3, -3], [-2, 1]]) >>> C2 = Matrix([[4, 2, -3], [1, 4, 3]]) >>> D2 = Matrix([[-2, 4], [0, 1]]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss2 = StateSpace(A2, B2, C2, D2) >>> p1 = MIMOParallel(ss1, ss2) >>> p1 MIMOParallel(StateSpace(Matrix([ [4, 1], [2, -3]]), Matrix([ [ 5, 2], [-3, -3]]), Matrix([ [2, -4], [0, 1]]), Matrix([ [3, 2], [1, -1]])), StateSpace(Matrix([ [-3, 4, 2], [-1, -3, 0], [ 2, 5, 3]]), Matrix([ [ 1, 4], [-3, -3], [-2, 1]]), Matrix([ [4, 2, -3], [1, 4, 3]]), Matrix([ [-2, 4], [ 0, 1]])))
doit()can be used to findStateSpaceequivalent for the system containingStateSpaceobjects.>>> p1.doit() StateSpace(Matrix([ [4, 1, 0, 0, 0], [2, -3, 0, 0, 0], [0, 0, -3, 4, 2], [0, 0, -1, -3, 0], [0, 0, 2, 5, 3]]), Matrix([ [ 5, 2], [-3, -3], [ 1, 4], [-3, -3], [-2, 1]]), Matrix([ [2, -4, 4, 2, -3], [0, 1, 1, 4, 3]]), Matrix([ [1, 6], [1, 0]]))
Notes
All the transfer function matrices should use the same complex variable
varof the Laplace transform.See also
- doit(**hints)[source]¶
Returns the resultant transfer function matrix or StateSpace obtained after evaluating the MIMO systems arranged in a parallel configuration.
Examples
>>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, MIMOParallel, TransferFunctionMatrix >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) >>> MIMOParallel(tfm_1, tfm_2).doit() TransferFunctionMatrix(((TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s), TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s)), (TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s), TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s))))
- property num_inputs¶
Returns the number of input signals of the parallel system.
- property num_outputs¶
Returns the number of output signals of the parallel system.
- property shape¶
Returns the shape of the equivalent MIMO system.
- property var¶
Returns the complex variable used by all the systems.
Examples
>>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOParallel >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> G4 = TransferFunction(p**2, p**2 - 1, p) >>> tfm_a = TransferFunctionMatrix([[G1, G2], [G3, G4]]) >>> tfm_b = TransferFunctionMatrix([[G2, G1], [G4, G3]]) >>> MIMOParallel(tfm_a, tfm_b).var p
- class sympy.physics.control.lti.MIMOFeedback(sys1, sys2, sign=-1)[source]¶
A class for representing closed-loop feedback interconnection between two MIMO input/output systems.
- Parameters:
sys1 : MIMOSeries, TransferFunctionMatrix, StateSpaceBase
The MIMO system placed on the feedforward path.
sys2 : MIMOSeries, TransferFunctionMatrix, StateSpaceBase
The system placed on the feedback path (often a feedback controller).
sign : int, optional
The sign of feedback. Can either be
1(for positive feedback) or-1(for negative feedback). Default value is \(-1\).- Raises:
ValueError
When
sys1andsys2are not using the same complex variable of the Laplace transform or z-transform.Forward path model should have an equal number of inputs/outputs to the feedback path outputs/inputs.
When product of
sys1andsys2is not a square matrix.When the equivalent MIMO system is not invertible.
TypeError
When either
sys1orsys2is not aMIMOSeries,TransferFunctionMatrixor aStateSpaceBaseobject.
Examples
>>> from sympy import Matrix, pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import StateSpace, TransferFunctionMatrix, MIMOFeedback >>> plant_mat = Matrix([[1, 1/s], [0, 1]]) >>> controller_mat = Matrix([[10, 0], [0, 10]]) # Constant Gain >>> plant = TransferFunctionMatrix.from_Matrix(plant_mat, s) >>> controller = TransferFunctionMatrix.from_Matrix(controller_mat, s) >>> feedback = MIMOFeedback(plant, controller) # Negative Feedback (default) >>> pprint(feedback, use_unicode=False) / [1 1] [10 0 ] \-1 [1 1] | [- -] [-- - ] | [- -] | [1 s] [1 1 ] | [1 s] |I + [ ] *[ ] | * [ ] | [0 1] [0 10] | [0 1] | [- -] [- --] | [- -] \ [1 1]{t} [1 1 ]{t}/ [1 1]{t}
To get the equivalent system matrix, use either
doitorrewritemethod.>>> pprint(feedback.doit(), use_unicode=False) [1 1 ] [-- -----] [11 121*s] [ ] [0 1 ] [- -- ] [1 11 ]{t}
To negate the
MIMOFeedbackobject, use-operator.>>> neg_feedback = -feedback >>> pprint(neg_feedback.doit(), use_unicode=False) [-1 -1 ] [--- -----] [11 121*s] [ ] [ 0 -1 ] [ - --- ] [ 1 11 ]{t}
MIMOFeedbackcan also be used to connect MIMOStateSpacesystems.>>> A1 = Matrix([[4, 1], [2, -3]]) >>> B1 = Matrix([[5, 2], [-3, -3]]) >>> C1 = Matrix([[2, -4], [0, 1]]) >>> D1 = Matrix([[3, 2], [1, -1]]) >>> A2 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) >>> B2 = Matrix([[1, 4], [-3, -3], [-2, 1]]) >>> C2 = Matrix([[4, 2, -3], [1, 4, 3]]) >>> D2 = Matrix([[-2, 4], [0, 1]]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss2 = StateSpace(A2, B2, C2, D2) >>> F1 = MIMOFeedback(ss1, ss2) >>> F1 MIMOFeedback(StateSpace(Matrix([ [4, 1], [2, -3]]), Matrix([ [ 5, 2], [-3, -3]]), Matrix([ [2, -4], [0, 1]]), Matrix([ [3, 2], [1, -1]])), StateSpace(Matrix([ [-3, 4, 2], [-1, -3, 0], [ 2, 5, 3]]), Matrix([ [ 1, 4], [-3, -3], [-2, 1]]), Matrix([ [4, 2, -3], [1, 4, 3]]), Matrix([ [-2, 4], [ 0, 1]])), -1)
doit()can be used to findStateSpaceequivalent for the system containingStateSpaceobjects.>>> F1.doit() StateSpace(Matrix([ [ 3, -3/4, -15/4, -37/2, -15], [ 7/2, -39/8, 9/8, 39/4, 9], [ 3, -41/4, -45/4, -51/2, -19], [-9/2, 129/8, 73/8, 171/4, 36], [-3/2, 47/8, 31/8, 85/4, 18]]), Matrix([ [-1/4, 19/4], [ 3/8, -21/8], [ 1/4, 29/4], [ 3/8, -93/8], [ 5/8, -35/8]]), Matrix([ [ 1, -15/4, -7/4, -21/2, -9], [1/2, -13/8, -13/8, -19/4, -3]]), Matrix([ [-1/4, 11/4], [ 1/8, 9/8]]))
See also
- doit(
- cancel=True,
- expand=False,
- **hints,
Returns the resultant transfer function matrix obtained by the feedback interconnection.
Examples
>>> from sympy import pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(s, 1 - s, s) >>> tf2 = TransferFunction(1, s, s) >>> tf3 = TransferFunction(5, 1, s) >>> tf4 = TransferFunction(s - 1, s, s) >>> tf5 = TransferFunction(0, 1, s) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) >>> sys2 = TransferFunctionMatrix([[tf3, tf5], [tf5, tf5]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) >>> pprint(F_1, use_unicode=False) / [ s 1 ] [5 0] \-1 [ s 1 ] | [----- - ] [- -] | [----- - ] | [1 - s s ] [1 1] | [1 - s s ] |I - [ ] *[ ] | * [ ] | [ 5 s - 1] [0 0] | [ 5 s - 1] | [ - -----] [- -] | [ - -----] \ [ 1 s ]{t} [1 1]{t}/ [ 1 s ]{t} >>> pprint(F_1.doit(), use_unicode=False) [ -s s - 1 ] [------- ----------- ] [6*s - 1 s*(6*s - 1) ] [ ] [5*s - 5 (s - 1)*(6*s + 24)] [------- ------------------] [6*s - 1 s*(6*s - 1) ]{t}
If the user wants the resultant
TransferFunctionMatrixobject without canceling the common factors then thecancelkwarg should be passedFalse.>>> pprint(F_1.doit(cancel=False), use_unicode=False) [ s*(s - 1) s - 1 ] [ ----------------- ----------- ] [ (1 - s)*(6*s - 1) s*(6*s - 1) ] [ ] [s*(25*s - 25) + 5*(1 - s)*(6*s - 1) s*(s - 1)*(6*s - 1) + s*(25*s - 25)] [----------------------------------- -----------------------------------] [ (1 - s)*(6*s - 1) 2 ] [ s *(6*s - 1) ]{t}
If the user wants the expanded form of the resultant transfer function matrix, the
expandkwarg should be passed asTrue.>>> pprint(F_1.doit(expand=True), use_unicode=False) [ -s s - 1 ] [------- -------- ] [6*s - 1 2 ] [ 6*s - s ] [ ] [ 2 ] [5*s - 5 6*s + 18*s - 24] [------- ----------------] [6*s - 1 2 ] [ 6*s - s ]{t}
- property num_inputs¶
Returns the number of inputs of the system.
- property num_outputs¶
Returns the number of outputs of the system.
- property sensitivity¶
Returns the sensitivity function matrix of the feedback loop.
Sensitivity of a closed-loop system is the ratio of change in the open loop gain to the change in the closed loop gain.
Note
This method would not return the complementary sensitivity function.
Examples
>>> from sympy import pprint >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(p, 1 - p, p) >>> tf2 = TransferFunction(1, p, p) >>> tf3 = TransferFunction(1, 1, p) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) # Positive feedback >>> F_2 = MIMOFeedback(sys1, sys2) # Negative feedback >>> pprint(F_1.sensitivity, use_unicode=False) [ 4 3 2 5 4 2 ] [- p + 3*p - 4*p + 3*p - 1 p - 2*p + 3*p - 3*p + 1 ] [---------------------------- -----------------------------] [ 4 3 2 5 4 3 2 ] [ p + 3*p - 8*p + 8*p - 3 p + 3*p - 8*p + 8*p - 3*p] [ ] [ 4 3 2 3 2 ] [ p - p - p + p 3*p - 6*p + 4*p - 1 ] [ -------------------------- -------------------------- ] [ 4 3 2 4 3 2 ] [ p + 3*p - 8*p + 8*p - 3 p + 3*p - 8*p + 8*p - 3 ] >>> pprint(F_2.sensitivity, use_unicode=False) [ 4 3 2 5 4 2 ] [p - 3*p + 2*p + p - 1 p - 2*p + 3*p - 3*p + 1] [------------------------ --------------------------] [ 4 3 5 4 2 ] [ p - 3*p + 2*p - 1 p - 3*p + 2*p - p ] [ ] [ 4 3 2 4 3 ] [ p - p - p + p 2*p - 3*p + 2*p - 1 ] [ ------------------- --------------------- ] [ 4 3 4 3 ] [ p - 3*p + 2*p - 1 p - 3*p + 2*p - 1 ]
- property sign¶
Returns the type of feedback interconnection of two models.
1for Positive and-1for Negative.
- property sys1¶
Returns the system placed on the feedforward path of the MIMO feedback interconnection.
Examples
>>> from sympy import pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(s**2 + s + 1, s**2 - s + 1, s) >>> tf2 = TransferFunction(1, s, s) >>> tf3 = TransferFunction(1, 1, s) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf3, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) >>> F_1.sys1 TransferFunctionMatrix(((TransferFunction(s**2 + s + 1, s**2 - s + 1, s), TransferFunction(1, s, s)), (TransferFunction(1, s, s), TransferFunction(s**2 + s + 1, s**2 - s + 1, s)))) >>> pprint(_, use_unicode=False) [ 2 ] [s + s + 1 1 ] [---------- - ] [ 2 s ] [s - s + 1 ] [ ] [ 2 ] [ 1 s + s + 1] [ - ----------] [ s 2 ] [ s - s + 1]{t}
- property sys2¶
Returns the feedback controller of the MIMO feedback interconnection.
Examples
>>> from sympy import pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(s**2, s**3 - s + 1, s) >>> tf2 = TransferFunction(1, s, s) >>> tf3 = TransferFunction(1, 1, s) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2) >>> F_1.sys2 TransferFunctionMatrix(((TransferFunction(s**2, s**3 - s + 1, s), TransferFunction(1, 1, s)), (TransferFunction(1, 1, s), TransferFunction(1, s, s)))) >>> pprint(_, use_unicode=False) [ 2 ] [ s 1] [---------- -] [ 3 1] [s - s + 1 ] [ ] [ 1 1] [ - -] [ 1 s]{t}
- property var¶
Returns the complex variable of the Laplace transform used by all the transfer functions involved in the MIMO feedback loop.
Examples
>>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(p, 1 - p, p) >>> tf2 = TransferFunction(1, p, p) >>> tf3 = TransferFunction(1, 1, p) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) # Positive feedback >>> F_1.var p
- sympy.physics.control.lti.create_state_space(A, B, C, D, sampling_time=0)[source]¶
Creates a new state space object. sampling_time == 0 means continuous time state space. sampling_time > 0 means discrete time state space.
- Parameters:
sampling_time : Symbol, Number, optional
Default is 0. Time interval between two consecutive sampling instants. If sampling_time == 0, it is a continuous time state space, else it is a discrete time state space.
Examples
>>> from sympy import Matrix >>> from sympy.abc import t >>> from sympy.physics.control.lti import create_state_space >>> A = Matrix([[1,0],[0,1]]) >>> B = Matrix([1,0]) >>> C = Matrix([1,0]).T >>> D = Matrix([0]) >>> create_state_space(A, B, C, D) StateSpace(Matrix([ [1, 0], [0, 1]]), Matrix([ [1], [0]]), Matrix([[1, 0]]), Matrix([[0]])) >>> create_state_space(A, B, C, D, t) DiscreteStateSpace(Matrix([ [1, 0], [0, 1]]), Matrix([ [1], [0]]), Matrix([[1, 0]]), Matrix([[0]]), t)
See also
- class sympy.physics.control.lti.StateSpaceBase(
- A=None,
- B=None,
- C=None,
- D=None,
- *args,
- **kwargs,
Base class for state space objects. This class is not meant to be used directly.
- Parameters:
A : Matrix, optional
The State matrix of the state space model.
B : Matrix, optional
The Input-to-State matrix of the state space model.
C : Matrix, optional
The State-to-Output matrix of the state space model.
D : Matrix, optional
The Feedthrough matrix of the state space model.
*args, **kwargs:
Additional arguments and keyword arguments that are passed to the parent class such as sampling time for discrete-time systems.
Explanation
State space model (ssm) of a linear, time invariant control system.
Represents the standard state-space model with A, B, C, D as state-space matrices. This makes the linear control system:
- For continuous-time systems:
x’(t) = A * x(t) + B * u(t); x in R^n , u in R^k
y(t) = C * x(t) + D * u(t); y in R^m
- For discrete-time systems:
x[k+1] = A * x[k] + B * u[k]; x in R^n , u in R^k
y[k] = C * x[k] + D * u[k]; y in R^m
where u(t) or u[k] is any input signal, y(t) or y[k] the corresponding output, and x(t) or x[k] the system’s state.
See also
StateSpace,DiscreteStateSpace,TransferFunction,DiscreteTransferFunction,TransferFunctionMatrixReferences
- property A¶
Returns the state matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.state_matrix Matrix([ [1, 2], [1, 0]])
- property B¶
Returns the input matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.input_matrix Matrix([ [1], [1]])
- property C¶
Returns the output matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.output_matrix Matrix([[0, 1]])
- property D¶
Returns the feedforward matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.feedforward_matrix Matrix([[0]])
- apply_similarity_transform(
- transform_matrix,
Returns an algebrically equivalent state space model, based on the transformation matrix \(T\) such that:
\[\begin{split}\begin{cases} \bar A=T^{-1}AT\\ \bar B=T^{-1}B\\ \bar C=CT\\ \bar D=D\end{cases}\end{split}\]- Parameters:
transform_matrix : Matrix
The transformation matrix \(T\) to be applied to the state space model. The transformation matrix must be invertible and have the same dimensions as the state matrix \(A\).
- Returns:
StateSpace
The transformed state space model.
Examples
>>> from sympy import Matrix, Rational >>> from sympy.physics.control import StateSpace >>> A = Matrix([[5, -2, 2], [0, 1, -4], [0, 0, -3]]) >>> B = Matrix([1,0,0]) >>> C = Matrix([1, 0, 0]).T >>> ss = StateSpace(A, B, C) >>> T = Matrix([[0, Rational(1, 2), 1], [1, 1, 0], [1, 0, 0]]) >>> ss.apply_similarity_transform(T).A Matrix([ [-3, 0, 0], [ 0, 1, 0], [ 0, 0, 5]])
- controllability_matrix()[source]¶
- Returns the controllability matrix of the system:
[B, A * B, A^2 * B, .. , A^(n-1) * B]; A in R^(n x n), B in R^(n x m)
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-1.5, -2], [1, 0]]) >>> B = Matrix([0.5, 0]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([1]) >>> ss = StateSpace(A, B, C, D) >>> ss.controllability_matrix() Matrix([ [0.5, -0.75], [ 0, 0.5]])
References
- controllable_subspace()[source]¶
Returns the controllable subspace of the state space model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-1.5, -2], [1, 0]]) >>> B = Matrix([0.5, 0]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([1]) >>> ss = StateSpace(A, B, C, D) >>> co_subspace = ss.controllable_subspace() >>> co_subspace [Matrix([ [0.5], [ 0]]), Matrix([ [-0.75], [ 0.5]])]
- property feedforward_matrix¶
Returns the feedforward matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.feedforward_matrix Matrix([[0]])
- abstractmethod get_asymptotic_stability_conditions(
- fast=False,
Returns the asymptotic stability conditions for the state space.
This is a convenient shorthand, based on the system type (continuous or discrete), for:
[c > 0 for c in sys.A.charpoly().hurwitz_conditions()]which gives conditions for stability such that the eigenvalues of the A matrix are in the left half of the complex plane.[c > 0 for c in sys.A.charpoly().schur_conditions()]which gives conditions for stability such that the eigenvalues of the A matrix lie inside the unit circle.
For some systems that are larger or have more complicated expressions it might be useful to set
fasttoTrue. The algorithm will use the EXRAW domain which will quickly generate large unsimplified expressions that are mostly only suitable for use with lambdify.- Parameters:
fast : Boolean
If True, uses the EXRAW domain to quickly generate large unsimplified expressions. If False, uses the default domain which is suitable for symbolic manipulation.
Notes
In the discrete case, using
fast = Truemay lead to significant precision issues.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> from sympy import symbols, reduce_inequalities >>> k = symbols('k') >>> A = Matrix([[0,1,0],[0,0,1], [k-1, -2*k, -1]]) >>> B = Matrix([1, 0, 0]) >>> C = Matrix([[0, 1, 0]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ineq = ss.get_asymptotic_stability_conditions() >>> ineq [True, 3*k - 1 > 0, 1 - k > 0] >>> reduce_inequalities(ineq) (1/3 < k) & (k < 1)
- property input_matrix¶
Returns the input matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.input_matrix Matrix([ [1], [1]])
- is_controllable()[source]¶
Returns conditions for the state space model to be controllable.
Examples
>>> from sympy import symbols, Matrix >>> from sympy.physics.control import StateSpace >>> A1 = Matrix([[-1.5, -2], [1, 0]]) >>> B1 = Matrix([0.5, 0]) >>> C1 = Matrix([[0, 1]]) >>> D1 = Matrix([1]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss1.is_controllable() True
>>> a = symbols("a") >>> A2 = Matrix([[1, 0, 1], [1, 1, 0], [0, 0, a]]) >>> B2 = Matrix([0.5, 1, 1]) >>> C2 = Matrix([[0, 1, 0]]) >>> ss2 = StateSpace(A2, B2, C2)
- is_observable()[source]¶
Returns conditions for the state space model to be observable.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A1 = Matrix([[-1.5, -2], [1, 0]]) >>> B1 = Matrix([0.5, 0]) >>> C1 = Matrix([[0, 1]]) >>> D1 = Matrix([1]) >>> ss1 = StateSpace(A1, B1, C1, D1) >>> ss1.is_observable() True
- property num_inputs¶
Returns the number of inputs of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.num_inputs 1
- property num_outputs¶
Returns the number of outputs of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.num_outputs 1
- property num_states¶
Returns the number of states of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.num_states 2
- observability_matrix()[source]¶
- Returns the observability matrix of the state space model:
[C, C * A^1, C * A^2, .. , C * A^(n-1)]; A in R^(n x n), C in R^(m x k)
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-1.5, -2], [1, 0]]) >>> B = Matrix([0.5, 0]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([1]) >>> ss = StateSpace(A, B, C, D) >>> ob = ss.observability_matrix() >>> ob Matrix([ [0, 1], [1, 0]])
References
- observable_subspace()[source]¶
Returns the observable subspace of the state space model.
Note: this method raises an error for matrices with symbolic entries because it is not possible determine the observable subspace in general.
- Raises:
NotImplementedError
If the state space model has symbolic entries, the observable subspace cannot be determined in general.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-1.5, -2], [1, 0]]) >>> B = Matrix([0.5, 0]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([1]) >>> ss = StateSpace(A, B, C, D) >>> ob_subspace = ss.observable_subspace() >>> ob_subspace [Matrix([ [1], [0]]), Matrix([ [0], [1]])]
- property output_matrix¶
Returns the output matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.output_matrix Matrix([[0, 1]])
- property shape¶
Returns the shape of the equivalent StateSpace system.
- property state_matrix¶
Returns the state matrix of the model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> ss = StateSpace(A, B, C, D) >>> ss.state_matrix Matrix([ [1, 2], [1, 0]])
- to_controllable_form()[source]¶
Returns an equivalent state space model decomposed in controllable and uncontrollable parts. The returned system is algebraically similar to the original but with the A and B matrices in block triangular form showing the controllable and uncontrollable subsystems.
\[\begin{split}\begin{bmatrix} A_{R} & A_{R\bar R}\\0 & A_{\bar R} \end{bmatrix}\end{split}\]\[\begin{split}\begin{bmatrix} B_{R} \\ 0 \end{bmatrix}\end{split}\]\[\begin{bmatrix} C_{R} & C_{\bar R} \end{bmatrix}\]Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 0, 1], [0, 0, 0],[0, 0, -2]]) >>> B = Matrix([1, 1, 0]) >>> C = Matrix([1, 1, 0]).T >>> ss = StateSpace(A, B, C) >>> ss = ss.to_controllable_form() >>> ss.A Matrix([ [0, 0, 0], [1, 1, 1], [0, 0, -2]]) >>> ss.B Matrix([ [1], [0], [0]]) >>> ss.C Matrix([[2, 1, 0]])
- to_observable_form()[source]¶
Returns an equivalent state space model decomposed in observable and unobservable parts. The returned system is algebraically similar to the original but with the A and C matrices in block triangular form showing the observable and unobservable subsystems.
\[\begin{split}\begin{bmatrix} A_{O} & 0\\ A_{O\bar O} & A_{\bar O} \end{bmatrix}\end{split}\]\[\begin{split}\begin{bmatrix} B_{O} \\ B_{\bar O} \end{bmatrix}\end{split}\]\[\begin{bmatrix} C_{O} & 0 \end{bmatrix}\]Examples
>>> from sympy import Matrix, Rational >>> from sympy.physics.control import StateSpace >>> A = Matrix([[1, 0, 1], [0, 0, 0],[0, 0, -2]]) >>> B = Matrix([1, 1, 0]) >>> C = Matrix([1, 1, Rational(1,3)]).T >>> ss = StateSpace(A, B, C) >>> ss = ss.to_observable_form() >>> ss.A Matrix([ [0, 0, 0], [0, 1, 0], [0, -3, -2]]) >>> ss.B Matrix([ [ 1], [ 3/10], [-3/10]]) >>> ss.C Matrix([[1, 10/3, 0]])
- uncontrollable_subspace()[source]¶
Returns the uncontrollable subspace of the state space model.
Note: this method raises an error for matrices with symbolic entries because it is not possible determine the uncontrollable subspace in general.
- Raises:
NotImplementedError
If the state space model has symbolic entries, the uncontrollable subspace cannot be determined in general.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-1.5, -2], [1, 0]]) >>> B = Matrix([0.5, 0]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([1]) >>> ss = StateSpace(A, B, C, D) >>> co_subspace = ss.controllable_subspace() >>> co_subspace [Matrix([ [0.5], [ 0]]), Matrix([ [-0.75], [ 0.5]])]
- unobservable_subspace()[source]¶
Returns the unobservable subspace of the state space model.
Note: this method raises an error for matrices with symbolic entries because it is not possible determine the unobservable subspace in general.
- Raises:
NotImplementedError
If the state space model has symbolic entries, the unobservable subspace cannot be determined in general.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-1.5, -2], [1, 0]]) >>> B = Matrix([0.5, 0]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([1]) >>> ss = StateSpace(A, B, C, D) >>> ob_subspace = ss.observable_subspace() >>> ob_subspace [Matrix([ [1], [0]]), Matrix([ [0], [1]])]
- class sympy.physics.control.lti.StateSpace(A=None, B=None, C=None, D=None)[source]¶
State space model of a linear, continuous-time, time invariant control system.
See py:class:\(~.StateSpaceBase\) for more details.
- Parameters:
A : Matrix, optional
The State matrix of the state space model.
B : Matrix, optional
The Input-to-State matrix of the state space model.
C : Matrix, optional
The State-to-Output matrix of the state space model.
D : Matrix, optional
The Feedthrough matrix of the state space model.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace
The easiest way to create a StateSpaceModel is via four matrices:
>>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> StateSpace(A, B, C, D) StateSpace(Matrix([ [1, 2], [1, 0]]), Matrix([ [1], [1]]), Matrix([[0, 1]]), Matrix([[0]]))
One can use less matrices. The rest will be filled with a minimum of zeros:
>>> StateSpace(A, B) StateSpace(Matrix([ [1, 2], [1, 0]]), Matrix([ [1], [1]]), Matrix([[0, 0]]), Matrix([[0]]))
- dsolve(
- initial_conditions=None,
- input_vector=None,
- var=t,
Returns \(y(t)\) or output of StateSpace given by the solution of equations:
\[\begin{split}\begin{aligned} \dot{x}(t) &= Ax(t) + Bu(t) \\ y(t) &= Cx(t) + Du(t) \end{aligned}\end{split}\]- Parameters:
initial_conditions : Matrix
The initial conditions of \(x\) state vector. If not provided, it defaults to a zero vector.
input_vector : Matrix
The input vector for state space. If not provided, it defaults to a zero vector.
var : Symbol
The symbol representing time. If not provided, it defaults to \(t\).
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import StateSpace >>> A = Matrix([[-2, 0], [1, -1]]) >>> B = Matrix([[1], [0]]) >>> C = Matrix([[2, 1]]) >>> ip = Matrix([5]) >>> i = Matrix([0, 0]) >>> ss = StateSpace(A, B, C) >>> ss.dsolve(input_vector=ip, initial_conditions=i).simplify() Matrix([[15/2 - 5*exp(-t) - 5*exp(-2*t)/2]])
If no input is provided it defaults to solving the system with zero initial conditions and zero input.
>>> ss.dsolve() Matrix([[0]])
References
- class sympy.physics.control.lti.DiscreteStateSpace(
- A=None,
- B=None,
- C=None,
- D=None,
- sampling_time=1,
State space model of a linear, discrete-time, time invariant control system.
See py:class:\(~.StateSpaceBase\) for more details.
- Parameters:
A : Matrix, optional
The State matrix of the state space model.
B : Matrix, optional
The Input-to-State matrix of the state space model.
C : Matrix, optional
The State-to-Output matrix of the state space model.
D : Matrix, optional
The Feedthrough matrix of the state space model.
sampling_time : Symbol, Number, optional
Time interval between two consecutive sampling instants Defaults to 1.
Examples
>>> from sympy import Matrix >>> from sympy.physics.control import DiscreteStateSpace
The easiest way to create a StateSpaceModel is via four matrices:
>>> A = Matrix([[1, 2], [1, 0]]) >>> B = Matrix([1, 1]) >>> C = Matrix([[0, 1]]) >>> D = Matrix([0]) >>> DiscreteStateSpace(A, B, C, D) DiscreteStateSpace(Matrix([ [1, 2], [1, 0]]), Matrix([ [1], [1]]), Matrix([[0, 1]]), Matrix([[0]]), 1)
One can use less matrices. The rest will be filled with a minimum of zeros:
>>> DiscreteStateSpace(A, B, sampling_time=0.2) DiscreteStateSpace(Matrix([ [1, 2], [1, 0]]), Matrix([ [1], [1]]), Matrix([[0, 0]]), Matrix([[0]]), 0.2)
- sympy.physics.control.lti.gbt(tf, sample_per, alpha)[source]¶
Returns falling coefficients of H(z) from numerator and denominator.
- Parameters:
tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sample_per : Symbol, Number
Time interval between two consecutive sampling instants.
alpha: Symbol, Number
The parameter for the generalised bilinear transformation method.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the generalised bilinear transformation method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{z-1}{T(\alpha z + (1-\alpha))}\) into H(s), where T is the sample period. Coefficients are falling, i.e. \(H(z) = \frac{az+b}{cz+d}\) is returned as [a, b], [c, d].
Examples
>>> from sympy.physics.control.lti import TransferFunction, gbt >>> from sympy.abc import s, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> numZ, denZ = gbt(tf, T, 0.5) >>> numZ [T/(2*(L + R*T/2)), T/(2*(L + R*T/2))] >>> denZ [1, (-L + R*T/2)/(L + R*T/2)]
>>> numZ, denZ = gbt(tf, T, 0) >>> numZ [T/L] >>> denZ [1, (-L + R*T)/L]
>>> numZ, denZ = gbt(tf, T, 1) >>> numZ [T/(L + R*T), 0] >>> denZ [1, -L/(L + R*T)]
>>> numZ, denZ = gbt(tf, T, 0.3) >>> numZ [3*T/(10*(L + 3*R*T/10)), 7*T/(10*(L + 3*R*T/10))] >>> denZ [1, (-L + 7*R*T/10)/(L + 3*R*T/10)]
References
- sympy.physics.control.lti.bilinear(tf, sample_per)[source]¶
Returns falling coefficients of H(z) from numerator and denominator.
- Parameters:
tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the bilinear transform method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{2}{T}\frac{z-1}{z+1}\) into H(s), where T is the sample period. Coefficients are falling, i.e. \(H(z) = \frac{az+b}{cz+d}\) is returned as [a, b], [c, d].
Examples
>>> from sympy.physics.control.lti import TransferFunction, bilinear >>> from sympy.abc import s, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> numZ, denZ = bilinear(tf, T) >>> numZ [T/(2*(L + R*T/2)), T/(2*(L + R*T/2))] >>> denZ [1, (-L + R*T/2)/(L + R*T/2)]
- sympy.physics.control.lti.forward_diff(tf, sample_per)[source]¶
Returns falling coefficients of H(z) from numerator and denominator.
- Parameters:
tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the forward difference transform method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{z-1}{T}\) into H(s), where T is the sample period. Coefficients are falling, i.e. \(H(z) = \frac{az+b}{cz+d}\) is returned as [a, b], [c, d].
Examples
>>> from sympy.physics.control.lti import TransferFunction, forward_diff >>> from sympy.abc import s, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> numZ, denZ = forward_diff(tf, T) >>> numZ [T/L] >>> denZ [1, (-L + R*T)/L]
- sympy.physics.control.lti.backward_diff(tf, sample_per)[source]¶
Returns falling coefficients of H(z) from numerator and denominator.
- Parameters:
tf : TransferFunction
The continuous transfer function H(s) to be discretized.
sampling_time : Symbol, Number
Time interval between two consecutive sampling instants.
Explanation
Where H(z) is the corresponding discretized transfer function, discretized with the backward difference transform method. H(z) is obtained from the continuous transfer function H(s) by substituting \(s(z) = \frac{z-1}{Tz}\) into H(s), where T is the sample period. Coefficients are falling, i.e. \(H(z) = \frac{az+b}{cz+d}\) is returned as [a, b], [c, d].
Examples
>>> from sympy.physics.control.lti import TransferFunction, backward_diff >>> from sympy.abc import s, L, R, T
>>> tf = TransferFunction(1, s*L + R, s) >>> numZ, denZ = backward_diff(tf, T) >>> numZ [T/(L + R*T), 0] >>> denZ [1, -L/(L + R*T)]