In the cell below, we obtain a signal of the system y(k)=0.1y(k−1)−0.5u(k−1)y(k−1)+0.1u(k−2). You can change it as you wish, or use your own data collected elsewhere. If you want to use your own data, it is better to use this software in the Matlab or Octave environment.
Fs = 100; % Sampling frequency of the data acquisition, in Hz.
u = randn(2000, 1);
y = zeros(size(u));
t = (1:length(y))/Fs;
for k = 5:length(y)
y(k) = 0.1*y(k-1) - 0.5*u(k-1)*y(k-1) + 0.1*u(k-2);
end
subplot(1,2,1);plot(t, u); title('input'); xlabel('t(s)')
subplot(1,2,2);plot(t, y); title('output'); xlabel('t(s)')
x=2+2
x = 4
Here we throw away the first 100 samples to avoid transient effects. This prepare could also involve some kind of normalization.
input = u(100:end);
output = y(100:end);
The model structure that we use to identify the nonlinear system is called as NARMAX and has the following structure:
y(k)=F[y(k−1),y(k−2),...,y(k−my),u(k−d),...,u(k−d−mu),ξ(k−1),...,ξ(k−mξ)]
where u is the input signal, y is the output signal and ξ is the residue signal. The format of the NARMAX model used is the polynomial form:
y(k)=β0+n∑i1=1βi1xi1(k)+n∑i1=1n∑i2=i1βi1i2xi1(k)xi2(k)+...+n∑i1=1...n∑il=il−1βi1i2...ilxi1xi2...xil+ξ(k) with
xm(k)={u(k−m)1⩽m⩽muy(k−(m−mu))mu+1⩽m⩽mu+myξ(k−(m−mu−my))mu+my+1⩽m⩽mu+my+mξ
where mu is the number of input past values to be considered in the model search, my is the number of output past values to be considered in the model search, mξ is the number of the residue past values to be considered in the model search and l is the maximal polynomial degree to be considered to form the combinations between the signals u, y e ξ.
Calling each combination xi1xi2...xil as pi, the Equation above can be rewritten as:
y(k)=M∑i=1βipi(k)+ξ(k)
where M is the number of combinations used in the model search. In matricial form, the equation above is:
Y=PB+ξ
where:
Y=[y(1),y(2),...,y(N)]TB=[β1,β2,...,βM]Tξ=[ξ(1),ξ(2),...,ξ(N)]TP=[p1,p2,...,pM]=[p1(1)p2(1)...pM(1)⋮⋮⋱⋮p1(k)p2(k)...pM(k)⋮⋮⋱⋮p1(N)p2(N)...pM(N)]
where T stand for the matrix or vector transponse.
For the identification of the system described at the beginning of this notebook we use the parameters in the cell bellow. As in this demonstration of the FROLS method we know our system, the used parameters are exactly what we need, but normally we do not know what parameters to use! Normally, to find these parameters, we need to try some values before finding the right ones. If you use mu,my and mξ values higher than necessary, the algorithm will work but the time of processing will be longer. If you use them lower than necessary, the algorithm will not find the correct model. Try to modify the parameters below to see what happens.
mu = 2;
my = 1;
me = max(mu,my);
degree = 3;
delay = 1;
dataLength = 500; % number of samplings to be used during the identification process. Normally a number between 400 and
% 600 is good. Do not use large numbers.
pho = 1e-2; % a lower value will give you more identified terms. A higher value will give you less.
delta = 1e-1;
numberOfCandidates = round(findPMatrixSize(mu - delay + 1, my, degree));
begin = randi([1 length(input) - dataLength - 1], 1);
u = input(begin+1:begin + dataLength);
y = output(begin+1:begin + dataLength);
[p, D]= buildPMatrix(u, y, degree, mu, my, delay);
y = y(max(mu,my) + 1:end);
The terms that the FROLS algorithm will use to try to find the model are:
disp(D)
Columns 1 through 6 '1' 'u(k-1)' 'u(k-2)' 'y(k-1)' 'u(k-1)u(k-1)' 'u(k-1)u(k-2)' Columns 7 through 10 'u(k-1)y(k-1)' 'u(k-2)u(k-2)' 'u(k-2)y(k-1)' 'y(k-1)y(k-1)' Columns 11 through 13 'u(k-1)u(k-1)u(k-1)' 'u(k-1)u(k-1)u(k-2)' 'u(k-1)u(k-1)y(k-1)' Columns 14 through 16 'u(k-1)u(k-2)u(k-2)' 'u(k-1)u(k-2)y(k-1)' 'u(k-1)y(k-1)y(k-1)' Columns 17 through 19 'u(k-2)u(k-2)u(k-2)' 'u(k-2)u(k-2)y(k-1)' 'u(k-2)y(k-1)y(k-1)' Column 20 'y(k-1)y(k-1)y(k-1)'
The first 15 lines of the P matrix are:
disp(p(1:15,:))
Columns 1 through 7 1.0000 0.4590 1.9524 0.0381 0.2107 0.8962 0.0175 1.0000 -0.3993 0.4590 0.1903 0.1595 -0.1833 -0.0760 1.0000 -0.2254 -0.3993 0.1029 0.0508 0.0900 -0.0232 1.0000 -0.2803 -0.2254 -0.0180 0.0786 0.0632 0.0051 1.0000 1.3067 -0.2803 -0.0269 1.7075 -0.3663 -0.0351 1.0000 -0.2844 1.3067 -0.0132 0.0809 -0.3716 0.0037 1.0000 -0.7917 -0.2844 0.1275 0.6268 0.2251 -0.1009 1.0000 0.2406 -0.7917 0.0348 0.0579 -0.1905 0.0084 1.0000 -0.0946 0.2406 -0.0799 0.0090 -0.0228 0.0076 1.0000 0.7932 -0.0946 0.0123 0.6292 -0.0751 0.0098 1.0000 0.9594 0.7932 -0.0131 0.9205 0.7611 -0.0126 1.0000 1.0871 0.9594 0.0843 1.1818 1.0430 0.0916 1.0000 0.6472 1.0871 0.0586 0.4188 0.7035 0.0379 1.0000 0.6326 0.6472 0.0956 0.4001 0.4094 0.0605 1.0000 1.9033 0.6326 0.0440 3.6225 1.2039 0.0838 Columns 8 through 14 3.8118 0.0744 0.0015 0.0967 0.4114 0.0080 1.7497 0.2107 0.0874 0.0362 -0.0637 0.0732 0.0303 -0.0841 0.1595 -0.0411 0.0106 -0.0114 -0.0203 0.0052 -0.0359 0.0508 0.0041 0.0003 -0.0220 -0.0177 -0.0014 -0.0142 0.0786 0.0075 0.0007 2.2313 -0.4786 -0.0459 0.1027 1.7075 -0.0172 0.0002 -0.0230 0.1057 -0.0011 -0.4856 0.0809 -0.0363 0.0163 -0.4962 -0.1782 0.0799 -0.0640 0.6268 -0.0275 0.0012 0.0139 -0.0458 0.0020 0.1508 0.0579 -0.0192 0.0064 -0.0008 0.0022 -0.0007 -0.0055 0.0090 -0.0012 0.0002 0.4991 -0.0596 0.0077 0.0071 0.6292 -0.0104 0.0002 0.8832 0.7302 -0.0121 0.6037 0.9205 0.0809 0.0071 1.2847 1.1339 0.0996 1.0007 1.1818 0.0637 0.0034 0.2711 0.4553 0.0245 0.7648 0.4188 0.0619 0.0091 0.2531 0.2589 0.0383 0.2649 0.4001 0.0279 0.0019 6.8945 2.2914 0.1595 0.7615 Columns 15 through 20 0.0341 0.0007 7.4420 0.1452 0.0028 0.0001 -0.0349 -0.0145 0.0967 0.0401 0.0166 0.0069 0.0093 -0.0024 -0.0637 0.0164 -0.0042 0.0011 -0.0011 -0.0001 -0.0114 -0.0009 -0.0001 -0.0000 0.0098 0.0009 -0.0220 -0.0021 -0.0002 -0.0000 0.0049 -0.0000 2.2313 -0.0225 0.0002 -0.0000 0.0287 -0.0129 -0.0230 0.0103 -0.0046 0.0021 -0.0066 0.0003 -0.4962 0.0218 -0.0010 0.0000 0.0018 -0.0006 0.0139 -0.0046 0.0015 -0.0005 -0.0009 0.0001 -0.0008 0.0001 -0.0000 0.0000 -0.0100 0.0002 0.4991 -0.0082 0.0001 -0.0000 0.0879 0.0077 0.8832 0.0776 0.0068 0.0006 0.0412 0.0022 1.2847 0.0692 0.0037 0.0002 0.0391 0.0058 0.2711 0.0400 0.0059 0.0009 0.0530 0.0037 0.2531 0.0176 0.0012 0.0001
global l q g err A ESR M0;
s = 1;
ESR = 1;
M = size(p, 3);
l = zeros(1, M);
function beta = mfrols(p, y, pho, s)
The global variables are used due to the lack of pointers in Matlab/Octave
global l;
global err ESR;
global A;
global q g M0;
beta = [];
M = size(p,2);
L = size(p,3);
gs=zeros(L,M);
ERR=zeros(L,M);
qs=zeros(size(p));
for j=1:L
sigma = y(:,j)'*y(:,j);
for m=1:M
if (max(m*ones(size(l))==l)==0)
The Gram-Schmidt method was implemented in a modified way, as shown in Rice, JR(1966)
For each m, we compute: qsm=pm−s−1∑r=1qTrqsmqTrqrqr
qs(:,m,j) = p(:,m,j);
for r=1:s-1
qs(:,m,j) = qs(:,m,j) - (squeeze(q(:,r,j))'*qs(:,m,j))/...
(squeeze(q(:,r,j))'*squeeze(q(:,r,j)))*squeeze(q(:,r,j));
end
We compute for each candidate that was not chosen:
gsm=yTqsmqsTmqsmERRm=gs2mqsTmqsyTy
gs(j,m) = (y(:,j)'*squeeze(qs(:,m,j)))/(squeeze(qs(:,m,j))'*squeeze(qs(:,m,j)));
ERR(j,m) = (gs(j,m)^2)*(squeeze(qs(:,m,j))'*squeeze(qs(:,m,j)))/sigma;
else
ERR(j,m)=0;
end
end
end
And here we chose to be part of the model the candidate term with the highest ERR.
ERR_m = mean(ERR, 1);
l(s) = find(ERR_m == max(ERR_m), 1);
err(s) = ERR_m(l(s));
for j=1:L
After the model term has been chosen we compute the values of the matrix A
ar,s=qTrpchosen termqTrqr,1⩽r⩽s−1as,s=1
for r = 1:s-1
A(r, s, j) = (q(:,r,j)'*p(:,l(s),j))/(q(:,r,j)'*q(:,r,j));
end
A(s, s, j) = 1;
q(:, s,j) = qs(:,l(s),j);
g(j,s) = gs(j,l(s));
end
After this process the matrix A will have the format: A=[1a12...a1s01...a2s⋮⋮⋱⋮0...1as−1,s00...1]
ESR = ESR - err(s);
The stop criterium is based on the ERR value of the chosen term. If it is lower than ρ, the process of search for terms stops.
if (err(s) >= pho && s < M)
s = s + 1;
clear qs
clear gs
Here is the recurrent call of the frols algorithm.
beta = mfrols(p, y, pho, s);
else
M0 = s;
s = s + 1;
for j=1:L
At the end, we compute the coefficients β of each term by doing:B=A−1g
beta(:,j) = A(:,:,j)\g(j,:)';
end
end
end
q = []; err=[]; A=[]; g=[];
beta = mfrols(p, y, pho, s);
la = l(1:M0)';
Da = D(la)';
[Dn, an, ln] = NARXNoiseModelIdentification(input, output, degree, mu, my, me, delay, dataLength, 1, pho, ...
beta, la);
[a, an, xi] = NARMAXCompleteIdentification(input, output, Da, Dn, dataLength, ...
1, delta, degree, degree);
for i = 1:length(Da)
disp({Da{i}, num2str(a(i))})
end
'u(k-2)' '0.1' 'u(k-1)y(k-1)' '-0.5' 'y(k-1)' '0.1'
Note that the found terms should be the same of the system difference equation on the top of this notebook.
If your identified system has terms with inputs and outputs, the GFRF will be non-null for degrees higher than the maximal polynomial degree. In this case, a good number is to add one to your maximal polynomial degree. If you have only inputs or outputs terms, the GFRFdegree will be the maximal polynomial degree.
GFRFdegree = 3;
Hn = computeSignalsGFRF(Da, Fs, a, GFRFdegree);
for j = 1:GFRFdegree
disp(['GFRF of order ' num2str(j) ': '])
pretty(Hn{j})
end
GFRF of order 1: / pi f1 i \ exp| - ------- | \ 25 / - --------------------------- / / pi f1 i \ \ | exp| - ------- | | | \ 50 / | 10 | ---------------- - 1 | \ 10 / GFRF of order 2: / pi f1 i \ / pi f1 i \ / pi f2 i \ exp| - ------- | exp| - ------- | exp| - ------- | \ 25 / \ 50 / \ 50 / - -------------------------------------------------------------- / / pi f1 i \ \ / / pi f1 i pi f2 i \ \ | exp| - ------- | | | exp| - ------- - ------- | | | \ 50 / | | \ 50 50 / | 20 | ---------------- - 1 | | -------------------------- - 1 | \ 10 / \ 10 / GFRF of order 3: / / pi f1 i \ / pi f3 i \ \ - | exp| - ------- | exp(-#2) exp(-#1) exp| - ------- | exp(- #2 - #1) | / \ \ 25 / \ 50 / / / | | / exp(-#2) \ / exp(- #2 - #1) \ | 40 | -------- - 1 | | -------------- - 1 | \ \ 10 / \ 10 / / / pi f3 i \ \ \ | exp| - #2 - #1 - ------- | | | | \ 50 / | | | -------------------------- - 1 | | \ 10 / / where pi f2 i #1 == ------- 50 pi f1 i #2 == ------- 50
Hfun = matlabFunction((abs(Hn{1})));
freq = [linspace(-50, 0, 50) linspace(0, 50, 50)];
plot(freq, Hfun(freq))
xlabel('f (Hz)'); ylabel('H_1')
x = 2+2
Undefined variable Hn.
Hfun = matlabFunction((abs(Hn{2})));
freq1 = [linspace(-50, 0, 20) linspace(0, 50, 20)];
freq2 = [linspace(-50, 0, 20) linspace(0, 50, 20)];
[F1,F2] = meshgrid(freq1,freq2);
surf(F1, F2, Hfun(F1,F2));
xlabel('f_1 (Hz)'); ylabel('f_2 (Hz)');
The frequency response of the output signal y of a system to a given input u is:
Y(jω)=N∑n=1Yn(jω)
where:
Yn(jω)=1/√n(2π)n−1∫ω=ω1+...+ωnHn(jω,...,jωn)n∏i=1U(jωi)dσωn
As an example of the use of NOFRF, below the expressions above will be used to predict what will be the output of the system to the input signal u(t)=cos(2π8t).
t = 0:1/Fs:10000/Fs-1/Fs;
u = cos(2*pi*8*t);
First, we compute the FFT of u(t).
fres = 0.1; % the frequency resolution of the NOFRF
fmin = 0; % lower frequency limit of the NOFRF
fmax = 50; % upper frequency limit of the NOFRF
U = computeSignalFFT(u', Fs, fres); f_u = -Fs/2:fres:Fs/2;
plot(f_u, abs(U));xlim([0 50]); xlabel('f(Hz)');ylabel('|U(f)|')
% Initialize variables for the NOFRF computation
fv = -Fs/2:fres:Fs/2;
f_out = fmin:fres:fmax;
f_inputMin = 4;
f_inputMax = 12;
NOFRF = zeros(size(f_out));
% NOFRF computing
for i = 1:3
if logical(Hn{i} ~= 0)
HnFunction = matlabFunction(Hn{i});
for j = 1:length(f_out)
if i == 1
validFrequencyIndices = abs(fv-f_out(j))<=1e-3 & f_out(j)>=f_inputMin(1) & f_out(j) <= f_inputMax(1);
if ~isempty(U(validFrequencyIndices))
NOFRF(j) = 2 * HnFunction(f_out(j)) * U(validFrequencyIndices);
end
else
NOFRF(j) = NOFRF(j) + 2 * computeDegreeNOFRF(HnFunction, U, Fs, i, f_out(j), fres, f_inputMin, f_inputMax);
end
end
end
end
plot(f_out, abs(NOFRF));xlim([-1 50])
y = zeros(size(u));
t = (1:length(y))/Fs;
for k = 5:length(y)
y(k) = 0.1*y(k-1) - 0.5*u(k-1)*y(k-1) + 0.1*u(k-2);
end
Y = computeSignalFFT(y', Fs, fres); f_y = -Fs/2:fres:Fs/2;
plot(f_y, 2*abs(Y));xlim([-1 50]); xlabel('f(Hz)');ylabel('|Y(f)|')