Example #1
0
    def subspace_identification(self):
        """
        Perform subspace identification based on the PO-MOESP method.
        The instrumental variable contains past outputs and past inputs.
        The implementation uses a QR-decomposition for numerical efficiency and is based on page 329 of [1].

        A key result of this function is the eigenvalue decomposition of the :math:`R_{32}` matrix
        ``self.R32_decomposition``, based on which the order of the system should be determined.

        [1] Verhaegen, Michel, and Vincent Verdult. *Filtering and system identification: a least squares approach.*
        Cambridge university press, 2007.
        """
        u_hankel = Utils.block_hankel_matrix(self.u_array, self.num_block_rows)
        y_hankel = Utils.block_hankel_matrix(self.y_array, self.num_block_rows)

        u_past, u_future = u_hankel[:, :-self.
                                    num_block_rows], u_hankel[:, self.
                                                              num_block_rows:]
        y_past, y_future = y_hankel[:, :-self.
                                    num_block_rows], y_hankel[:, self.
                                                              num_block_rows:]
        u_instrumental_y = np.concatenate([u_future, u_past, y_past, y_future])

        q, r = map(lambda matrix: matrix.T,
                   np.linalg.qr(u_instrumental_y.T, mode='reduced'))

        y_rows, u_rows = self.y_dim * self.num_block_rows, self.u_dim * self.num_block_rows
        self.R32 = r[-y_rows:, u_rows:-y_rows]
        self.R22 = r[u_rows:-y_rows, u_rows:-y_rows]
        self.R32_decomposition = Utils.eigenvalue_decomposition(self.R32)
Example #2
0
 def _get_observability_matrix_decomposition(self) -> Decomposition:
     """
     Calculate the eigenvalue decomposition of the estimate of the observability matrix as per N4SID.
     """
     u_hankel = Utils.block_hankel_matrix(self.u_array, self.num_block_rows)
     y_hankel = Utils.block_hankel_matrix(self.y_array, self.num_block_rows)
     u_and_y = np.concatenate([u_hankel, y_hankel])
     observability = self.R32 @ np.linalg.pinv(self.R22) @ u_and_y
     observability_decomposition = Utils.reduce_decomposition(
         Utils.eigenvalue_decomposition(observability), self.x_dim)
     return observability_decomposition
Example #3
0
 def test_block_hankel_matrix(self):
     matrix = np.array(range(15)).reshape((5, 3))
     hankel = Utils.block_hankel_matrix(matrix, 2)
     desired_result = np.array([
         [0., 3., 6., 9.],
         [1., 4., 7., 10.],
         [2., 5., 8., 11.],
         [3., 6., 9., 12.],
         [4., 7., 10., 13.],
         [5., 8., 11., 14.],
     ])
     self.assertTrue(np.all(np.isclose(desired_result, hankel)))