Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
sys = frdata.FRD(sysdata, smooth=True)
elif isinstance(sysdata, xferfcn.TransferFunction):
sys = sysdata
elif getattr(sysdata, '__iter__', False) and len(sysdata) == 3:
mag, phase, omega = sysdata
sys = frdata.FRD(mag * np.exp(1j * phase * math.pi/180),
omega, smooth=True)
else:
sys = xferfcn._convert_to_transfer_function(sysdata)
except Exception as e:
print (e)
raise ValueError("Margin sysdata must be either a linear system or "
"a 3-sequence of mag, phase, omega.")
# calculate gain of system
if isinstance(sys, xferfcn.TransferFunction):
# check for siso
if not issiso(sys):
raise ValueError("Can only do margins for SISO system")
# real and imaginary part polynomials in omega:
rnum, inum = _polyimsplit(sys.num[0][0])
rden, iden = _polyimsplit(sys.den[0][0])
# test (imaginary part of tf) == 0, for phase crossover/gain margins
test_w_180 = np.polyadd(np.polymul(inum, rden), np.polymul(rnum, -iden))
w_180 = np.roots(test_w_180)
# first remove imaginary and negative frequencies, epsw removes the
# "0" frequency for type-2 systems
w_180 = np.real(w_180[(np.imag(w_180) == 0) * (w_180 >= epsw)])
# Each transfer function matrix row
# has a common denominator.
den[i][j] = list(tfout[5][i, :])
except ImportError:
# If slycot is not available, use signal.lti (SISO only)
if sys.inputs != 1 or sys.outputs != 1:
raise TypeError("No support for MIMO without slycot.")
# Do the conversion using sp.signal.ss2tf
# Note that this returns a 2D array for the numerator
num, den = sp.signal.ss2tf(sys.A, sys.B, sys.C, sys.D)
num = squeeze(num) # Convert to 1D array
den = squeeze(den) # Probably not needed
return TransferFunction(num, den, sys.dt)
elif isinstance(sys, (int, float, complex, np.number)):
if "inputs" in kw:
inputs = kw["inputs"]
else:
inputs = 1
if "outputs" in kw:
outputs = kw["outputs"]
else:
outputs = 1
num = [[[sys] for j in range(inputs)] for i in range(outputs)]
den = [[[1] for j in range(inputs)] for i in range(outputs)]
return TransferFunction(num, den)
(timebaseEqual(self, other)):
dt = self.dt # use dt from first argument
else:
raise ValueError("Systems have different sampling times")
# Preallocate the numerator and denominator of the sum.
num = [[[] for j in range(self.inputs)] for i in range(self.outputs)]
den = [[[] for j in range(self.inputs)] for i in range(self.outputs)]
for i in range(self.outputs):
for j in range(self.inputs):
num[i][j], den[i][j] = _add_siso(
self.num[i][j], self.den[i][j],
other.num[i][j], other.den[i][j])
return TransferFunction(num, den, dt)
pm: float or array_loke
Phase margin
sm: float or array_like
Stability margin, the minimum distance from the Nyquist plot to -1
wg: float or array_like
Frequency for gain margin (at phase crossover, phase = -180 degrees)
wp: float or array_like
Frequency for phase margin (at gain crossover, gain = 1)
ws: float or array_like
Frequency for stability margin (complex gain closest to -1)
"""
try:
if isinstance(sysdata, frdata.FRD):
sys = frdata.FRD(sysdata, smooth=True)
elif isinstance(sysdata, xferfcn.TransferFunction):
sys = sysdata
elif getattr(sysdata, '__iter__', False) and len(sysdata) == 3:
mag, phase, omega = sysdata
sys = frdata.FRD(mag * np.exp(1j * phase * math.pi/180),
omega, smooth=True)
else:
sys = xferfcn._convert_to_transfer_function(sysdata)
except Exception as e:
print (e)
raise ValueError("Margin sysdata must be either a linear system or "
"a 3-sequence of mag, phase, omega.")
# calculate gain of system
if isinstance(sys, xferfcn.TransferFunction):
# check for siso
>>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]]
>>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]]
>>> sys1 = tf2ss(num, den)
>>> sys_tf = tf(num, den)
>>> sys2 = tf2ss(sys_tf)
"""
if len(args) == 2 or len(args) == 3:
# Assume we were given the num, den
return _convertToStateSpace(TransferFunction(*args))
elif len(args) == 1:
sys = args[0]
if not isinstance(sys, TransferFunction):
raise TypeError("tf2ss(sys): sys must be a TransferFunction \
object.")
return _convertToStateSpace(sys)
else:
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))
>>> sys1 = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> # Convert a TransferFunction to a StateSpace object.
>>> sys_tf = tf([2.], [1., 3])
>>> sys2 = ss(sys_tf)
"""
if len(args) == 4 or len(args) == 5:
return StateSpace(*args)
elif len(args) == 1:
from .xferfcn import TransferFunction
sys = args[0]
if isinstance(sys, StateSpace):
return deepcopy(sys)
elif isinstance(sys, TransferFunction):
return tf2ss(sys)
else:
raise TypeError("ss(sys): sys must be a StateSpace or \
TransferFunction object. It is %s." % type(sys))
else:
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))
outputs = kw["outputs"]
else:
outputs = 1
num = [[[sys] for j in range(inputs)] for i in range(outputs)]
den = [[[1] for j in range(inputs)] for i in range(outputs)]
return TransferFunction(num, den)
# If this is array-like, try to create a constant feedthrough
try:
D = array(sys)
outputs, inputs = D.shape
num = [[[D[i, j]] for j in range(inputs)] for i in range(outputs)]
den = [[[1] for j in range(inputs)] for i in range(outputs)]
return TransferFunction(num, den)
except Exception as e:
print("Failure to assume argument is matrix-like in"
" _convertToTransferFunction, result %s" % e)
raise TypeError("Can't convert given type to TransferFunction system.")
Examples
--------
>>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]]
>>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]]
>>> sys1 = tf2ss(num, den)
>>> sys_tf = tf(num, den)
>>> sys2 = tf2ss(sys_tf)
"""
from .xferfcn import TransferFunction
if len(args) == 2 or len(args) == 3:
# Assume we were given the num, den
return _convertToStateSpace(TransferFunction(*args))
elif len(args) == 1:
sys = args[0]
if not isinstance(sys, TransferFunction):
raise TypeError("tf2ss(sys): sys must be a TransferFunction \
object.")
return _convertToStateSpace(sys)
else:
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))
def __pow__(self, other):
if not type(other) == int:
raise ValueError("Exponent must be an integer")
if other == 0:
return TransferFunction([1], [1]) # unity
if other > 0:
return self * (self**(other - 1))
if other < 0:
return (TransferFunction([1], [1]) / self) * (self**(other + 1))
start2 = 0
if stop2 is None:
stop2 = len(self.num[0])
num = []
den = []
for i in range(start1, stop1, step1):
num_i = []
den_i = []
for j in range(start2, stop2, step2):
num_i.append(self.num[i][j])
den_i.append(self.den[i][j])
num.append(num_i)
den.append(den_i)
if self.isctime():
return TransferFunction(num, den)
else:
return TransferFunction(num, den, self.dt)