def testSSSS2(self, tsys): """State space system with state space feedback block, including a direct feedthrough term.""" sys3 = StateSpace([[-1., 4.], [2., -3]], [[2.], [3.]], [[-3., 1.]], [[-2.]]) sys4 = StateSpace([[-3., -2.], [1., 4.]], [[-2.], [-6.]], [[2., -3.]], [[3.]]) ans1 = feedback(sys3, sys4) ans2 = feedback(sys3, sys4, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-4.6, 5.2, 0.8, -1.2], [-3.4, -1.2, 1.2, -1.8], [-1.2, 0.4, -1.4, -4.4], [-3.6, 1.2, 5.8, -3.2]]) np.testing.assert_array_almost_equal(ans1.B, [[-0.4], [-0.6], [-0.8], [-2.4]]) np.testing.assert_array_almost_equal(ans1.C, [[0.6, -0.2, -0.8, 1.2]]) np.testing.assert_array_almost_equal(ans1.D, [[0.4]]) np.testing.assert_array_almost_equal(ans2.A, [[-3.57142857142857, 4.85714285714286, 0.571428571428571, -0.857142857142857], [-1.85714285714286, -1.71428571428571, 0.857142857142857, -1.28571428571429], [0.857142857142857, -0.285714285714286, -1.85714285714286, -3.71428571428571], [2.57142857142857, -0.857142857142857, 4.42857142857143, -1.14285714285714]]) np.testing.assert_array_almost_equal(ans2.B, [[0.285714285714286], [0.428571428571429], [0.571428571428571], [1.71428571428571]]) np.testing.assert_array_almost_equal(ans2.C, [[-0.428571428571429, 0.142857142857143, -0.571428571428571, 0.857142857142857]]) np.testing.assert_array_almost_equal(ans2.D, [[-0.285714285714286]])
def testSSSS2(self): """State space system with state space feedback block, including a direct feedthrough term.""" sys3 = StateSpace([[-1., 4.], [2., -3]], [[2.], [3.]], [[-3., 1.]], [[-2.]]) sys4 = StateSpace([[-3., -2.], [1., 4.]], [[-2.], [-6.]], [[2., -3.]], [[3.]]) ans1 = feedback(sys3, sys4) ans2 = feedback(sys3, sys4, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-4.6, 5.2, 0.8, -1.2], [-3.4, -1.2, 1.2, -1.8], [-1.2, 0.4, -1.4, -4.4], [-3.6, 1.2, 5.8, -3.2]]) np.testing.assert_array_almost_equal(ans1.B, [[-0.4], [-0.6], [-0.8], [-2.4]]) np.testing.assert_array_almost_equal(ans1.C, [[0.6, -0.2, -0.8, 1.2]]) np.testing.assert_array_almost_equal(ans1.D, [[0.4]]) np.testing.assert_array_almost_equal(ans2.A, [[-3.57142857142857, 4.85714285714286, 0.571428571428571, -0.857142857142857], [-1.85714285714286, -1.71428571428571, 0.857142857142857, -1.28571428571429], [0.857142857142857, -0.285714285714286, -1.85714285714286, -3.71428571428571], [2.57142857142857, -0.857142857142857, 4.42857142857143, -1.14285714285714]]) np.testing.assert_array_almost_equal(ans2.B, [[0.285714285714286], [0.428571428571429], [0.571428571428571], [1.71428571428571]]) np.testing.assert_array_almost_equal(ans2.C, [[-0.428571428571429, 0.142857142857143, -0.571428571428571, 0.857142857142857]]) np.testing.assert_array_almost_equal(ans2.D, [[-0.285714285714286]])
def testScalarScalar(self): """Scalar system with scalar feedback block.""" ans1 = feedback(self.x1, self.x2) ans2 = feedback(self.x1, self.x2, 1.) self.assertAlmostEqual(ans1.num[0][0][0] / ans1.den[0][0][0], -2.5 / 6.5) self.assertAlmostEqual(ans2.num[0][0][0] / ans2.den[0][0][0], 2.5 / 8.5)
def testScalarScalar(self, tsys): """Scalar system with scalar feedback block.""" ans1 = feedback(tsys.x1, tsys.x2) ans2 = feedback(tsys.x1, tsys.x2, 1.) np.testing.assert_almost_equal( ans1.num[0][0][0] / ans1.den[0][0][0], -2.5 / 6.5) np.testing.assert_almost_equal( ans2.num[0][0][0] / ans2.den[0][0][0], 2.5 / 8.5)
def testTFScalar(self, tsys): """Transfer function system with scalar feedback block.""" ans1 = feedback(tsys.sys1, tsys.x1) ans2 = feedback(tsys.sys1, tsys.x1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[1., 2.]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[1., 2.]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]])
def testTFScalar(self): """Transfer function system with scalar feedback block.""" ans1 = feedback(self.sys1, self.x1) ans2 = feedback(self.sys1, self.x1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[1., 2.]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[1., 2.]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]])
def testScalarTF(self): """Scalar system with transfer function feedback block.""" ans1 = feedback(self.x1, self.sys1) ans2 = feedback(self.x1, self.sys1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[2.5, 5., 7.5]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[2.5, 5., 7.5]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]])
def testTFTF(self): """Transfer function system with transfer function feedback block.""" ans1 = feedback(self.sys1, self.sys1) ans2 = feedback(self.sys1, self.sys1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[1., 4., 7., 6.]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4., 11., 16., 13.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[1., 4., 7., 6.]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., 4., 9., 8., 5.]]])
def testTFTF(self, tsys): """Transfer function system with transfer function feedback block.""" ans1 = feedback(tsys.sys1, tsys.sys1) ans2 = feedback(tsys.sys1, tsys.sys1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[1., 4., 7., 6.]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4., 11., 16., 13.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[1., 4., 7., 6.]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., 4., 9., 8., 5.]]])
def testSSScalar(self, tsys): """State space system with scalar feedback block.""" ans1 = feedback(tsys.sys2, tsys.x1) ans2 = feedback(tsys.sys2, tsys.x1, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) np.testing.assert_array_almost_equal(ans1.B, [[1.], [-4.]]) np.testing.assert_array_almost_equal(ans1.C, [[1., 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[0.]]) np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[1.], [-4.]]) np.testing.assert_array_almost_equal(ans2.C, [[1., 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[0.]])
def testScalarSS(self): """Scalar system with state space feedback block.""" ans1 = feedback(self.x1, self.sys2) ans2 = feedback(self.x1, self.sys2, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) np.testing.assert_array_almost_equal(ans1.B, [[2.5], [-10.]]) np.testing.assert_array_almost_equal(ans1.C, [[-2.5, 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[2.5]]) np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[2.5], [-10.]]) np.testing.assert_array_almost_equal(ans2.C, [[2.5, 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[2.5]])
def testSSScalar(self): """State space system with scalar feedback block.""" ans1 = feedback(self.sys2, self.x1) ans2 = feedback(self.sys2, self.x1, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) np.testing.assert_array_almost_equal(ans1.B, [[1.], [-4.]]) np.testing.assert_array_almost_equal(ans1.C, [[1., 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[0.]]) np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[1.], [-4.]]) np.testing.assert_array_almost_equal(ans2.C, [[1., 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[0.]])
def testSSSS1(self, tsys): """State space system with state space feedback block.""" ans1 = feedback(tsys.sys2, tsys.sys2) ans2 = feedback(tsys.sys2, tsys.sys2, 1.) np.testing.assert_array_almost_equal(ans1.A, [[1., 4., -1., 0.], [3., 2., 4., 0.], [1., 0., 1., 4.], [-4., 0., 3., 2]]) np.testing.assert_array_almost_equal(ans1.B, [[1.], [-4.], [0.], [0.]]) np.testing.assert_array_almost_equal(ans1.C, [[1., 0., 0., 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[0.]]) np.testing.assert_array_almost_equal(ans2.A, [[1., 4., 1., 0.], [3., 2., -4., 0.], [1., 0., 1., 4.], [-4., 0., 3., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[1.], [-4.], [0.], [0.]]) np.testing.assert_array_almost_equal(ans2.C, [[1., 0., 0., 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[0.]])
def testScalarTF(self, tsys): """Scalar system with transfer function feedback block.""" ans1 = feedback(tsys.x1, tsys.sys1) ans2 = feedback(tsys.x1, tsys.sys1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[2.5, 5., 7.5]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[2.5, 5., 7.5]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]]) # Make sure default arugments work as well ans3 = feedback(tsys.sys1, 1) ans4 = feedback(tsys.sys1) np.testing.assert_array_almost_equal(ans3.num, ans4.num) np.testing.assert_array_almost_equal(ans3.den, ans4.den)
def testSSSS1(self): """State space system with state space feedback block.""" ans1 = feedback(self.sys2, self.sys2) ans2 = feedback(self.sys2, self.sys2, 1.) np.testing.assert_array_almost_equal(ans1.A, [[1., 4., -1., 0.], [3., 2., 4., 0.], [1., 0., 1., 4.], [-4., 0., 3., 2]]) np.testing.assert_array_almost_equal(ans1.B, [[1.], [-4.], [0.], [0.]]) np.testing.assert_array_almost_equal(ans1.C, [[1., 0., 0., 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[0.]]) np.testing.assert_array_almost_equal(ans2.A, [[1., 4., 1., 0.], [3., 2., -4., 0.], [1., 0., 1., 4.], [-4., 0., 3., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[1.], [-4.], [0.], [0.]]) np.testing.assert_array_almost_equal(ans2.C, [[1., 0., 0., 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[0.]])
def testScalarTF(self): """Scalar system with transfer function feedback block.""" ans1 = feedback(self.x1, self.sys1) ans2 = feedback(self.x1, self.sys1, 1.) np.testing.assert_array_almost_equal(ans1.num, [[[2.5, 5., 7.5]]]) np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) np.testing.assert_array_almost_equal(ans2.num, [[[2.5, 5., 7.5]]]) np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]]) # Make sure default arugments work as well ans3 = feedback(self.sys1, 1) ans4 = feedback(self.sys1) np.testing.assert_array_almost_equal(ans3.num, ans4.num) np.testing.assert_array_almost_equal(ans3.den, ans4.den)
def gangof4_plot(P, C, omega=None): """Plot the "Gang of 4" transfer functions for a system Generates a 2x2 plot showing the "Gang of 4" sensitivity functions [T, PS; CS, S] Parameters ---------- P, C : Lti Linear input/output systems (process and control) omega : array Range of frequencies (list or bounds) in rad/sec Returns ------- None """ if (P.inputs > 1 or P.outputs > 1 or C.inputs > 1 or C.outputs > 1): #TODO: Add MIMO go4 plots. raise NotImplementedError( "Gang of four is currently only implemented for SISO systems.") else: # Select a default range if none is provided #! TODO: This needs to be made more intelligent if (omega == None): omega = default_frequency_range((P, C)) # Compute the senstivity functions L = P * C S = feedback(1, L) T = L * S # Plot the four sensitivity functions #! TODO: Need to add in the mag = 1 lines mag_tmp, phase_tmp, omega = T.freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(221) plt.loglog(omega, mag) mag_tmp, phase_tmp, omega = (P * S).freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(222) plt.loglog(omega, mag) mag_tmp, phase_tmp, omega = (C * S).freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(223) plt.loglog(omega, mag) mag_tmp, phase_tmp, omega = S.freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(224) plt.loglog(omega, mag)
def testRootLocus(self): """Basic root locus plot""" klist = [-1, 0, 1] rlist = root_locus(self.sys1, [-1, 0, 1], Plot=False) for k in klist: np.testing.assert_array_almost_equal( np.sort(rlist[k]), np.sort(feedback(self.sys1, klist[k]).pole()))
def testScalarSS(self, tsys): """Scalar system with state space feedback block.""" ans1 = feedback(tsys.x1, tsys.sys2) ans2 = feedback(tsys.x1, tsys.sys2, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) np.testing.assert_array_almost_equal(ans1.B, [[2.5], [-10.]]) np.testing.assert_array_almost_equal(ans1.C, [[-2.5, 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[2.5]]) np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[2.5], [-10.]]) np.testing.assert_array_almost_equal(ans2.C, [[2.5, 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[2.5]]) # Make sure default arugments work as well ans3 = feedback(tsys.sys2, 1) ans4 = feedback(tsys.sys2) np.testing.assert_array_almost_equal(ans3.A, ans4.A) np.testing.assert_array_almost_equal(ans3.B, ans4.B) np.testing.assert_array_almost_equal(ans3.C, ans4.C) np.testing.assert_array_almost_equal(ans3.D, ans4.D)
def gangof4_plot(P, C, omega=None): """Plot the "Gang of 4" transfer functions for a system Generates a 2x2 plot showing the "Gang of 4" sensitivity functions [T, PS; CS, S] Parameters ---------- P, C : Lti Linear input/output systems (process and control) omega : array Range of frequencies (list or bounds) in rad/sec Returns ------- None """ if (P.inputs > 1 or P.outputs > 1 or C.inputs > 1 or C.outputs >1): #TODO: Add MIMO go4 plots. raise NotImplementedError("Gang of four is currently only implemented for SISO systems.") else: # Select a default range if none is provided #! TODO: This needs to be made more intelligent if (omega == None): omega = default_frequency_range((P,C)) # Compute the senstivity functions L = P*C; S = feedback(1, L); T = L * S; # Plot the four sensitivity functions #! TODO: Need to add in the mag = 1 lines mag_tmp, phase_tmp, omega = T.freqresp(omega); mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(221); plt.loglog(omega, mag); mag_tmp, phase_tmp, omega = (P*S).freqresp(omega); mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(222); plt.loglog(omega, mag); mag_tmp, phase_tmp, omega = (C*S).freqresp(omega); mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(223); plt.loglog(omega, mag); mag_tmp, phase_tmp, omega = S.freqresp(omega); mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) plt.subplot(224); plt.loglog(omega, mag);
def testScalarSS(self): """Scalar system with state space feedback block.""" ans1 = feedback(self.x1, self.sys2) ans2 = feedback(self.x1, self.sys2, 1.) np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) np.testing.assert_array_almost_equal(ans1.B, [[2.5], [-10.]]) np.testing.assert_array_almost_equal(ans1.C, [[-2.5, 0.]]) np.testing.assert_array_almost_equal(ans1.D, [[2.5]]) np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) np.testing.assert_array_almost_equal(ans2.B, [[2.5], [-10.]]) np.testing.assert_array_almost_equal(ans2.C, [[2.5, 0.]]) np.testing.assert_array_almost_equal(ans2.D, [[2.5]]) # Make sure default arugments work as well ans3 = feedback(self.sys2, 1) ans4 = feedback(self.sys2) np.testing.assert_array_almost_equal(ans3.A, ans4.A) np.testing.assert_array_almost_equal(ans3.B, ans4.B) np.testing.assert_array_almost_equal(ans3.C, ans4.C) np.testing.assert_array_almost_equal(ans3.D, ans4.D)
def testbdalg(self): # get two SISO transfer functions h1 = TransferFunction([1], [1, 2, 2]) h2 = TransferFunction([1], [0.1, 1]) omega = np.logspace(-1, 2, 10) f1 = FRD(h1, omega) f2 = FRD(h2, omega) np.testing.assert_array_almost_equal( (bdalg.series(f1, f2)).frequency_response([0.1, 1.0, 10])[0], (bdalg.series(h1, h2)).frequency_response([0.1, 1.0, 10])[0]) np.testing.assert_array_almost_equal( (bdalg.parallel(f1, f2)).frequency_response([0.1, 1.0, 10])[0], (bdalg.parallel(h1, h2)).frequency_response([0.1, 1.0, 10])[0]) np.testing.assert_array_almost_equal( (bdalg.feedback(f1, f2)).frequency_response([0.1, 1.0, 10])[0], (bdalg.feedback(h1, h2)).frequency_response([0.1, 1.0, 10])[0]) np.testing.assert_array_almost_equal( (bdalg.negate(f1)).frequency_response([0.1, 1.0, 10])[0], (bdalg.negate(h1)).frequency_response([0.1, 1.0, 10])[0])
def testbdalg(self): # get two SISO transfer functions h1 = TransferFunction([1], [1, 2, 2]) h2 = TransferFunction([1], [0.1, 1]) omega = np.logspace(-1, 2, 10) f1 = FRD(h1, omega) f2 = FRD(h2, omega) np.testing.assert_array_almost_equal( (bdalg.series(f1, f2)).freqresp([0.1, 1.0, 10])[0], (bdalg.series(h1, h2)).freqresp([0.1, 1.0, 10])[0]) np.testing.assert_array_almost_equal( (bdalg.parallel(f1, f2)).freqresp([0.1, 1.0, 10])[0], (bdalg.parallel(h1, h2)).freqresp([0.1, 1.0, 10])[0]) np.testing.assert_array_almost_equal( (bdalg.feedback(f1, f2)).freqresp([0.1, 1.0, 10])[0], (bdalg.feedback(h1, h2)).freqresp([0.1, 1.0, 10])[0]) np.testing.assert_array_almost_equal( (bdalg.negate(f1)).freqresp([0.1, 1.0, 10])[0], (bdalg.negate(h1)).freqresp([0.1, 1.0, 10])[0])
def testFeedback(self): # State space addition sys = feedback(self.siso_ss1, self.siso_ss1d) sys = feedback(self.siso_ss1, self.siso_ss1c) sys = feedback(self.siso_ss1c, self.siso_ss1) sys = feedback(self.siso_ss1d, self.siso_ss1) sys = feedback(self.siso_ss1c, self.siso_ss1c) sys = feedback(self.siso_ss1d, self.siso_ss1d) self.assertRaises(ValueError, feedback, self.mimo_ss1c, self.mimo_ss1d) self.assertRaises(ValueError, feedback, self.mimo_ss1d, self.mimo_ss2d) self.assertRaises(ValueError, feedback, self.siso_ss1d, self.siso_ss3d) # Transfer function addition sys = feedback(self.siso_tf1, self.siso_tf1d) sys = feedback(self.siso_tf1, self.siso_tf1c) sys = feedback(self.siso_tf1c, self.siso_tf1) sys = feedback(self.siso_tf1d, self.siso_tf1) sys = feedback(self.siso_tf1c, self.siso_tf1c) sys = feedback(self.siso_tf1d, self.siso_tf1d) self.assertRaises(ValueError, feedback, self.siso_tf1c, self.siso_tf1d) self.assertRaises(ValueError, feedback, self.siso_tf1d, self.siso_tf2d) self.assertRaises(ValueError, feedback, self.siso_tf1d, self.siso_tf3d) # State space, transfer function sys = feedback(self.siso_ss1c, self.siso_tf1c) sys = feedback(self.siso_tf1c, self.siso_ss1c) sys = feedback(self.siso_ss1d, self.siso_tf1d) sys = feedback(self.siso_tf1d, self.siso_ss1d) self.assertRaises(ValueError, feedback, self.siso_tf1c, self.siso_ss1d)
def check_cl_poles(self, sys, pole_list, k_list): for k, poles in zip(k_list, pole_list): poles_expected = np.sort(feedback(sys, k).pole()) poles = np.sort(poles) np.testing.assert_array_almost_equal(poles, poles_expected)