def test_balreal(): isys = Lowpass(0.05) noise = 0.5 * Lowpass(0.01) + 0.5 * Alpha(0.005) p = 0.8 sys = p * isys + (1 - p) * noise T, Tinv, S = balanced_transformation(sys) assert np.allclose(inv(T), Tinv) assert np.allclose(S, hsvd(sys)) balsys = sys.transform(T, Tinv) assert balsys == sys assert np.all(S >= 0) assert np.all(S[0] > 0.3) assert np.all(S[1:] < 0.05) assert np.allclose(sorted(S, reverse=True), S) P = control_gram(balsys) Q = observe_gram(balsys) diag = np.diag_indices(len(P)) offdiag = np.ones_like(P, dtype=bool) offdiag[diag] = False offdiag = np.where(offdiag) assert np.allclose(P[diag], S) assert np.allclose(P[offdiag], 0) assert np.allclose(Q[diag], S) assert np.allclose(Q[offdiag], 0)
def balreal(sys): """Computes the balanced realization of sys and returns its eigenvalues. References: [1] http://www.mathworks.com/help/control/ref/balreal.html [2] Laub, A.J., M.T. Heath, C.C. Paige, and R.C. Ward, "Computation of System Balancing Transformations and Other Applications of Simultaneous Diagonalization Algorithms," *IEEE Trans. Automatic Control*, AC-32 (1987), pp. 115-122. """ sys = LinearSystem(sys) # cast first to memoize sys2ss if not sys.analog: raise NotImplementedError("balanced digital filters not supported") R = control_gram(sys) O = observe_gram(sys) LR = cholesky(R, lower=True) LO = cholesky(O, lower=True) U, S, V = svd(np.dot(LO.T, LR)) T = np.dot(LR, V.T) * S ** (-1. / 2) Tinv = (S ** (-1. / 2))[:, None] * np.dot(U.T, LO.T) return similarity_transform(sys, T, Tinv), S
def test_grams(): sys = 0.6*Alpha(0.01) + 0.4*Lowpass(0.05) A, B, C, D = sys2ss(sys) P = control_gram(sys) assert np.allclose(np.dot(A, P) + np.dot(P, A.T), -np.dot(B, B.T)) assert np.linalg.matrix_rank(P) == len(P) # controllable Q = observe_gram(sys) assert np.allclose(np.dot(A.T, Q) + np.dot(Q, A), -np.dot(C.T, C)) assert np.linalg.matrix_rank(Q) == len(Q) # observable
def test_grams(): sys = 0.6 * Alpha(0.01) + 0.4 * Lowpass(0.05) A, B, C, D = sys2ss(sys) P = control_gram(sys) assert np.allclose(np.dot(A, P) + np.dot(P, A.T), -np.dot(B, B.T)) assert matrix_rank(P) == len(P) # controllable Q = observe_gram(sys) assert np.allclose(np.dot(A.T, Q) + np.dot(Q, A), -np.dot(C.T, C)) assert matrix_rank(Q) == len(Q) # observable
def hankel(sys): """Compute Hankel singular values of a linear system. References: [1] Glover, Keith, and Jonathan R. Partington. "Bounds on the achievable accuracy in model reduction." Modelling, robustness and sensitivity reduction in control systems. Springer Berlin Heidelberg, 1987. 95-118. """ sys = LinearSystem(sys) R, O = control_gram(sys), observe_gram(sys) # sort needed to be consistent across different versions return np.sort(np.sqrt(abs(eig(np.dot(O, R))[0])))[::-1]