def stationary_values(self): """ Computes the limit of :math:`\Sigma_t` as t goes to infinity by solving the associated Riccati equation. Computation is via the doubling algorithm (see the documentation in `matrix_eqn.solve_discrete_riccati`). Returns ------- Sigma_infinity : array_like or scalar(float) The infinite limit of :math:`\Sigma_t` K_infinity : array_like or scalar(float) The stationary Kalman gain. """ # === simplify notation === # A, C, G, H = self.ss.A, self.ss.C, self.ss.G, self.ss.H Q, R = np.dot(C, C.T), np.dot(H, H.T) # === solve Riccati equation, obtain Kalman gain === # Sigma_infinity = solve_discrete_riccati(A.T, G.T, Q, R) temp1 = dot(dot(A, Sigma_infinity), G.T) temp2 = inv(dot(G, dot(Sigma_infinity, G.T)) + R) K_infinity = dot(temp1, temp2) # == record as attributes and return == # self.Sigma_infinity, self.K_infinity = Sigma_infinity, K_infinity return Sigma_infinity, K_infinity
def stationary_values(self): """ Computes the limit of Sigma_t as t goes to infinity by solving the associated Riccati equation. Computation is via the doubling algorithm (see the documentation in `matrix_eqn.solve_discrete_riccati`). Returns ------- Sigma_infinity : array_like or scalar(float) The infinite limit of Sigma_t K_infinity : array_like or scalar(float) The stationary Kalman gain. """ # === simplify notation === # A, C, G, H = self.ss.A, self.ss.C, self.ss.G, self.ss.H Q, R = np.dot(C, C.T), np.dot(H, H.T) # === solve Riccati equation, obtain Kalman gain === # Sigma_infinity = solve_discrete_riccati(A.T, G.T, Q, R) temp1 = dot(dot(A, Sigma_infinity), G.T) temp2 = inv(dot(G, dot(Sigma_infinity, G.T)) + R) K_infinity = dot(temp1, temp2) # == record as attributes and return == # self.Sigma_infinity, self.K_infinity = Sigma_infinity, K_infinity return Sigma_infinity, K_infinity
def dare_test_tjm_1(): A = [[0.0, 0.1, 0.0], [0.0, 0.0, 0.1], [0.0, 0.0, 0.0]] B = [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]] Q = [[10**5, 0.0, 0.0], [0.0, 10**3, 0.0], [0.0, 0.0, -10.0]] R = [[0.0, 0.0], [0.0, 1.0]] X = solve_discrete_riccati(A, B, Q, R) Y = np.diag((1e5, 1e3, 0.0)) assert_allclose(X, Y, atol=1e-07)
def dare_test_tjm_2(): A = [[0, -1], [0, 2]] B = [[1, 0], [1, 1]] Q = [[1, 0], [0, 0]] R = [[4, 2], [2, 1]] X = solve_discrete_riccati(A, B, Q, R) Y = np.zeros((2, 2)) Y[0, 0] = 1 assert_allclose(X, Y, atol=1e-07)
def dare_test_tjm_3(): r = 0.5 I = np.identity(2) A = [[2 + r**2, 0], [0, 0]] A = np.array(A) B = I R = [[1, r], [r, r * r]] Q = I - np.dot(A.T, A) + np.dot(A.T, np.linalg.solve(R + I, A)) X = solve_discrete_riccati(A, B, Q, R) Y = np.identity(2) assert_allclose(X, Y, atol=1e-07)
def dare_test_tjm_3(): r = 0.5 I = np.identity(2) A = [[2 + r**2, 0], [0, 0]] A = np.array(A) B = I R = [[1, r], [r, r*r]] Q = I - np.dot(A.T, A) + np.dot(A.T, np.linalg.solve(R + I, A)) X = solve_discrete_riccati(A, B, Q, R) Y = np.identity(2) assert_allclose(X, Y, atol=1e-07)
def stationary_values(self, method='doubling'): """ Computes the limit of :math:`\Sigma_t` as t goes to infinity by solving the associated Riccati equation. The outputs are stored in the attributes `K_infinity` and `Sigma_infinity`. Computation is via the doubling algorithm (default) or a QZ decomposition method (see the documentation in `matrix_eqn.solve_discrete_riccati`). Parameters ---------- method : str, optional(default="doubling") Solution method used in solving the associated Riccati equation, str in {'doubling', 'qz'}. Returns ------- Sigma_infinity : array_like or scalar(float) The infinite limit of :math:`\Sigma_t` K_infinity : array_like or scalar(float) The stationary Kalman gain. """ # === simplify notation === # A, C, G, H = self.ss.A, self.ss.C, self.ss.G, self.ss.H Q, R = np.dot(C, C.T), np.dot(H, H.T) # === solve Riccati equation, obtain Kalman gain === # Sigma_infinity = solve_discrete_riccati(A.T, G.T, Q, R, method=method) temp1 = np.dot(np.dot(A, Sigma_infinity), G.T) temp2 = inv(np.dot(G, np.dot(Sigma_infinity, G.T)) + R) K_infinity = np.dot(temp1, temp2) # == record as attributes and return == # self._Sigma_infinity, self._K_infinity = Sigma_infinity, K_infinity return Sigma_infinity, K_infinity
def stationary_values(self, method='doubling'): """ Computes the limit of :math:`\Sigma_t` as t goes to infinity by solving the associated Riccati equation. The outputs are stored in the attributes `K_infinity` and `Sigma_infinity`. Computation is via the doubling algorithm (default) or a QZ decomposition method (see the documentation in `matrix_eqn.solve_discrete_riccati`). Parameters ---------- method : str, optional(default="doubling") Solution method used in solving the associated Riccati equation, str in {'doubling', 'qz'}. Returns ------- Sigma_infinity : array_like or scalar(float) The infinite limit of :math:`\Sigma_t` K_infinity : array_like or scalar(float) The stationary Kalman gain. """ # === simplify notation === # A, C, G, H = self.ss.A, self.ss.C, self.ss.G, self.ss.H Q, R = np.dot(C, C.T), np.dot(H, H.T) # === solve Riccati equation, obtain Kalman gain === # Sigma_infinity = solve_discrete_riccati(A.T, G.T, Q, R, method=method) temp1 = dot(dot(A, Sigma_infinity), G.T) temp2 = inv(dot(G, dot(Sigma_infinity, G.T)) + R) K_infinity = dot(temp1, temp2) # == record as attributes and return == # self._Sigma_infinity, self._K_infinity = Sigma_infinity, K_infinity return Sigma_infinity, K_infinity
def dare_golden_num_2d(method): A, B, R, Q = np.eye(2), np.eye(2), np.eye(2), np.eye(2) gold_diag = np.eye(2) * (1 + np.sqrt(5)) / 2. val = solve_discrete_riccati(A, B, R, Q, method=method) assert_allclose(val, gold_diag)
def dare_golden_num_float(method): val = solve_discrete_riccati(1.0, 1.0, 1.0, 1.0, method=method) gold_ratio = (1 + np.sqrt(5)) / 2. assert_allclose(val, gold_ratio)
def dare_test_golden_num_2d(): A, B, R, Q = np.eye(2), np.eye(2), np.eye(2), np.eye(2) gold_diag = np.eye(2) * (1 + np.sqrt(5)) / 2. val = solve_discrete_riccati(A, B, R, Q) assert_allclose(val, gold_diag)
def dare_test_golden_num_float(): val = solve_discrete_riccati(1.0, 1.0, 1.0, 1.0) gold_ratio = (1 + np.sqrt(5)) / 2. assert_allclose(val, gold_ratio)