def testTF(self, verbose=False): """ Directly tests the functions tb04ad and td04ad through direct comparison of transfer function coefficients. Similar to convert_test, but tests at a lower level. """ from slycot import tb04ad, td04ad for states in range(1, self.maxStates): for inputs in range(1, self.maxI+1): for outputs in range(1, self.maxO+1): for testNum in range(self.numTests): ssOriginal = matlab.rss(states, outputs, inputs) if (verbose): print('====== Original SS ==========') print(ssOriginal) print('states=', states) print('inputs=', inputs) print('outputs=', outputs) tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb,\ tfOrigingal_nctrb, tfOriginal_index,\ tfOriginal_dcoeff, tfOriginal_ucoeff =\ tb04ad(states, inputs, outputs, ssOriginal.A, ssOriginal.B, ssOriginal.C, ssOriginal.D, tol1=0.0) ssTransformed_nr, ssTransformed_A, ssTransformed_B,\ ssTransformed_C, ssTransformed_D\ = td04ad('R', inputs, outputs, tfOriginal_index, tfOriginal_dcoeff, tfOriginal_ucoeff, tol=0.0) tfTransformed_Actrb, tfTransformed_Bctrb,\ tfTransformed_Cctrb, tfTransformed_nctrb,\ tfTransformed_index, tfTransformed_dcoeff,\ tfTransformed_ucoeff = tb04ad( ssTransformed_nr, inputs, outputs, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D, tol1=0.0) # print 'size(Trans_A)=',ssTransformed_A.shape if (verbose): print('===== Transformed SS ==========') print(matlab.ss(ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D)) # print 'Trans_nr=',ssTransformed_nr # print 'tfOrig_index=',tfOriginal_index # print 'tfOrig_ucoeff=',tfOriginal_ucoeff # print 'tfOrig_dcoeff=',tfOriginal_dcoeff # print 'tfTrans_index=',tfTransformed_index # print 'tfTrans_ucoeff=',tfTransformed_ucoeff # print 'tfTrans_dcoeff=',tfTransformed_dcoeff # Compare the TF directly, must match # numerators np.testing.assert_array_almost_equal( tfOriginal_ucoeff, tfTransformed_ucoeff, decimal=3) # denominators np.testing.assert_array_almost_equal( tfOriginal_dcoeff, tfTransformed_dcoeff, decimal=3)
def testTF(self, verbose=False): """ Directly tests the functions tb04ad and td04ad through direct comparison of transfer function coefficients. Similar to convert_test, but tests at a lower level. """ from slycot import tb04ad, td04ad for states in range(1, self.maxStates): for inputs in range(1, self.maxI + 1): for outputs in range(1, self.maxO + 1): for testNum in range(self.numTests): ssOriginal = matlab.rss(states, outputs, inputs) if (verbose): print('====== Original SS ==========') print(ssOriginal) print('states=', states) print('inputs=', inputs) print('outputs=', outputs) tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb,\ tfOrigingal_nctrb, tfOriginal_index,\ tfOriginal_dcoeff, tfOriginal_ucoeff =\ tb04ad(states, inputs, outputs, ssOriginal.A, ssOriginal.B, ssOriginal.C, ssOriginal.D, tol1=0.0) ssTransformed_nr, ssTransformed_A, ssTransformed_B,\ ssTransformed_C, ssTransformed_D\ = td04ad('R', inputs, outputs, tfOriginal_index, tfOriginal_dcoeff, tfOriginal_ucoeff, tol=0.0) tfTransformed_Actrb, tfTransformed_Bctrb,\ tfTransformed_Cctrb, tfTransformed_nctrb,\ tfTransformed_index, tfTransformed_dcoeff,\ tfTransformed_ucoeff = tb04ad( ssTransformed_nr, inputs, outputs, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D, tol1=0.0) # print('size(Trans_A)=',ssTransformed_A.shape) if (verbose): print('===== Transformed SS ==========') print( matlab.ss(ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D))
def testTF(self, verbose=False): """ Directly tests the functions tb04ad and td04ad through direct comparison of transfer function coefficients. Similar to convert_test, but tests at a lower level. """ from slycot import tb04ad, td04ad for states in range(1, self.maxStates): for inputs in range(1, self.maxI + 1): for outputs in range(1, self.maxO + 1): for testNum in range(self.numTests): ssOriginal = matlab.rss(states, outputs, inputs) if (verbose): print('====== Original SS ==========') print(ssOriginal) print('states=', states) print('inputs=', inputs) print('outputs=', outputs) tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb, tfOrigingal_nctrb, tfOriginal_index,\ tfOriginal_dcoeff, tfOriginal_ucoeff = tb04ad(states,inputs,outputs,\ ssOriginal.A,ssOriginal.B,ssOriginal.C,ssOriginal.D,tol1=0.0) ssTransformed_nr, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D\ = td04ad('R',inputs,outputs,tfOriginal_index,tfOriginal_dcoeff,tfOriginal_ucoeff,tol=0.0) tfTransformed_Actrb, tfTransformed_Bctrb, tfTransformed_Cctrb, tfTransformed_nctrb,\ tfTransformed_index, tfTransformed_dcoeff, tfTransformed_ucoeff = tb04ad(ssTransformed_nr,\ inputs,outputs,ssTransformed_A, ssTransformed_B, ssTransformed_C,ssTransformed_D,tol1=0.0) #print 'size(Trans_A)=',ssTransformed_A.shape if (verbose): print('===== Transformed SS ==========') print( matlab.ss(ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D)) # print 'Trans_nr=',ssTransformed_nr # print 'tfOrig_index=',tfOriginal_index # print 'tfOrig_ucoeff=',tfOriginal_ucoeff # print 'tfOrig_dcoeff=',tfOriginal_dcoeff # print 'tfTrans_index=',tfTransformed_index # print 'tfTrans_ucoeff=',tfTransformed_ucoeff # print 'tfTrans_dcoeff=',tfTransformed_dcoeff #Compare the TF directly, must match #numerators np.testing.assert_array_almost_equal( tfOriginal_ucoeff, tfTransformed_ucoeff, decimal=3) #denominators np.testing.assert_array_almost_equal( tfOriginal_dcoeff, tfTransformed_dcoeff, decimal=3)
def testFreqResp(self): """Compare the bode reponses of the SS systems and TF systems to the original SS They generally are different realizations but have same freq resp. Currently this test may only be applied to SISO systems. """ for states in range(1,self.maxStates): for testNum in range(self.numTests): for inputs in range(1,1): for outputs in range(1,1): ssOriginal = matlab.rss(states, inputs, outputs) tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb, tfOrigingal_nctrb, tfOriginal_index,\ tfOriginal_dcoeff, tfOriginal_ucoeff = tb04ad(states,inputs,outputs,\ ssOriginal.A,ssOriginal.B,ssOriginal.C,ssOriginal.D,tol1=0.0) ssTransformed_nr, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D\ = td04ad('R',inputs,outputs,tfOriginal_index,tfOriginal_dcoeff,tfOriginal_ucoeff,tol=0.0) tfTransformed_Actrb, tfTransformed_Bctrb, tfTransformed_Cctrb, tfTransformed_nctrb,\ tfTransformed_index, tfTransformed_dcoeff, tfTransformed_ucoeff = tb04ad(\ ssTransformed_nr,inputs,outputs,ssTransformed_A, ssTransformed_B, ssTransformed_C,\ ssTransformed_D,tol1=0.0) numTransformed = np.array(tfTransformed_ucoeff) denTransformed = np.array(tfTransformed_dcoeff) numOriginal = np.array(tfOriginal_ucoeff) denOriginal = np.array(tfOriginal_dcoeff) ssTransformed = matlab.ss(ssTransformed_A,ssTransformed_B,ssTransformed_C,ssTransformed_D) for inputNum in range(inputs): for outputNum in range(outputs): [ssOriginalMag,ssOriginalPhase,freq] = matlab.bode(ssOriginal,Plot=False) [tfOriginalMag,tfOriginalPhase,freq] = matlab.bode(matlab.tf(numOriginal[outputNum][inputNum],denOriginal[outputNum]),Plot=False) [ssTransformedMag,ssTransformedPhase,freq] = matlab.bode(ssTransformed,freq,Plot=False) [tfTransformedMag,tfTransformedPhase,freq] = matlab.bode(matlab.tf(numTransformed[outputNum][inputNum],denTransformed[outputNum]),freq,Plot=False) #print 'numOrig=',numOriginal[outputNum][inputNum] #print 'denOrig=',denOriginal[outputNum] #print 'numTrans=',numTransformed[outputNum][inputNum] #print 'denTrans=',denTransformed[outputNum] np.testing.assert_array_almost_equal(ssOriginalMag,tfOriginalMag,decimal=3) np.testing.assert_array_almost_equal(ssOriginalPhase,tfOriginalPhase,decimal=3) np.testing.assert_array_almost_equal(ssOriginalMag,ssTransformedMag,decimal=3) np.testing.assert_array_almost_equal(ssOriginalPhase,ssTransformedPhase,decimal=3) np.testing.assert_array_almost_equal(tfOriginalMag,tfTransformedMag,decimal=3) np.testing.assert_array_almost_equal(tfOriginalPhase,tfTransformedPhase,decimal=2)
def testFreqResp(self): """Compare the bode reponses of the SS systems and TF systems to the original SS They generally are different realizations but have same freq resp. Currently this test may only be applied to SISO systems. """ from slycot import tb04ad, td04ad for states in range(1, self.maxStates): for testNum in range(self.numTests): for inputs in range(1, 1): for outputs in range(1, 1): ssOriginal = matlab.rss(states, outputs, inputs) tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb,\ tfOrigingal_nctrb, tfOriginal_index,\ tfOriginal_dcoeff, tfOriginal_ucoeff = tb04ad( states, inputs, outputs, ssOriginal.A, ssOriginal.B, ssOriginal.C, ssOriginal.D, tol1=0.0) ssTransformed_nr, ssTransformed_A, ssTransformed_B,\ ssTransformed_C, ssTransformed_D\ = td04ad('R', inputs, outputs, tfOriginal_index, tfOriginal_dcoeff, tfOriginal_ucoeff, tol=0.0) tfTransformed_Actrb, tfTransformed_Bctrb,\ tfTransformed_Cctrb, tfTransformed_nctrb,\ tfTransformed_index, tfTransformed_dcoeff,\ tfTransformed_ucoeff = tb04ad( ssTransformed_nr, inputs, outputs, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D, tol1=0.0) numTransformed = np.array(tfTransformed_ucoeff) denTransformed = np.array(tfTransformed_dcoeff) numOriginal = np.array(tfOriginal_ucoeff) denOriginal = np.array(tfOriginal_dcoeff) ssTransformed = matlab.ss(ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D) for inputNum in range(inputs): for outputNum in range(outputs): [ssOriginalMag, ssOriginalPhase, freq] =\ matlab.bode(ssOriginal, plot=False) [tfOriginalMag, tfOriginalPhase, freq] =\ matlab.bode(matlab.tf( numOriginal[outputNum][inputNum], denOriginal[outputNum]), plot=False) [ssTransformedMag, ssTransformedPhase, freq] =\ matlab.bode(ssTransformed, freq, plot=False) [tfTransformedMag, tfTransformedPhase, freq] =\ matlab.bode(matlab.tf( numTransformed[outputNum][inputNum], denTransformed[outputNum]), freq, plot=False) # print('numOrig=', # numOriginal[outputNum][inputNum]) # print('denOrig=', # denOriginal[outputNum]) # print('numTrans=', # numTransformed[outputNum][inputNum]) # print('denTrans=', # denTransformed[outputNum]) np.testing.assert_array_almost_equal( ssOriginalMag, tfOriginalMag, decimal=3) np.testing.assert_array_almost_equal( ssOriginalPhase, tfOriginalPhase, decimal=3) np.testing.assert_array_almost_equal( ssOriginalMag, ssTransformedMag, decimal=3) np.testing.assert_array_almost_equal( ssOriginalPhase, ssTransformedPhase, decimal=3) np.testing.assert_array_almost_equal( tfOriginalMag, tfTransformedMag, decimal=3) np.testing.assert_array_almost_equal( tfOriginalPhase, tfTransformedPhase, decimal=2)
def _convertToTransferFunction(sys, **kw): """Convert a system to transfer function form (if needed). If sys is already a transfer function, then it is returned. If sys is a state space object, then it is converted to a transfer function and returned. If sys is a scalar, then the number of inputs and outputs can be specified manually, as in: >>> sys = _convertToTransferFunction(3.) # Assumes inputs = outputs = 1 >>> sys = _convertToTransferFunction(1., inputs=3, outputs=2) In the latter example, sys's matrix transfer function is [[1., 1., 1.] [1., 1., 1.]]. If sys is an array-like type, then it is converted to a constant-gain transfer function. >>> sys = _convertToTransferFunction([[1. 0.], [2. 3.]]) In this example, the numerator matrix will be [[[1.0], [0.0]], [[2.0], [3.0]]] and the denominator matrix [[[1.0], [1.0]], [[1.0], [1.0]]] """ from .statesp import StateSpace if isinstance(sys, TransferFunction): if len(kw): raise TypeError("If sys is a TransferFunction, " + "_convertToTransferFunction cannot take keywords.") return sys elif isinstance(sys, StateSpace): if 0 == sys.states: # Slycot doesn't like static SS->TF conversion, so handle # it first. Can't join this with the no-Slycot branch, # since that doesn't handle general MIMO systems num = [[[sys.D[i, j]] for j in range(sys.inputs)] for i in range(sys.outputs)] den = [[[1.] for j in range(sys.inputs)] for i in range(sys.outputs)] else: try: from slycot import tb04ad if len(kw): raise TypeError( "If sys is a StateSpace, " + "_convertToTransferFunction cannot take keywords.") # Use Slycot to make the transformation # Make sure to convert system matrices to numpy arrays tfout = tb04ad(sys.states, sys.inputs, sys.outputs, array(sys.A), array(sys.B), array(sys.C), array(sys.D), tol1=0.0) # Preallocate outputs. num = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] den = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] for i in range(sys.outputs): for j in range(sys.inputs): num[i][j] = list(tfout[6][i, j, :]) # 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) # 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.")
def _convertToTransferFunction(sys, **kw): """Convert a system to transfer function form (if needed). If sys is already a transfer function, then it is returned. If sys is a state space object, then it is converted to a transfer function and returned. If sys is a scalar, then the number of inputs and outputs can be specified manually, as in: >>> sys = _convertToTransferFunction(3.) # Assumes inputs = outputs = 1 >>> sys = _convertToTransferFunction(1., inputs=3, outputs=2) In the latter example, sys's matrix transfer function is [[1., 1., 1.] [1., 1., 1.]]. If sys is an array-like type, then it is converted to a constant-gain transfer function. >>> sys = _convertToTransferFunction([[1. 0.], [2. 3.]]) In this example, the numerator matrix will be [[[1.0], [0.0]], [[2.0], [3.0]]] and the denominator matrix [[[1.0], [1.0]], [[1.0], [1.0]]] """ from .statesp import StateSpace if isinstance(sys, TransferFunction): if len(kw): raise TypeError("If sys is a TransferFunction, " + "_convertToTransferFunction cannot take keywords.") return sys elif isinstance(sys, StateSpace): try: from slycot import tb04ad if len(kw): raise TypeError( "If sys is a StateSpace, " + "_convertToTransferFunction cannot take keywords.") # Use Slycot to make the transformation # Make sure to convert system matrices to numpy arrays tfout = tb04ad(sys.states, sys.inputs, sys.outputs, array(sys.A), array(sys.B), array(sys.C), array(sys.D), tol1=0.0) # Preallocate outputs. num = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] den = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] for i in range(sys.outputs): for j in range(sys.inputs): num[i][j] = list(tfout[6][i, j, :]) # Each transfer function matrix row # has a common denominator. den[i][j] = list(tfout[5][i, :]) # print(num) # print(den) 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") lti_sys = lti(sys.A, sys.B, sys.C, sys.D) num = squeeze(lti_sys.num) den = squeeze(lti_sys.den) # print(num) # print(den) return TransferFunction(num, den, sys.dt) elif isinstance(sys, (int, float, complex)): 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) # 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.")
def _convertToTransferFunction(sys, **kw): """Convert a system to transfer function form (if needed). If sys is already a transfer function, then it is returned. If sys is a state space object, then it is converted to a transfer function and returned. If sys is a scalar, then the number of inputs and outputs can be specified manually, as in: >>> sys = _convertToTransferFunction(3.) # Assumes inputs = outputs = 1 >>> sys = _convertToTransferFunction(1., inputs=3, outputs=2) In the latter example, sys's matrix transfer function is [[1., 1., 1.] [1., 1., 1.]]. """ if isinstance(sys, TransferFunction): if len(kw): raise TypeError("If sys is a TransferFunction, \ _convertToTransferFunction cannot take keywords.") return sys elif isinstance(sys, statesp.StateSpace): try: from slycot import tb04ad if len(kw): raise TypeError("If sys is a StateSpace, \ _convertToTransferFunction cannot take keywords.") # Use Slycot to make the transformation # Make sure to convert system matrices to numpy arrays tfout = tb04ad(sys.states, sys.inputs, sys.outputs, array(sys.A), array(sys.B), array(sys.C), array(sys.D), tol1=0.0) # Preallocate outputs. num = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] den = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] for i in range(sys.outputs): for j in range(sys.inputs): num[i][j] = list(tfout[6][i, j, :]) # Each transfer function matrix row has a common denominator. den[i][j] = list(tfout[5][i, :]) # print num # print den 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") lti_sys = lti(sys.A, sys.B, sys.C, sys.D) num = squeeze(lti_sys.num) den = squeeze(lti_sys.den) print num print den return TransferFunction(num, den) elif isinstance(sys, (int, long, float, complex)): 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) else: raise TypeError("Can't convert given type to TransferFunction system.")