def test_step_response_mimo(self, tsystem): """Test MIMO system, which contains ``siso_ss1`` twice.""" sys = tsystem.sys t = tsystem.t yref = tsystem.ystep _t, y_00 = step_response(sys, T=t, input=0, output=0) _t, y_11 = step_response(sys, T=t, input=1, output=1) np.testing.assert_array_almost_equal(y_00, yref, decimal=4) np.testing.assert_array_almost_equal(y_11, yref, decimal=4)
def test_step_response_return(self, tsystem): """Verify continuous and discrete time use same return conventions.""" sysc = tsystem.sys sysd = c2d(sysc, 1) # discrete time system Tvec = np.linspace(0, 10, 11) # make sure to use integer times 0..10 Tc, youtc = step_response(sysc, Tvec, input=0) Td, youtd = step_response(sysd, Tvec, input=0) np.testing.assert_array_equal(Tc.shape, Td.shape) np.testing.assert_array_equal(youtc.shape, youtd.shape)
def testSimulation(self): T = range(100) U = np.sin(T) # For now, just check calling syntax # TODO: add checks on output of simulations tout, yout = step_response(self.siso_ss1d) tout, yout = step_response(self.siso_ss1d, T) tout, yout = impulse_response(self.siso_ss1d, T) tout, yout = impulse_response(self.siso_ss1d) tout, yout, xout = forced_response(self.siso_ss1d, T, U, 0) tout, yout, xout = forced_response(self.siso_ss2d, T, U, 0) tout, yout, xout = forced_response(self.siso_ss3d, T, U, 0)
def test_step_robustness(self): "Test robustness os step_response against denomiantors: gh-240" # Create 2 input, 2 output system num = [[[0], [1]], [[1], [0]]] den1 = [[[1], [1,1]], [[1, 4], [1]]] sys1 = TransferFunction(num, den1) den2 = [[[1], [1e-10, 1, 1]], [[1, 4], [1]]] # slight perturbation sys2 = TransferFunction(num, den2) t1, y1 = step_response(sys1, input=0, T=2, T_num=100) t2, y2 = step_response(sys2, input=0, T=2, T_num=100) np.testing.assert_array_almost_equal(y1, y2)
def test_time_series_data_convention_2D(self, tsystem): """Allow input time as 2D array (output should be 1D)""" tin = np.array(np.linspace(0, 10, 100), ndmin=2) t, y = step_response(tsystem.sys, tin) assert isinstance(t, np.ndarray) and not isinstance(t, np.matrix) assert t.ndim == 1 assert y.ndim == 1 # SISO returns "scalar" output assert t.shape == y.shape # Allows direct plotting of output
def test_step_nostates(self, dt): """Constant system, continuous and discrete time. gh-374 "Bug in step_response()" """ sys = TransferFunction([1], [1], dt) t, y = step_response(sys) np.testing.assert_allclose(y, np.ones(len(t)))
def step(sys, T=None, X0=0., input=0, output=0, **keywords): ''' Step response of a linear system If the system has multiple inputs or outputs (MIMO), one input and one output have to be selected for the simulation. The parameters `input` and `output` do this. All other inputs are set to 0, all other outputs are ignored. Parameters ---------- sys: StateSpace, or TransferFunction LTI system to simulate T: array-like object, optional Time vector (argument is autocomputed if not given) X0: array-like or number, optional Initial condition (default = 0) Numbers are converted to constant arrays with the correct shape. input: int Index of the input that will be used in this simulation. output: int Index of the output that will be used in this simulation. **keywords: Additional keyword arguments control the solution algorithm for the differential equations. These arguments are passed on to the function :func:`control.forced_response`, 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 ------- yout: array Response of the system T: array Time values of the output See Also -------- lsim, initial, impulse Examples -------- >>> T, yout = step(sys, T, X0) ''' T, yout = timeresp.step_response(sys, T, X0, input, output, transpose = True, **keywords) return yout, T
def step(sys, T=None, X0=0., input=0, output=None, **keywords): ''' Step response of a linear system If the system has multiple inputs or outputs (MIMO), one input and one output have to be selected for the simulation. The parameters `input` and `output` do this. All other inputs are set to 0, all other outputs are ignored. Parameters ---------- sys: StateSpace, or TransferFunction LTI system to simulate T: array-like object, optional Time vector (argument is autocomputed if not given) X0: array-like or number, optional Initial condition (default = 0) Numbers are converted to constant arrays with the correct shape. input: int Index of the input that will be used in this simulation. output: int Index of the output that will be used in this simulation. **keywords: Additional keyword arguments control the solution algorithm for the differential equations. These arguments are passed on to the function :func:`control.forced_response`, 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 ------- yout: array Response of the system T: array Time values of the output See Also -------- lsim, initial, impulse Examples -------- >>> yout, T = step(sys, T, X0) ''' T, yout = timeresp.step_response(sys, T, X0, input, output, transpose = True, **keywords) return yout, T
def test_step_response_siso(self, tsystem, kwargs): """Test SISO system step response""" sys = tsystem.sys t = tsystem.t yref = tsystem.ystep # SISO call out = step_response(sys, T=t, **kwargs) tout, yout = out[:2] assert len(out) == 3 if ('return_x', True) in kwargs.items() else 2 np.testing.assert_array_almost_equal(tout, t) np.testing.assert_array_almost_equal(yout, yref, decimal=4)
def test_step_info(self, tsystem, systype, time_2d, yfinal): """Test step info for SISO systems.""" step_info_kwargs = tsystem.kwargs.get('step_info', {}) if systype == "time response": # simulate long enough for steady state value tfinal = 3 * tsystem.step_info['SettlingTime'] if np.isnan(tfinal): pytest.skip("test system does not settle") t, y = step_response(tsystem.sys, T=tfinal, T_num=5000) sysdata = y step_info_kwargs['T'] = t[np.newaxis, :] if time_2d else t else: sysdata = tsystem.sys if yfinal: step_info_kwargs['yfinal'] = tsystem.step_info['SteadyStateValue'] info = step_info(sysdata, **step_info_kwargs) self.assert_step_info_match(tsystem.sys, info, tsystem.step_info)
def test_step_info_mimo(self, tsystem, systype, yfinal): """Test step info for MIMO systems.""" step_info_kwargs = tsystem.kwargs.get('step_info', {}) if systype == "time response": tfinal = 3 * max([S['SettlingTime'] for Srow in tsystem.step_info for S in Srow]) t, y = step_response(tsystem.sys, T=tfinal, T_num=5000) sysdata = y step_info_kwargs['T'] = t else: sysdata = tsystem.sys if yfinal: step_info_kwargs['yfinal'] = [[S['SteadyStateValue'] for S in Srow] for Srow in tsystem.step_info] info_dict = step_info(sysdata, **step_info_kwargs) for i, row in enumerate(info_dict): for j, info in enumerate(row): self.assert_step_info_match(tsystem.sys, info, tsystem.step_info[i][j])
def test_discrete_time_steps(self, tsystem): """Make sure rounding errors in sample time are handled properly These tests play around with the input time vector to make sure that small rounding errors don't generate spurious errors. gh-332 """ sys = tsystem.sys # Set up a time range and simulate T = np.arange(0, 100, 0.2) tout1, yout1 = step_response(sys, T) # Simulate every other time step T = np.arange(0, 100, 0.4) tout2, yout2 = step_response(sys, T) np.testing.assert_array_almost_equal(tout1[::2], tout2) np.testing.assert_array_almost_equal(yout1[::2], yout2) # Add a small error into some of the time steps T = np.arange(0, 100, 0.2) T[1:-2:2] -= 1e-12 # tweak second value and a few others tout3, yout3 = step_response(sys, T) np.testing.assert_array_almost_equal(tout1, tout3) np.testing.assert_array_almost_equal(yout1, yout3) # Add a small error into some of the time steps (w/ skipping) T = np.arange(0, 100, 0.4) T[1:-2:2] -= 1e-12 # tweak second value and a few others tout4, yout4 = step_response(sys, T) np.testing.assert_array_almost_equal(tout2, tout4) np.testing.assert_array_almost_equal(yout2, yout4) # Make sure larger errors *do* generate an error T = np.arange(0, 100, 0.2) T[1:-2:2] -= 1e-3 # change second value and a few others with pytest.raises(ValueError): step_response(sys, T)
def test_squeeze_exception(self, fcn): sys = fcn(ct.rss(2, 1, 1)) with pytest.raises(ValueError, match="Unknown squeeze value"): step_response(sys, squeeze=1)