# 一、N4SID 算法概述
N4SID (Subspace Identification for State-Space Models) 方法是系统辨识领域中一种常用的子空间方法,用于从输入输出数据中辨识线性时不变系统的状态空间模型。该方法的主要目标是通过测量数据来确定系统的状态、动态矩阵和输出矩阵,从而获得系统的数学模型。这种方法广泛应用于自动控制、信号处理、通讯等领域,尤其适用于多输入多输出 (MIMO) 系统。N4SID 方法通过子空间技术,能够有效地处理高阶、多变量系统的辨识问题。它无需假设特定的系统结构,直接从数据中提取状态信息,避免了许多传统方法中的参数估计困难和计算复杂度问题。
# 二、N4SID 算法主要流程
# 2.1 数据预处理
考虑如下的线性时不变离散状态空间方程模型:
其中, 和 分别是系统在 时刻的状态向量、输入向量和输出向量。
对 的所有维度添加高斯白噪声,并采集 个时刻的 和。(注:论文《N4SID: Subspace Algorithms for the Identi cation of Combined Deterministic-Stochastic Systems》的 Section 6.1 中提到了当采样时间无限,或确定性输入 是白色噪声,或系统是纯确定性系统时,N4SID 的估计是无偏估计)
# 2.2 构造 Hankel 矩阵
根据 2.1 中采集的数据 和, ,设计 Hankel 矩阵的行数,则整体 Hankel 矩阵的列数为。将整体的 Hankel 矩阵按照行数对半拆分,可以获得 Hankel 矩阵,, 和,分别如下所示:
过去输入 / 输出 Hankel 矩阵
未来输入 / 输出 Hankel 矩阵
# 2.3 正交三角分解(QR)
定义,考虑如下的下三角正交 LQ 分解:
式中,、 为下三角矩阵,,、 正交。从上式可以得出:
# 2.4 奇异值分解(SVD)
原始系统的 Toeplitz 矩阵为:
扩展可观性矩阵为:
过去状态序列为:
未来状态序列为:
根据 2.2 节和如上的定义,可以得到:
对比上式和 2.3 节中最后一个式子,可以得到:
对 进行 SVD 分解,可以得到:
# 2.5 (方法 1)估计状态序列
从 2.4 节中的 SVD 分解结果得到如下关系:
一般情况下,可以取。根据上式可以估计出状态序列向量:
定义 维向量:
# 2.6 (方法 1)最小二乘法计算系统参数
根据 2.5 节估计的状态序列向量,可以构造如下的关系:
这是一个系统的线性矩阵方程,可以使用最小二乘法估计出系统的矩阵参数
# 2.5 (方法 2)直接使用 SVD 的结果计算系统参数矩阵
由于
因此可以从计算出的 中提取矩阵。矩阵 可以通过下式进行计算,其中上标 在矩阵不为方阵时可采用伪逆的计算方式:
同理,由于
因此可以从计算出的 中提取矩阵,矩阵 可以通过下式进行计算,其中上标 在矩阵不为方阵时可采用伪逆的计算方式:
# 三、参考 matlab 程序
% -------------------------------------------------------- | |
% Author: Alexander Robles | |
% Feec-UNICAMP | |
% --------------------------------------------------------- | |
clear all;clc; | |
run('systemdata.m') | |
% Script for comparing MOESP and N4SID outputs | |
clc; | |
% Inputs of functions N, R, k | |
% Form Hankel matrices U,Y from system data (u,y) see blkhank.m | |
% R=input('Block_MOESP rows: '); | |
% k=input('Block_N4SID rows: '); | |
R=20; | |
k=20; | |
% call functions | |
[A1,B1,C1,D1,n1]=moespar(u,y,R); | |
[A2,B2,C2,D2,n2] = n4sidkatamodar(u,y,k); | |
[A3,B3,C3,D3,n3] = n4sid_self(u,y,k); | |
%Check Markov parameters (impulse responseof of MIMO system): | |
% Dr, Cr*Br, Cr*Ar*Br, Cr*Ar^2*Br ... | |
% D1, C1*B1, C1*A1*B1, C1*A1^2*B1 ... | |
% Graphics of system outputs and model outputs (estimate outputs) | |
run('modeloutputs.m') |
% ------------------------------------------------------- | |
% Generate system data (inputs and outputs) | |
% -------------------------------------------------------- | |
% Author: Alexander Robles | |
% FEEC-UNICAMP | |
% --------------------------------------------------------- | |
clear all | |
clc | |
% The state space system equations: | |
% x_k+1 = A x_k + B u_k | |
% y_k = C x_k + D u_k | |
Ar=[0.2128 0.1360 0.1979 -0.0836; | |
0.1808 0.4420 -0.3279 0.2344; | |
-0.5182 0.1728 -0.5448 -0.3083; | |
0.2252 -0.0541 -0.4679 0.8290]; | |
Br=[-0.0101 0.0317 -0.9347; | |
-0.0600 0.5621 0.1657; | |
-0.3310 -0.3712 -0.5846; | |
-0.2655 0.4255 0.2204]; | |
Cr=[0.6557 -0.2502 -0.5188 -0.1229; | |
0.6532 -0.1583 -0.0550 -0.2497]; | |
Dr=[-0.4326 0.1253 -1.1465 | |
-1.6656 0.2877 1.1909]; | |
%-------------- | |
% N=input('Size of data N:'); | |
N=500; | |
tt = 0:1:(N-1); | |
% -------------Input, u (white noise), is persistently exciting -------------- | |
u1 = randn(1,N); | |
u2 = randn(1,N); | |
u3 = randn(1,N); | |
u = [u1; u2; u3]; | |
%-------------Desing state-space model and outputs------ | |
X0=zeros(4,1); % first state | |
%%%----- | |
x(:,1) = X0; | |
xc(:,1) = x(:,1); | |
yc(:,1) = Cr * xc(:,1) + Dr*u(:,1); | |
for i = 1:length(tt) | |
xc(:,i+1) = Ar * xc(:,i) + Br* u(:,i); | |
yc(:,i) = Cr * xc(:,i) + Dr*u(:,i); | |
y = yc; | |
end | |
%-------------Plot inputs------------------------- | |
% figure (1) | |
% plot(tt,u1,'r',tt,u2,'c',tt,u3,'k'); | |
% title('Inputs'); | |
% legend('u1', 'u2', 'u3'); | |
%-------------Plot outputs------------------------- | |
% figure (2) | |
% plot(tt,y(1,:),'g',tt,yc(1,:),'*b'); | |
% title('Outputs'); | |
% legend('y1', 'y1c'); | |
% | |
% figure (3) | |
% plot(tt,y(2,:),'g',tt,yc(2,:),'*b'); | |
% title('Outputs'); | |
% legend('y2', 'y2c'); |
% MOESP Function | |
% m = dim(u), p = dim(y), n = dim(x); R = Numero de filas de blocos | |
% U = km x N Matriz de Entradas | |
% Y = kp x N Matriz de Saidas | |
% Number of columns depends number of Hankel blocks R--- N=ndat-R+1 | |
% If R ups >>j will decrease !DO NOT FORGET! 07/11/16 | |
function [A,B,C,D,n] = moespar(u,y,R) | |
%Number of inputs and outputs: | |
[m,nu] = size(u); | |
if nu < m;u = u';[m,nu] = size(u);end | |
[p,ny] = size(y); | |
if ny < p;y = y';[p,ny] = size(y);end | |
Ncol=ny-R+1;% Calculate number of COLUMNS BLOCK HANKEL | |
%Make BLOCK HANKEL INPUTS U-OUTPUTS Y | |
U= blkhank(u,R,Ncol); | |
Y= blkhank(y,R,Ncol); | |
km = size(U,1); kp = size(Y,1); % Rows of U and Y | |
L = triu(qr([U;Y]'))'; % LQ decomposition %Eq. 3.45 qr: Orthogonal-triangular decomposition. | |
L11 = L(1:km,1:km); | |
L21 = L(km+1:km+kp,1:km); | |
L22 = L(km+1:km+kp,km+1:km+kp); | |
[UU,SS,VV] = svd(L22); % Eq. 3.48 Singular Value Descomposition | |
s1 = diag(SS); | |
n=find(cumsum(s1)>0.8*sum(s1),1); | |
%n=4; | |
U1 = UU(:,1:n); % n is known, as you can see last equation | |
Ok = U1*sqrtm(SS(1:n,1:n)); % SQRTM Matrix square root. %Eq. 3.49 | |
% Matrices A and C | |
C = Ok(1:p,1:n); % Eq. (6.41) | |
A = pinv(Ok(1:p*(R-1),1:n))*Ok(p+1:p*R,1:n); % Eq.3.51 | |
% Matrices B and D | |
U2 = UU(:,n+1:size(UU',1)); | |
Z = U2'*L21/L11; % Eq. 3.53 | |
XX = []; RR = []; | |
for j = 1:R | |
XX = [XX; Z(:,m*(j-1)+1:m*j)]; | |
Okj = Ok(1:p*(R-j),:); | |
Rj = [zeros(p*(j-1),p) zeros(p*(j-1),n); | |
eye(p) zeros(p,n); zeros(p*(R-j),p) Okj]; | |
RR = [RR; U2'*Rj]; | |
end | |
DB = pinv(RR)*XX; % Eq. 3.57 | |
D = DB(1:p,:); | |
B = DB(p+1:size(DB,1),:); |
% Algoritmo do metodo N4SID modificado, com dados de entrada u, | |
% saida y, e k a ordem dos blocos de Hankel | |
function [A,B,C,D,n] = n4sidkatamodar(u,y,k) | |
[l,ny] = size(y);if (ny < l);y = y';[l,ny] = size(y);end | |
[m,nu] = size(u);if (nu < m);u = u';[m,nu] = size(u);end | |
% Determinar o numero de columns para as matrizes de Hankel | |
N = ny-2*k+1; | |
%Constroir as matrizes de dados, bloco de Hankel | |
U = blkhank(u,2*k,N); | |
Y = blkhank(y,2*k,N); | |
Up=U(1:k*m,:); | |
Uf=U(k*m+1:2*k*m,:); | |
Yp=Y(1:k*l,:); | |
Yf=Y(k*l+1:2*k*l,:); | |
km = size(Up,1); | |
kl = size(Yp,1); | |
Wp = [Up;Yp]; | |
% *********** ALGORITMO *********** | |
%Passo 1 | |
%decomposicao LQ | |
[Q,L] = qr([Uf;Up;Yp;Yf]',0); | |
Q=Q'; L=L'; | |
L11 = L(1:km,1:km); | |
L21 = L(km+1:2*km,1:km); | |
L22 = L(km+1:2*km,km+1:2*km); | |
L31 = L(2*km+1:2*km+kl,1:km); | |
L32 = L(2*km+1:2*km+kl,km+1:2*km); | |
L33 = L(2*km+1:2*km+kl,2*km+1:2*km+kl); | |
L41 = L(2*km+kl+1:2*km+2*kl,1:km); | |
L42 = L(2*km+kl+1:2*km+2*kl,km+1:2*km); | |
L43 = L(2*km+kl+1:2*km+2*kl,2*km+1:2*km+kl); | |
L44 = L(2*km+kl+1:2*km+2*kl,2*km+kl+1:2*km+2*kl); | |
R11 = L11; | |
R21 = [L21;L31]; | |
R22 = [L22 zeros(km,kl); L32 L33]; | |
R31 = L41; | |
R32 = [L42 L43]; | |
xi = R32*pinv(R22)*Wp; | |
%Passo 2 | |
[UU,SS,VV] = svd(xi); | |
ss = diag(SS); | |
n=find(cumsum(ss)>0.85*sum(ss),1); | |
%n=4; | |
% hold off | |
% figure(1) | |
% title('Valores singulares'); | |
% xlabel('Ordem'); | |
% plot(ss) | |
% pause; | |
% figure(2) | |
% title('Valores singulares'); | |
% xlabel('Ordem'); | |
% bar(ss) | |
% n = input(' Ordem do sistema ? '); | |
% while isempty(n) | |
% n = input(' Ordem do sistema ? '); | |
% end | |
U1 = UU(:,1:n); | |
S1 = SS(1:n,1:n); | |
V1 = VV(:,1:n); | |
%Matrizes A e C | |
Ok = U1*sqrtm(S1); | |
C = Ok(1:l,1:n); | |
A = pinv(Ok(1:l*(k-1),1:n))*Ok(l+1:l*k,1:n); | |
%Passo 3 | |
%Matrizes B e D | |
TOEP = (R31 - R32*pinv(R22)*R21)*pinv(R11); | |
G = TOEP(:,1:m); | |
G0 = G(1:l,:); | |
G1 = G(l+1:2*l,:); | |
G2 = G(2*l+1:3*l,:); | |
G3 = G(3*l+1:4*l,:); | |
G4 = G(4*l+1:5*l,:); | |
D = G0; | |
Hk = [G1 G2;G2 G3;G3 G4]; | |
Ok1 = Ok(1:3*l,:); | |
Ck = pinv(Ok1)*Hk; | |
B = Ck(:,1:m); | |
%% 自己尝试估计状态序列向量 | |
X_f_estimate = sqrtm(S1) * V1'; | |
X_f_fzy = X_f_estimate(:,2:end); | |
X_p_fzy = X_f_estimate(:,1:end-1); | |
u_fzy = Uf(1:m,1:end-1); | |
y_fzy = Yf(1:l,1:end-1); | |
input_fzy = [X_p_fzy;u_fzy]; | |
output_fzy = [X_f_fzy;y_fzy]; | |
predict_sys = output_fzy*input_fzy'/(input_fzy*input_fzy'); | |
predict_A = predict_sys(1:n,1:n); | |
predict_B = predict_sys(1:n,n+1:end); | |
predict_C = predict_sys(n+1:end,1:n); | |
predict_D = predict_sys(n+1:end,n+1:end); | |
% disp(norm(predict_A-A)) | |
% disp(norm(predict_B-B)) | |
% disp(norm(predict_C-C)) | |
% disp(norm(predict_D-D)) |
% | |
% H = blkhank(y,i,j) | |
% | |
% Description: | |
% Make a block Hankel matrix with the data y | |
% containing i block-rows and j columns | |
% | |
function H = blkhank(y,i,j) % i=k=R is an abritary positive | |
% Make a (block)-row vector out of y | |
[l,nd] = size(y); | |
if nd < l;y = y';[l,nd] = size(y);end | |
% Check dimensions | |
if i < 0;error('blkHank: i should be positive');end | |
if j < 0;error('blkHank: j should be positive');end | |
if j > nd-i+1;error('blkHank: j too big');end % j is less or iqual nd-i+1 | |
% Make a block-Hankel matrix | |
H=zeros(l*i,j); | |
for k=1:i | |
H((k-1)*l+1:k*l,:)=y(:,k:k+j-1); | |
end |
%Benchmarck : | |
% Consider a multivariable fourth order system a,b,c,d | |
% with 3 inputs and 2 outputs: | |
clc; | |
u1 = u; | |
% The state space system equations: | |
% x_{k+1) = A x_k + B u_k | |
% y_k = C x_k + D u_k | |
% Model output: | |
ym = dlsim(A1,B1,C1,D1,u1)'; % MOESP output | |
yn = dlsim(A2,B2,C2,D2,u1)'; % N4SID output | |
y_self = dlsim(A3,B3,C3,D3,u1)'; % N4SID output | |
%-------------Plot system outputs and model outputs------------------------- | |
figure (1) | |
hold off;subplot;clf; | |
subplot(211);plot(tt,y(1,:),'r',tt,ym(1,:),'*b'); | |
title('First ouput'); | |
legend('System output', 'MOESP output'); | |
subplot(212);plot(tt,y(2,:),'r',tt,ym(2,:),'*b'); | |
legend('System output', 'MOESP output'); | |
title('Second output'); | |
figure (2) | |
hold off;subplot;clf; | |
subplot(211);plot(tt,y(1,:),'r',tt,yn(1,:),'*b'); | |
title('First ouput'); | |
legend('System output', 'M4SID output'); | |
subplot(212);plot(tt,y(2,:),'r',tt,yn(2,:),'*b'); | |
legend('System output', 'N4SID output'); | |
title('Second output'); | |
figure (3) | |
hold off;subplot;clf; | |
subplot(211);plot(tt,y(1,:),'r',tt,y_self(1,:),'*b'); | |
title('First ouput'); | |
legend('System output', 'M4SID output'); | |
subplot(212);plot(tt,y(2,:),'r',tt,y_self(2,:),'*b'); | |
legend('System output', 'N4SID output'); | |
title('Second output'); | |
%----------------Mean square error-------------------------------------------- | |
errMOESP = (sum((y(1,:)-ym(1,:)).^2)+sum((y(2,:)-ym(2,:)).^2))/N | |
errN4SID = (sum((y(1,:)-yn(1,:)).^2)+sum((y(2,:)-yn(2,:)).^2))/N | |
errN4SID_self = (sum((y(1,:)-y_self(1,:)).^2)+sum((y(2,:)-y_self(2,:)).^2))/N |