[Scipy-svn] r6367 - in trunk: doc/release doc/source scipy/signal scipy/signal/tests

scipy-svn at scipy.org scipy-svn at scipy.org
Sun May 2 19:19:59 EDT 2010


Author: warren.weckesser
Date: 2010-05-02 18:19:59 -0500 (Sun, 02 May 2010)
New Revision: 6367

Modified:
   trunk/doc/release/0.8.0-notes.rst
   trunk/doc/source/signal.rst
   trunk/scipy/signal/info.py
   trunk/scipy/signal/ltisys.py
   trunk/scipy/signal/tests/test_ltisys.py
Log:
ENH: signal: Added the function step2 to compute the step response of a linear system using lsim2 (which used odeint).

Modified: trunk/doc/release/0.8.0-notes.rst
===================================================================
--- trunk/doc/release/0.8.0-notes.rst	2010-05-02 02:20:45 UTC (rev 6366)
+++ trunk/doc/release/0.8.0-notes.rst	2010-05-02 23:19:59 UTC (rev 6367)
@@ -85,9 +85,9 @@
 
 Additions and modification to LTI functions (scipy.signal)
 ----------------------------------------------------------
-* The function `impulse2` was added to `scipy.signal`.  It uses the ODE
-  solver `scipy.integrate.odeint` to compute the impulse response of
-  a system.
+* The functions `impulse2` and `step2` were added to `scipy.signal`.
+  They use the function `scipy.signal.lsim2` to compute the impulse and
+  step response of a system, respectively.
 * The function `scipy.signal.lsim2` was changed to pass any additional
   keyword arguments to the ODE solver.
 

Modified: trunk/doc/source/signal.rst
===================================================================
--- trunk/doc/source/signal.rst	2010-05-02 02:20:45 UTC (rev 6366)
+++ trunk/doc/source/signal.rst	2010-05-02 23:19:59 UTC (rev 6367)
@@ -103,6 +103,7 @@
    impulse
    impulse2
    step
+   step2
 
 LTI Reresentations
 ==================

Modified: trunk/scipy/signal/info.py
===================================================================
--- trunk/scipy/signal/info.py	2010-05-02 02:20:45 UTC (rev 6366)
+++ trunk/scipy/signal/info.py	2010-05-02 23:19:59 UTC (rev 6367)
@@ -70,8 +70,9 @@
     lsim     -- continuous-time simulation of output to linear system.
     lsim2    -- like lsim, but `scipy.integrate.odeint` is used. 
     impulse  -- impulse response of linear, time-invariant (LTI) system.
-    impulse2 -- like impulse2, but `scipy.integrate.odeint` is used.
+    impulse2 -- like impulse, but `scipy.integrate.odeint` is used.
     step     -- step response of continous-time LTI system.
+    step2    -- like step, but `scipy.integrate.odeint` is used.
 
  LTI Reresentations:
 

Modified: trunk/scipy/signal/ltisys.py
===================================================================
--- trunk/scipy/signal/ltisys.py	2010-05-02 02:20:45 UTC (rev 6366)
+++ trunk/scipy/signal/ltisys.py	2010-05-02 23:19:59 UTC (rev 6367)
@@ -495,8 +495,9 @@
 def _default_response_times(A, n):
     """Compute a reasonable set of time samples for the response time.
 
-    This function is used by impulse(), impulse2() and step() to compute
-    the response time when the `T` argument to the function  is None.
+    This function is used by impulse(), impulse2(), step() and step2()
+    to compute the response time when the `T` argument to the function
+    is None.
 
     Parameters
     ----------
@@ -595,7 +596,7 @@
     **kwargs :
         Additional keyword arguments are passed on the function
         `scipy.signal.lsim2`, which in turn passes them on to
-        :func:`scipy.integrate.odeint`.  See the documation for
+        :func:`scipy.integrate.odeint`.  See the documentation for
         :func:`scipy.integrate.odeint` for information about these
         arguments.
 
@@ -661,6 +662,9 @@
     yout : 1D ndarray
         Step response of system.
 
+    See also
+    --------
+    scipy.signal.step2
     """
     if isinstance(system, lti):
         sys = system
@@ -673,3 +677,58 @@
     U = ones(T.shape, sys.A.dtype)
     vals = lsim(sys, U, T, X0=X0)
     return vals[0], vals[1]
+
+def step2(system, X0=None, T=None, N=None, **kwargs):
+    """Step response of continuous-time system.
+    
+    This function is functionally the same as `scipy.signal.step`, but
+    it uses the function `scipy.ltisys.lsim2` to compute the step
+    response.
+
+    Parameters
+    ----------
+    system : an instance of the LTI class or a tuple describing the system.
+        The following gives the number of elements in the tuple and
+        the interpretation.
+            2 (num, den)
+            3 (zeros, poles, gain)
+            4 (A, B, C, D)
+    X0 : array_like, optional
+        Initial state-vector (default is zero).
+    T : array_like, optional
+        Time points (computed if not given).
+    N : int
+        Number of time points to compute if `T` is not given.
+    **kwargs :
+        Additional keyword arguments are passed on the function
+        `scipy.signal.lsim2`, which in turn passes them on to
+        :func:`scipy.integrate.odeint`.  See the documentation for
+        :func:`scipy.integrate.odeint` for information about these
+        arguments.
+
+    Returns
+    -------
+    T : 1D ndarray
+        Output time points.
+    yout : 1D ndarray
+        Step response of system.
+
+    See also
+    --------
+    scipy.signal.step
+
+    Notes
+    -----
+    .. versionadded:: 0.8.0
+    """
+    if isinstance(system, lti):
+        sys = system
+    else:
+        sys = lti(*system)
+    if N is None:
+        N = 100
+    if T is None:
+        T = _default_response_times(sys.A, N)
+    U = ones(T.shape, sys.A.dtype)
+    vals = lsim2(sys, U, T, X0=X0, **kwargs)
+    return vals[0], vals[1]

Modified: trunk/scipy/signal/tests/test_ltisys.py
===================================================================
--- trunk/scipy/signal/tests/test_ltisys.py	2010-05-02 02:20:45 UTC (rev 6366)
+++ trunk/scipy/signal/tests/test_ltisys.py	2010-05-02 23:19:59 UTC (rev 6367)
@@ -1,8 +1,9 @@
 import numpy as np
 from numpy.testing import assert_almost_equal, assert_equal, run_module_suite
 
-from scipy.signal.ltisys import ss2tf, lsim2, impulse2, lti
+from scipy.signal.ltisys import ss2tf, lsim2, impulse2, step2, lti
 
+
 class TestSS2TF:
     def tst_matrix_shapes(self, p, q, r):
         ss2tf(np.zeros((p, p)),
@@ -148,5 +149,65 @@
         expected_y = tout * np.exp(-tout)
         assert_almost_equal(y, expected_y)
 
+class Test_step2(object):
+
+    def test_01(self):
+        # First order system: x'(t) + x(t) = u(t)
+        # Exact step response is x(t) = 1 - exp(-t).
+        system = ([1.0],[1.0,1.0])
+        tout, y = step2(system)
+        expected_y = 1.0 - np.exp(-tout)
+        assert_almost_equal(y, expected_y)
+
+    def test_02(self):
+        """Specify the desired time values for the output."""
+
+        # First order system: x'(t) + x(t) = u(t)
+        # Exact step response is x(t) = 1 - exp(-t).
+        system = ([1.0],[1.0,1.0])
+        n = 21
+        t = np.linspace(0, 2.0, n)
+        tout, y = step2(system, T=t)
+        assert_equal(tout.shape, (n,))
+        assert_almost_equal(tout, t)
+        expected_y = 1 - np.exp(-t)
+        assert_almost_equal(y, expected_y)
+
+    def test_03(self):
+        """Specify an initial condition as a scalar."""
+        
+        # First order system: x'(t) + x(t) = u(t), x(0)=3.0
+        # Exact step response is x(t) = 1 + 2*exp(-t).
+        system = ([1.0],[1.0,1.0])
+        tout, y = step2(system, X0=3.0)
+        expected_y = 1 + 2.0*np.exp(-tout)
+        assert_almost_equal(y, expected_y)
+
+    def test_04(self):
+        """Specify an initial condition as a list."""
+
+        # First order system: x'(t) + x(t) = u(t), x(0)=3.0
+        # Exact step response is x(t) = 1 + 2*exp(-t).
+        system = ([1.0],[1.0,1.0])
+        tout, y = step2(system, X0=[3.0])
+        expected_y = 1 + 2.0*np.exp(-tout)
+        assert_almost_equal(y, expected_y)
+
+    def test_05(self):
+        # Simple integrator: x'(t) = u(t)
+        # Exact step response is x(t) = t.
+        system = ([1.0],[1.0,0.0])
+        tout, y = step2(system, atol=1e-10, rtol=1e-8)
+        expected_y = tout
+        assert_almost_equal(y, expected_y)
+
+    def test_06(self):
+        # Second order system with a repeated root: x''(t) + 2*x(t) + x(t) = u(t)
+        # The exact step response is 1 - (1 + t)*exp(-t).
+        system = ([1.0], [1.0, 2.0, 1.0])
+        tout, y = step2(system, atol=1e-10, rtol=1e-8)
+        expected_y = 1 - (1 + tout) * np.exp(-tout)
+        assert_almost_equal(y, expected_y)
+
 if __name__ == "__main__":
     run_module_suite()




More information about the Scipy-svn mailing list