def dTFsensitivity(self): """Compute the transfer function sensitivity measure and matrix Returns - M: tf sensitivity measure - MX: tf sensitivity matrix """ return _w_norm_prod(dSS(self.AZ, self._M1, self.CZ, self._M2), dSS(self.AZ, self.BZ, self._N1, self._N2), self.dZ)
def to_dSS(self, form="ctrl"): """ Transform the transfer function into a state-space Parameters: - form: controllable canonical form ('ctrl') or observable canonical form ('obs') """ # TODO: code it without scipy from fixif.LTI import dSS if form == 'ctrl': A = mat(diagflat(ones((1, self.order - 1)), 1)) A[self.order - 1, :] = fliplr(-self.den[0, 1:]) B = mat(r_[zeros((self.order - 1, 1)), atleast_2d(1)]) C = mat( fliplr(self.num[0, 1:]) - fliplr(self.den[0, 1:]) * self.num[0, 0]) D = mat(atleast_2d(self.num[0, 0])) elif form == 'obs': # TODO: to it manually!! A, B, C, D = tf2ss(array(self.num)[0, :], array(self.den)[0, :]) else: raise ValueError( 'dTF.to_dSS: the form "%s" is invalid (must be "ctrl" or "obs")' % form) return dSS(A, B, C, D)
def _build_AZtoDZ(self): # compute AZ, BZ, CZ and DZ matrices AZ = self.K * self._invJ * self.M + self.P BZ = self.K * self._invJ * self.N + self.Q CZ = self.L * self._invJ * self.M + self.R DZ = self.L * self._invJ * self.N + self.S # and store them in a dSS object self._dSS = dSS(AZ, BZ, CZ, DZ)
def test_construction(): """ Test the constructor """ # test non-consistency size with pytest.raises(ValueError): dSS([[1, 2], [3, 4], [5, 6]], 1, 2, 3) with pytest.raises(ValueError): dSS([[1, 2], [3, 4]], 1, 2, 3) with pytest.raises(ValueError): dSS([[1, 2], [3, 4]], [[1], [2]], 2, 3) with pytest.raises(ValueError): dSS([[1, 2], [3, 4]], [[1], [2]], [[1, 2], [1, 2]], 3)
def __init__(self, num=None, den=None, A=None, B=None, C=None, D=None, tf=None, ss=None, stable=None, name='noname'): """ Create a Filter from numerator and denominator OR from A,B,C,D matrices Parameters ---------- num, den: numerator and denominator of the transfer function A,B,C,D: State-Space matrices tf: a dTF object ss: a dSS object """ self._dSS = None self._dTF = None self._name = name if A is not None and B is not None and C is not None and D is not None: self._dSS = dSS(A, B, C, D) elif num is not None and den is not None: self._dTF = dTF(num, den) elif tf is not None: self._dTF = tf elif ss is not None: self._dSS = ss else: raise ValueError( 'Filter: the values given to the Filter constructor are not correct' ) # is the filter stable? if stable is None: # TODO: compute the eigenvalues to know if it is stable or not self._stable = False else: self._stable = stable
def Hepsilon(self): """Hepsilon is the state-space system from the roundoff errors to the output""" if self._Hepsilon is None: self._Hepsilon = dSS(self.AZ, self._M1, self.CZ, self._M2) return self._Hepsilon
def Hu(self): """Hu system is the state-space system from the inputs to the intern variables t,x,y""" if self._Hu is None: self._Hu = dSS(self.AZ, self.BZ, self._N1, self._N2) return self._Hu
def WCPG_txy(S): N1 = np.bmat(np.r_[S.invJ * S.M, S.AZ, S.CZ]) N2 = np.bmat(np.r_[S.invJ * S.N, S.BZ, S.DZ]) SS = dSS(S.AZ, S.BZ, N1, N2) return SS.WCPG()
def makerhoDFII(filt, gamma=None, Delta=None, transposed=True, scaling=None, equiv_dSS=False): """ Factory function to make a rho Direct Form II Realisation - gamma and Delta are free parameters of the rho Direct Form II (Delta can be computed if None, see 'scaling' option, Gamma is set to 1 if None) Options: - transposed: (boolean, True as default) transpose (or not) the realization: rhoDirect Form II transposed (True) or rho Direct Form II (False) - scaling: tell how the Delta parameters should be chosen, WHEN the Deltas are not given (equal to None) - None: Deltas are all equal to 1 (no scaling) - 'l2': a l2-scaling is applied to deduce the Deltas - 'l2-relaxed': a l2-relaxed scaling is applied to deduce the Deltas - equiv_dSS: if True returns the equivalent State-Space (instead of the Direct Form II itself) Returns - a dictionary of necessary infos to build the Realization """ # see LI04b and Hila11b for reference n = filt.order if gamma is None: gamma = ones((1, n)) gamma = mat(gamma) # ===================================== # Step 1: build Valapha_bar, Vbeta_bar # by considering Delta_k = 1 for all k # ===================================== # Va and Vb Va = transpose(filt.dTF.den) Vb = transpose(filt.dTF.num) # Build Tbar Tbar = mat(zeros((n + 1, n + 1))) Tbar[n, n] = 1 for i in range(n - 1, -1, -1): Tbar[i, i:n + 1] = poly(gamma[0, i:n].A1) # Valpha_bar, Vbeta_bar Valpha_bar = transpose(inv(Tbar)) * Va Vbeta_bar = transpose(inv(Tbar)) * Vb # Equivalent state space (Abar, Bbar, Cbar, Dbar) A0 = diagflat(mat(ones((n - 1, 1))), 1) A0[:, 0] = -Valpha_bar[1:, 0] Abar = diagflat(gamma) + A0 Bbar = Vbeta_bar[1:, 0] - Vbeta_bar[0, 0] * Valpha_bar[1:, 0] Cbar = mat(zeros((1, n))) Cbar[0, 0] = 1 Dbar = Vbeta_bar[0, 0] # ============================================ # Step 2: Compute Delta according to scaling # (when Delta is not given) # ============================================ if Delta is None: # We need to compute the Deltas, according to the option 'scaling' if scaling is None: Delta = ones((1, n)) else: Wc = dSS(Abar, Bbar, Cbar, Dbar).Wc Delta = zeros((1, n)) if scaling == 'l2': # compute the Deltas that perform a l2-scaling (see Li04b) Delta[0, 0] = sqrt(Wc[0, 0]) for i in range(1, n): Delta[0, i] = sqrt(Wc[i, i] / Wc[i - 1, i - 1]) elif scaling == 'l2-relaxed': # compute the Deltas that perform a l2-scaling (see Hila09b) Delta[0, 0] = floor2(sqrt(Wc[0, 0])) for i in range(1, n): Delta[0, i] = floor2(sqrt(Wc[i, i] / Wc[i - 1, i - 1])) else: raise ValueError( "rhoDFII: the `scaling` parameter should be None, 'l2' or 'l2-relaxed'" ) # ============================================ # Step 3: Compute the coefficients (Valpha, Vbeta # ============================================ # compute Valpha and Vbeta # compute Tbar Tbar = mat(zeros((n + 1, n + 1))) Tbar[n, n] = 1 for i in range(n - 1, -1, -1): Tbar[i, i:n + 1] = poly(gamma[0, i:n].A1) / prod(Delta[0, i:n]) Ka = prod(Delta[0, :]) Valpha = transpose(inv(Ka * Tbar)) * Va Vbeta = transpose(inv(Ka * Tbar)) * Vb # ============================ # Step 4 : build SIF # ============================ if equiv_dSS: # Equivalent state space (A, B, C, D) A0 = diagflat(mat(ones((n - 1, 1))), 1) A0[:, 0] = -Valpha[1:, 0] Arho = diagflat(gamma) + A0 * diagflat(Delta) Brho = Vbeta[1:, 0] - Vbeta[0, 0] * Valpha[1:, 0] Crho = mat(zeros((1, n))) Crho[0, 0] = Delta[0, 0] Drho = mat(Vbeta[0, 0]) J = eye(0) K = zeros((n, 0)) L = zeros((1, 0)) M = zeros((0, n)) N = zeros((0, 1)) P = Arho Q = Brho R = Crho S = Drho # TODO: build dJtodS matrix, according to gammaExact and DeltaExact options else: if array_equal(Delta, ones((1, n))): # specific SIF when the Delta are all equal to 1 (the temporary variables are not necessary, since t_i = x_i * Delta_i) J = mat(1) K = -Valpha[1:n + 1, 0] L = mat(1) M = c_[atleast_2d(1), zeros((1, n - 1))] N = mat(Vbeta[0, 0]) P = mat(diagflat(Delta)) + mat(diagflat(ones((1, n - 1)), 1)) Q = Vbeta[1:n + 1, 0] R = zeros((1, n)) S = mat(0) else: J = eye(n) K = mat(diagflat(ones((1, n - 1)), 1)) K[:, 0] = -Valpha[1:n + 1, 0] L = c_[atleast_2d(1), zeros((1, n - 1))] M = mat(diagflat(Delta)) N = r_[atleast_2d(Vbeta[0, 0]), zeros((n - 1, 1))] P = mat(diagflat(gamma)) Q = Vbeta[1:n + 1, 0] R = zeros((1, n)) S = mat(0) if not transposed: # matrices J, K, L, M, N, P, Q, R and S were for transposed form K, M = M.transpose(), K.transpose() P = P.transpose() R, Q = Q.transpose(), R.transpose() L, N = N.transpose(), L.transpose() J = J.transpose() S = S.transpose() # no need to really do this, since S is a scalar # TODO: store gamma !! return {"JtoS": (J, K, L, M, N, P, Q, R, S)}
def to_dSS(self): from fixif.LTI import dSS return dSS(mpf_to_numpy(self._A), mpf_to_numpy(self._B), mpf_to_numpy(self._C), mpf_to_numpy(self._D))