From bc1bbbfb55c6a535c67fc8ef44933d6e0d977eed Mon Sep 17 00:00:00 2001 From: zerberros Date: Tue, 27 Jan 2015 00:52:37 +0100 Subject: [PATCH 1/8] add class for discrete lineal time-invariant systems like continuous systems this is the first of a series of commits for the enhancement of the discrete lti systems. --- scipy/signal/dltisys.py | 176 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) diff --git a/scipy/signal/dltisys.py b/scipy/signal/dltisys.py index 59d1530acc77..b92c40c721e2 100644 --- a/scipy/signal/dltisys.py +++ b/scipy/signal/dltisys.py @@ -10,7 +10,181 @@ from scipy.interpolate import interp1d from .ltisys import tf2ss, zpk2ss -__all__ = ['dlsim', 'dstep', 'dimpulse'] +__all__ = ['dlsim', 'dstep', 'dimpulse','dlti'] + +class dlti(object) + """Linear Time Invariant class which simplifies representation. + + Parameters + ---------- + args : arguments + The `lti` class can be instantiated with either 2, 3 or 4 arguments. + The following gives the number of elements in the tuple and the + interpretation: + + * 2: (numerator, denominator) + * 3: (zeros, poles, gain) + * 4: (A, B, C, D) + + Each argument can be an array or sequence. + + Notes + ----- + `lti` instances have all types of representations available; for example + after creating an instance s with ``(zeros, poles, gain)`` the transfer + function representation (numerator, denominator) can be accessed as + ``s.num`` and ``s.den``. + + """ + + def __init__(self, *args, **kwords): + """ + Initialize the LTI system using either: + + -> (numerator, denominator, dt) + -> (zeros, poles, gain, dt) + X - (A, B, C, D, dt) : state-space. + + """ + + N = len(args) + if N == 2: # Numerator denominator transfer function input + self._num, self._den = normalize(*args) + self._update(N) + self.inputs = 1 + if len(self.num.shape) > 1: + self.outputs = self.num.shape[0] + else: + self.outputs = 1 + elif N == 3: # Zero-pole-gain form + self._zeros, self._poles, self._gain = args + self._update(N) + # make sure we have numpy arrays + self.zeros = numpy.asarray(self.zeros) + self.poles = numpy.asarray(self.poles) + self.inputs = 1 + if len(self.zeros.shape) > 1: + self.outputs = self.zeros.shape[0] + else: + self.outputs = 1 + elif N == 4: # State-space form + self._A, self._B, self._C, self._D = abcd_normalize(*args) + self._update(N) + self.inputs = self.B.shape[-1] + self.outputs = self.C.shape[0] + else: + raise ValueError("Needs 2, 3, or 4 arguments.") + + + def __repr__(self): + """ + Canonical representation using state-space to preserve numerical + precision and any MIMO information + """ + return '{0}(\n{1},\n{2},\n{3},\n{4}\n)'.format( + self.__class__.__name__, + repr(self.A), + repr(self.B), + repr(self.C), + repr(self.D), + ) + + @property + def num(self): + return self._num + + @num.setter + def num(self, value): + self._num = value + self._update(2) + + @property + def den(self): + return self._den + + @den.setter + def den(self, value): + self._den = value + self._update(2) + + @property + def zeros(self): + return self._zeros + + @zeros.setter + def zeros(self, value): + self._zeros = value + self._update(3) + + @property + def poles(self): + return self._poles + + @poles.setter + def poles(self, value): + self._poles = value + self._update(3) + + @property + def gain(self): + return self._gain + + @gain.setter + def gain(self, value): + self._gain = value + self._update(3) + + @property + def A(self): + return self._A + + @A.setter + def A(self, value): + self._A = value + self._update(4) + + @property + def B(self): + return self._B + + @B.setter + def B(self, value): + self._B = value + self._update(4) + + @property + def C(self): + return self._C + + @C.setter + def C(self, value): + self._C = value + self._update(4) + + @property + def D(self): + return self._D + + @D.setter + def D(self, value): + self._D = value + self._update(4) + + def _update(self, N): + if N == 2: + self._zeros, self._poles, self._gain = tf2zpk(self.num, self.den) + self._A, self._B, self._C, self._D = tf2ss(self.num, self.den) + if N == 3: + self._num, self._den = zpk2tf(self.zeros, self.poles, self.gain) + self._A, self._B, self._C, self._D = zpk2ss(self.zeros, + self.poles, self.gain) + if N == 4: + self._num, self._den = ss2tf(self.A, self.B, self.C, self.D) + self._zeros, self._poles, self._gain = ss2zpk(self.A, self.B, + self.C, self.D) + + + def dlsim(system, u, t=None, x0=None): From e03bd44b153b43a3db146d454a5ca4b20ab245ca Mon Sep 17 00:00:00 2001 From: zerberros Date: Tue, 27 Jan 2015 23:49:47 +0100 Subject: [PATCH 2/8] import from ltisys to dltisys pzk2ss and ss2pzk --- scipy/signal/dltisys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scipy/signal/dltisys.py b/scipy/signal/dltisys.py index b92c40c721e2..4f934777b922 100644 --- a/scipy/signal/dltisys.py +++ b/scipy/signal/dltisys.py @@ -8,7 +8,7 @@ import numpy as np from scipy.interpolate import interp1d -from .ltisys import tf2ss, zpk2ss +from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk __all__ = ['dlsim', 'dstep', 'dimpulse','dlti'] From c14b14c4163461f3b68a2fd2466d73db553a81bc Mon Sep 17 00:00:00 2001 From: zerberros Date: Mon, 9 Feb 2015 17:52:01 +0100 Subject: [PATCH 3/8] fix some docstrings --- scipy/signal/dltisys.py | 54 +++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/scipy/signal/dltisys.py b/scipy/signal/dltisys.py index 4f934777b922..09e98037282c 100644 --- a/scipy/signal/dltisys.py +++ b/scipy/signal/dltisys.py @@ -6,19 +6,21 @@ # April 4, 2011 from __future__ import division, print_function, absolute_import +from .filter_design import tf2zpk, zpk2tf, normalize, freqs import numpy as np from scipy.interpolate import interp1d from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk -__all__ = ['dlsim', 'dstep', 'dimpulse','dlti'] +__all__ = ['dlsim', 'dstep', 'dimpulse', 'dlti'] -class dlti(object) - """Linear Time Invariant class which simplifies representation. + +class dlti(object): + """Discrete Linear Time Invariant class which simplifies representation. Parameters ---------- args : arguments - The `lti` class can be instantiated with either 2, 3 or 4 arguments. + The `dlti` class can be instantiated with either 2, 3 or 4 arguments. The following gives the number of elements in the tuple and the interpretation: @@ -30,20 +32,20 @@ class dlti(object) Notes ----- - `lti` instances have all types of representations available; for example - after creating an instance s with ``(zeros, poles, gain)`` the transfer + `dlti` instances have all types of representations available; for example + after creating an instance z with ``(zeros, poles, gain)`` the transfer function representation (numerator, denominator) can be accessed as - ``s.num`` and ``s.den``. + ``z.num`` and ``z.den``. """ - + def __init__(self, *args, **kwords): """ - Initialize the LTI system using either: + Initialize the DLTI system using either: - -> (numerator, denominator, dt) - -> (zeros, poles, gain, dt) - X - (A, B, C, D, dt) : state-space. + - (numerator, denominator) + - (zeros, poles, gain) + - (A, B, C, D) : state-space. """ @@ -75,7 +77,6 @@ def __init__(self, *args, **kwords): else: raise ValueError("Needs 2, 3, or 4 arguments.") - def __repr__(self): """ Canonical representation using state-space to preserve numerical @@ -184,8 +185,19 @@ def _update(self, N): self.C, self.D) + def dimpulse(self, x0=None, t=None, n=None): + """ + Return the impulse response of a discrete-time system. + + """ + return impulse(self, x0=x0, t=t, n=n) + def dstep(self, x0=None, t=None, n=None): + """ + Return the step response of a continuous-time system. + """ + return dstep(self, x0=x0, t=t, n=n) def dlsim(system, u, t=None, x0=None): """ @@ -268,9 +280,9 @@ def dlsim(system, u, t=None, x0=None): # Check initial condition if x0 is None: - xout[0,:] = np.zeros((a.shape[1],)) + xout[0, :] = np.zeros((a.shape[1],)) else: - xout[0,:] = np.asarray(x0) + xout[0, :] = np.asarray(x0) # Pre-interpolate inputs into the desired time steps if t is None: @@ -284,12 +296,12 @@ def dlsim(system, u, t=None, x0=None): # Simulate the system for i in range(0, out_samples - 1): - xout[i+1,:] = np.dot(a, xout[i,:]) + np.dot(b, u_dt[i,:]) - yout[i,:] = np.dot(c, xout[i,:]) + np.dot(d, u_dt[i,:]) + xout[i + 1, :] = np.dot(a, xout[i, :]) + np.dot(b, u_dt[i, :]) + yout[i, :] = np.dot(c, xout[i, :]) + np.dot(d, u_dt[i, :]) # Last point - yout[out_samples-1,:] = np.dot(c, xout[out_samples-1,:]) + \ - np.dot(d, u_dt[out_samples-1,:]) + yout[out_samples - 1, :] = np.dot(c, xout[out_samples - 1, :]) + \ + np.dot(d, u_dt[out_samples - 1, :]) if len(system) == 5: return tout, yout, xout @@ -358,7 +370,7 @@ def dimpulse(system, x0=None, t=None, n=None): yout = None for i in range(0, n_inputs): u = np.zeros((t.shape[0], n_inputs)) - u[0,i] = 1.0 + u[0, i] = 1.0 one_output = dlsim(system, u, t=t, x0=x0) @@ -433,7 +445,7 @@ def dstep(system, x0=None, t=None, n=None): yout = None for i in range(0, n_inputs): u = np.zeros((t.shape[0], n_inputs)) - u[:,i] = np.ones((t.shape[0],)) + u[:, i] = np.ones((t.shape[0],)) one_output = dlsim(system, u, t=t, x0=x0) From 65b4327c0b6ff2007f6c77f2a1ef97edb4ef42e2 Mon Sep 17 00:00:00 2001 From: zerberros Date: Tue, 10 Feb 2015 21:17:18 +0100 Subject: [PATCH 4/8] modify dlti's methods to get dt parameter --- scipy/signal/dltisys.py | 81 +++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/scipy/signal/dltisys.py b/scipy/signal/dltisys.py index 09e98037282c..d7013038d438 100644 --- a/scipy/signal/dltisys.py +++ b/scipy/signal/dltisys.py @@ -43,51 +43,54 @@ def __init__(self, *args, **kwords): """ Initialize the DLTI system using either: - - (numerator, denominator) - - (zeros, poles, gain) - - (A, B, C, D) : state-space. + - (numerator, denominator, dt) + - (zeros, poles, gain, dt) + - (A, B, C, D, dt) : state-space. """ N = len(args) - if N == 2: # Numerator denominator transfer function input - self._num, self._den = normalize(*args) + if N == 3: # Numerator denominator dt transfer function input + self._num, self._den, = normalize(args[0],args[1]) + self._dt = args[2] self._update(N) self.inputs = 1 if len(self.num.shape) > 1: self.outputs = self.num.shape[0] else: self.outputs = 1 - elif N == 3: # Zero-pole-gain form - self._zeros, self._poles, self._gain = args + elif N == 4: # Zero-pole-gain dt form + self._zeros, self._poles, self._gain, self._dt = args self._update(N) # make sure we have numpy arrays - self.zeros = numpy.asarray(self.zeros) - self.poles = numpy.asarray(self.poles) + self.zeros = np.asarray(self.zeros) + self.poles = np.asarray(self.poles) self.inputs = 1 if len(self.zeros.shape) > 1: self.outputs = self.zeros.shape[0] else: self.outputs = 1 - elif N == 4: # State-space form - self._A, self._B, self._C, self._D = abcd_normalize(*args) + elif N == 5: # State-space dt form + self._A, self._B, self._C, self._D, = abcd_normalize(args[0:3]) + self._dt = args[4] self._update(N) self.inputs = self.B.shape[-1] self.outputs = self.C.shape[0] else: - raise ValueError("Needs 2, 3, or 4 arguments.") + raise ValueError("Needs 3, 4, or 5 arguments.") def __repr__(self): """ Canonical representation using state-space to preserve numerical precision and any MIMO information """ - return '{0}(\n{1},\n{2},\n{3},\n{4}\n)'.format( + return '{0}(\n{1},\n{2},\n{3},\n{4}\n,{5})'.format( self.__class__.__name__, repr(self.A), repr(self.B), repr(self.C), repr(self.D), + repr(self.dt), ) @property @@ -97,7 +100,7 @@ def num(self): @num.setter def num(self, value): self._num = value - self._update(2) + self._update(3) @property def den(self): @@ -106,7 +109,7 @@ def den(self): @den.setter def den(self, value): self._den = value - self._update(2) + self._update(3) @property def zeros(self): @@ -115,7 +118,7 @@ def zeros(self): @zeros.setter def zeros(self, value): self._zeros = value - self._update(3) + self._update(4) @property def poles(self): @@ -124,7 +127,7 @@ def poles(self): @poles.setter def poles(self, value): self._poles = value - self._update(3) + self._update(4) @property def gain(self): @@ -133,7 +136,7 @@ def gain(self): @gain.setter def gain(self, value): self._gain = value - self._update(3) + self._update(4) @property def A(self): @@ -142,7 +145,7 @@ def A(self): @A.setter def A(self, value): self._A = value - self._update(4) + self._update(5) @property def B(self): @@ -151,7 +154,7 @@ def B(self): @B.setter def B(self, value): self._B = value - self._update(4) + self._update(5) @property def C(self): @@ -160,7 +163,7 @@ def C(self): @C.setter def C(self, value): self._C = value - self._update(4) + self._update(5) @property def D(self): @@ -169,17 +172,25 @@ def D(self): @D.setter def D(self, value): self._D = value - self._update(4) + self._update(5) + + @property + def dt(self): + return self._dt + + @dt.setter + def dt(self,value): + self._dt = value def _update(self, N): - if N == 2: + if N == 3: self._zeros, self._poles, self._gain = tf2zpk(self.num, self.den) self._A, self._B, self._C, self._D = tf2ss(self.num, self.den) - if N == 3: + if N == 4: self._num, self._den = zpk2tf(self.zeros, self.poles, self.gain) self._A, self._B, self._C, self._D = zpk2ss(self.zeros, self.poles, self.gain) - if N == 4: + if N == 5: self._num, self._den = ss2tf(self.A, self.B, self.C, self.D) self._zeros, self._poles, self._gain = ss2zpk(self.A, self.B, self.C, self.D) @@ -190,7 +201,7 @@ def dimpulse(self, x0=None, t=None, n=None): Return the impulse response of a discrete-time system. """ - return impulse(self, x0=x0, t=t, n=n) + return dimpulse(self, x0=x0, t=t, n=n) def dstep(self, x0=None, t=None, n=None): """ @@ -280,9 +291,9 @@ def dlsim(system, u, t=None, x0=None): # Check initial condition if x0 is None: - xout[0, :] = np.zeros((a.shape[1],)) + xout[0,:] = np.zeros((a.shape[1],)) else: - xout[0, :] = np.asarray(x0) + xout[0,:] = np.asarray(x0) # Pre-interpolate inputs into the desired time steps if t is None: @@ -295,13 +306,13 @@ def dlsim(system, u, t=None, x0=None): u_dt = u_dt_interp(tout).transpose() # Simulate the system - for i in range(0, out_samples - 1): - xout[i + 1, :] = np.dot(a, xout[i, :]) + np.dot(b, u_dt[i, :]) - yout[i, :] = np.dot(c, xout[i, :]) + np.dot(d, u_dt[i, :]) + for i in range(0, out_samples-1): + xout[i + 1,:] = np.dot(a, xout[i,:]) + np.dot(b, u_dt[i,:]) + yout[i, :] = np.dot(c, xout[i,:]) + np.dot(d, u_dt[i,:]) # Last point - yout[out_samples - 1, :] = np.dot(c, xout[out_samples - 1, :]) + \ - np.dot(d, u_dt[out_samples - 1, :]) + yout[out_samples - 1,:] = np.dot(c, xout[out_samples-1,:]) + \ + np.dot(d, u_dt[out_samples-1,:]) if len(system) == 5: return tout, yout, xout @@ -370,7 +381,7 @@ def dimpulse(system, x0=None, t=None, n=None): yout = None for i in range(0, n_inputs): u = np.zeros((t.shape[0], n_inputs)) - u[0, i] = 1.0 + u[0,i] = 1.0 one_output = dlsim(system, u, t=t, x0=x0) @@ -445,7 +456,7 @@ def dstep(system, x0=None, t=None, n=None): yout = None for i in range(0, n_inputs): u = np.zeros((t.shape[0], n_inputs)) - u[:, i] = np.ones((t.shape[0],)) + u[:,i] = np.ones((t.shape[0],)) one_output = dlsim(system, u, t=t, x0=x0) From 975a92462d42bd2696b01521d4ddf0a920e61b14 Mon Sep 17 00:00:00 2001 From: zerberros Date: Mon, 16 Feb 2015 10:35:50 +0100 Subject: [PATCH 5/8] bug fixes, buff... :P --- scipy/signal/cont2discrete.py | 3 ++- scipy/signal/dltisys.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scipy/signal/cont2discrete.py b/scipy/signal/cont2discrete.py index d17f8f2749db..20c9cf7cff2f 100644 --- a/scipy/signal/cont2discrete.py +++ b/scipy/signal/cont2discrete.py @@ -10,6 +10,7 @@ from scipy import linalg from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk +from .dltisys import dlti __all__ = ['cont2discrete'] @@ -139,4 +140,4 @@ def cont2discrete(sys, dt, method="zoh", alpha=None): else: raise ValueError("Unknown transformation method '%s'" % method) - return ad, bd, cd, dd, dt + return ad, bd, cd, dd, dt \ No newline at end of file diff --git a/scipy/signal/dltisys.py b/scipy/signal/dltisys.py index d7013038d438..2d7c0bee4810 100644 --- a/scipy/signal/dltisys.py +++ b/scipy/signal/dltisys.py @@ -9,7 +9,7 @@ from .filter_design import tf2zpk, zpk2tf, normalize, freqs import numpy as np from scipy.interpolate import interp1d -from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk +from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk, abcd_normalize __all__ = ['dlsim', 'dstep', 'dimpulse', 'dlti'] @@ -71,7 +71,7 @@ def __init__(self, *args, **kwords): else: self.outputs = 1 elif N == 5: # State-space dt form - self._A, self._B, self._C, self._D, = abcd_normalize(args[0:3]) + self._A, self._B, self._C, self._D, = abcd_normalize(args[0],args[1],args[2],args[3]) self._dt = args[4] self._update(N) self.inputs = self.B.shape[-1] From 3318eb44351d9644481e23288fc384453aea91b4 Mon Sep 17 00:00:00 2001 From: zerberros Date: Thu, 19 Feb 2015 09:59:09 +0100 Subject: [PATCH 6/8] simplifiction the cont2discrete function Now the cont2discrete function return a dlti class --- scipy/signal/cont2discrete.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/scipy/signal/cont2discrete.py b/scipy/signal/cont2discrete.py index 20c9cf7cff2f..1f95884d9b89 100644 --- a/scipy/signal/cont2discrete.py +++ b/scipy/signal/cont2discrete.py @@ -9,7 +9,7 @@ import numpy as np from scipy import linalg -from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk +from .ltisys import tf2ss, ss2tf, zpk2ss, ss2zpk, lti from .dltisys import dlti __all__ = ['cont2discrete'] @@ -49,6 +49,7 @@ def cont2discrete(sys, dt, method="zoh", alpha=None): sysd : tuple containing the discrete system Based on the input type, the output will be of the form + * (lti instance,dt) for lti class object input * (num, den, dt) for transfer function input * (zeros, poles, gain, dt) for zeros-poles-gain input * (A, B, C, D, dt) for state-space system input @@ -75,20 +76,13 @@ def cont2discrete(sys, dt, method="zoh", alpha=None): (http://www.ece.ualberta.ca/~gfzhang/research/ZCC07_preprint.pdf) """ - if len(sys) == 2: - sysd = cont2discrete(tf2ss(sys[0], sys[1]), dt, method=method, - alpha=alpha) - return ss2tf(sysd[0], sysd[1], sysd[2], sysd[3]) + (dt,) - elif len(sys) == 3: - sysd = cont2discrete(zpk2ss(sys[0], sys[1], sys[2]), dt, method=method, - alpha=alpha) - return ss2zpk(sysd[0], sysd[1], sysd[2], sysd[3]) + (dt,) - elif len(sys) == 4: - a, b, c, d = sys - else: - raise ValueError("First argument must either be a tuple of 2 (tf), " - "3 (zpk), or 4 (ss) arrays.") + + if isinstance(sys, lti): + sys = sys + else: + sys = lti(*sys) + a,b,c,d = sys.A,sys.B,sys.C,sys.D if method == 'gbt': if alpha is None: raise ValueError("Alpha parameter must be specified for the " @@ -140,4 +134,4 @@ def cont2discrete(sys, dt, method="zoh", alpha=None): else: raise ValueError("Unknown transformation method '%s'" % method) - return ad, bd, cd, dd, dt \ No newline at end of file + return dlti(ad, bd, cd, dd, dt) \ No newline at end of file From 660553a9b9d8e58c15be078a20d3c605e8c0e878 Mon Sep 17 00:00:00 2001 From: zerberros Date: Sun, 22 Feb 2015 21:06:12 +0100 Subject: [PATCH 7/8] adapted test_cont2discrete for the new dlti class --- scipy/signal/dltisys.py | 25 +++++- scipy/signal/tests/test_cont2discrete.py | 103 ++++++++++++----------- 2 files changed, 75 insertions(+), 53 deletions(-) diff --git a/scipy/signal/dltisys.py b/scipy/signal/dltisys.py index 2d7c0bee4810..8af12aa897c6 100644 --- a/scipy/signal/dltisys.py +++ b/scipy/signal/dltisys.py @@ -70,7 +70,7 @@ def __init__(self, *args, **kwords): self.outputs = self.zeros.shape[0] else: self.outputs = 1 - elif N == 5: # State-space dt form + elif N == 5: # State-space with dt form self._A, self._B, self._C, self._D, = abcd_normalize(args[0],args[1],args[2],args[3]) self._dt = args[4] self._update(N) @@ -263,6 +263,8 @@ def dlsim(system, u, t=None, x0=None): >>> y array([ 0., 0., 0., 1.]) + """ + ### OBRAS ##### """ if len(system) == 3: a, b, c, d = tf2ss(system[0], system[1]) @@ -276,6 +278,13 @@ def dlsim(system, u, t=None, x0=None): raise ValueError("System argument should be a discrete transfer " + "function, zeros-poles-gain specification, or " + "state-space system") + """ + if isinstance(system, dlti): + sys = system + else: + sys = dlti(*system) + + a, b, c, d, dt = sys.A, sys.B, sys.C, sys.D, sys.dt if t is None: out_samples = max(u.shape) @@ -352,6 +361,8 @@ def dimpulse(system, x0=None, t=None, n=None): -------- impulse, dstep, dlsim, cont2discrete + """ + # Obras ### """ # Determine the system type and set number of inputs and time steps if len(system) == 3: @@ -368,6 +379,16 @@ def dimpulse(system, x0=None, t=None, n=None): "function, zeros-poles-gain specification, or " + "state-space system") + """ + + if isinstance(system, dlti): + system = system + else: + system = dlti(*system) + + n_inputs = system.A.shape[1] + + # Default to 100 samples if unspecified if n is None: n = 100 @@ -375,7 +396,7 @@ def dimpulse(system, x0=None, t=None, n=None): # If time is not specified, use the number of samples # and system dt if t is None: - t = np.linspace(0, n * dt, n, endpoint=False) + t = np.linspace(0, n * system.dt, n, endpoint=False) # For each input, implement a step change yout = None diff --git a/scipy/signal/tests/test_cont2discrete.py b/scipy/signal/tests/test_cont2discrete.py index d34b241f8c09..36fa1277084e 100644 --- a/scipy/signal/tests/test_cont2discrete.py +++ b/scipy/signal/tests/test_cont2discrete.py @@ -24,13 +24,14 @@ def test_zoh(self): # c and d in discrete should be equal to their continuous counterparts dt_requested = 0.5 - ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, method='zoh') + # ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, method='zoh') + sys = c2d((ac, bc, cc, dc), dt_requested, method='zoh') - assert_array_almost_equal(ad_truth, ad) - assert_array_almost_equal(bd_truth, bd) - assert_array_almost_equal(cc, cd) - assert_array_almost_equal(dc, dd) - assert_almost_equal(dt_requested, dt) + assert_array_almost_equal(ad_truth, sys.A) + assert_array_almost_equal(bd_truth, sys.B) + assert_array_almost_equal(cc, sys.C) + assert_array_almost_equal(dc, sys.D) + assert_almost_equal(dt_requested, sys.dt) def test_gbt(self): ac = np.eye(2) @@ -50,13 +51,15 @@ def test_gbt(self): [0.2], [-0.205]]) - ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, - method='gbt', alpha=alpha) + #ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, + # method='gbt', alpha=alpha) + sys = c2d((ac, bc, cc, dc), dt_requested, method='gbt', alpha=alpha) - assert_array_almost_equal(ad_truth, ad) - assert_array_almost_equal(bd_truth, bd) - assert_array_almost_equal(cd_truth, cd) - assert_array_almost_equal(dd_truth, dd) + + assert_array_almost_equal(ad_truth, sys.A) + assert_array_almost_equal(bd_truth, sys.B) + assert_array_almost_equal(cd_truth, sys.C) + assert_array_almost_equal(dd_truth, sys.D) def test_euler(self): ac = np.eye(2) @@ -73,14 +76,13 @@ def test_euler(self): [1.0, 0.25]]) dd_truth = dc - ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, - method='euler') + sys = c2d((ac, bc, cc, dc), dt_requested, method='euler') - assert_array_almost_equal(ad_truth, ad) - assert_array_almost_equal(bd_truth, bd) - assert_array_almost_equal(cd_truth, cd) - assert_array_almost_equal(dd_truth, dd) - assert_almost_equal(dt_requested, dt) + assert_array_almost_equal(ad_truth, sys.A) + assert_array_almost_equal(bd_truth, sys.B) + assert_array_almost_equal(cd_truth, sys.C) + assert_array_almost_equal(dd_truth, sys.D) + assert_almost_equal(dt_requested, sys.dt) def test_backward_diff(self): ac = np.eye(2) @@ -99,13 +101,12 @@ def test_backward_diff(self): [1.0], [0.295]]) - ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, - method='backward_diff') + sys = c2d((ac, bc, cc, dc), dt_requested, method='backward_diff') - assert_array_almost_equal(ad_truth, ad) - assert_array_almost_equal(bd_truth, bd) - assert_array_almost_equal(cd_truth, cd) - assert_array_almost_equal(dd_truth, dd) + assert_array_almost_equal(ad_truth, sys.A) + assert_array_almost_equal(bd_truth, sys.B) + assert_array_almost_equal(cd_truth, sys.C) + assert_array_almost_equal(dd_truth, sys.D) def test_bilinear(self): ac = np.eye(2) @@ -124,14 +125,13 @@ def test_bilinear(self): [1.0 / 3.0], [-0.121666666666667]]) - ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, - method='bilinear') + sys = c2d((ac, bc, cc, dc), dt_requested, method='bilinear') - assert_array_almost_equal(ad_truth, ad) - assert_array_almost_equal(bd_truth, bd) - assert_array_almost_equal(cd_truth, cd) - assert_array_almost_equal(dd_truth, dd) - assert_almost_equal(dt_requested, dt) + assert_array_almost_equal(ad_truth, sys.A) + assert_array_almost_equal(bd_truth, sys.B) + assert_array_almost_equal(cd_truth, sys.C) + assert_array_almost_equal(dd_truth, sys.D) + assert_almost_equal(dt_requested, sys.dt) # Same continuous system again, but change sampling rate @@ -142,14 +142,14 @@ def test_bilinear(self): dt_requested = 1.0 / 3.0 - ad, bd, cd, dd, dt = c2d((ac, bc, cc, dc), dt_requested, + sys = c2d((ac, bc, cc, dc), dt_requested, method='bilinear') - assert_array_almost_equal(ad_truth, ad) - assert_array_almost_equal(bd_truth, bd) - assert_array_almost_equal(cd_truth, cd) - assert_array_almost_equal(dd_truth, dd) - assert_almost_equal(dt_requested, dt) + assert_array_almost_equal(ad_truth, sys.A) + assert_array_almost_equal(bd_truth, sys.B) + assert_array_almost_equal(cd_truth, sys.C) + assert_array_almost_equal(dd_truth, sys.D) + assert_almost_equal(dt_requested, sys.dt) def test_transferfunction(self): numc = np.array([0.25, 0.25, 0.5]) @@ -160,11 +160,11 @@ def test_transferfunction(self): dt_requested = 0.5 - num, den, dt = c2d((numc, denc), dt_requested, method='zoh') + sys = c2d((numc, denc), dt_requested, method='zoh') - assert_array_almost_equal(numd, num) - assert_array_almost_equal(dend, den) - assert_almost_equal(dt_requested, dt) + assert_array_almost_equal(numd, sys.num) + assert_array_almost_equal(dend, sys.den) + assert_almost_equal(dt_requested, sys.dt) def test_zerospolesgain(self): zeros_c = np.array([0.5, -0.5]) @@ -178,13 +178,13 @@ def test_zerospolesgain(self): dt_requested = 0.5 - zeros, poles, k, dt = c2d((zeros_c, poles_c, k_c), dt_requested, + sys = c2d((zeros_c, poles_c, k_c), dt_requested, method='zoh') - assert_array_almost_equal(zeros_d, zeros) - assert_array_almost_equal(polls_d, poles) - assert_almost_equal(k_d, k) - assert_almost_equal(dt_requested, dt) + assert_array_almost_equal(zeros_d, sys.zeros) + assert_array_almost_equal(polls_d, sys.poles) + assert_almost_equal(k_d, sys.gain) + assert_almost_equal(dt_requested, sys.dt) def test_gbt_with_sio_tf_and_zpk(self): """Test method='gbt' with alpha=0.25 for tf and zpk cases.""" @@ -222,11 +222,12 @@ def test_gbt_with_sio_tf_and_zpk(self): dz, dp, dk = ss2zpk(Ad, Bd, Cd, Dd) # Compute the discrete zpk using cont2discrete. - c2dz, c2dp, c2dk, dt = c2d((cz, cp, ck), h, method='gbt', alpha=alpha) + #c2dz, c2dp, c2dk, dt = c2d((cz, cp, ck), h, method='gbt', alpha=alpha) + sys = c2d((cz, cp, ck), h, method='gbt', alpha=alpha) - assert_allclose(dz, c2dz) - assert_allclose(dp, c2dp) - assert_allclose(dk, c2dk) + assert_allclose(dz, sys.zeros) + assert_allclose(dp, sys.poles) + assert_allclose(dk, sys.gain) def test_discrete_approx(self): """ From fcf07b1ec9cd8cce0d18842edbdb1055d23eedd3 Mon Sep 17 00:00:00 2001 From: zerberros Date: Sun, 22 Feb 2015 21:20:15 +0100 Subject: [PATCH 8/8] adapted test_cont2discrete for the new dlti class --- scipy/signal/tests/test_cont2discrete.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scipy/signal/tests/test_cont2discrete.py b/scipy/signal/tests/test_cont2discrete.py index 36fa1277084e..97ad94b3c630 100644 --- a/scipy/signal/tests/test_cont2discrete.py +++ b/scipy/signal/tests/test_cont2discrete.py @@ -213,10 +213,10 @@ def test_gbt_with_sio_tf_and_zpk(self): dnum, dden = ss2tf(Ad, Bd, Cd, Dd) # Compute the discrete tf using cont2discrete. - c2dnum, c2dden, dt = c2d((cnum, cden), h, method='gbt', alpha=alpha) + sys = c2d((cnum, cden), h, method='gbt', alpha=alpha) - assert_allclose(dnum, c2dnum) - assert_allclose(dden, c2dden) + assert_allclose(dnum, sys.num) + assert_allclose(dden, sys.den) # Convert explicit solution to zpk. dz, dp, dk = ss2zpk(Ad, Bd, Cd, Dd)