Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
%% convert hamlyn heart video to image sequence
% workingDir = tempname;
% mkdir(workingDir)
% mkdir(workingDir,'images')
%
% shuttleVideo = VideoReader('~/Downloads/hamlyn_heart.avi');
%
% ii = 1;
% while hasFrame(shuttleVideo)
% img = readFrame(shuttleVideo);
% filename = [sprintf('%03d',ii) '.jpg'];
% fullname = fullfile(workingDir,'images',filename);
% imwrite(img,fullname) % Write out to a JPEG file (img1.jpg, img2.jpg, etc.)
% ii = ii+1;
% end
%
% imageNames = dir(fullfile(workingDir,'images','*.jpg'));
% imageNames = {imageNames.name}';
%
%
% for ii = 1:length(imageNames)
% img = imread(fullfile(workingDir,'images',imageNames{ii}));
% grayImages(:,:,ii) = rgb2gray(img);
% end
%% Try DMD on it
clear variables
load data/HamlynHeartImages.mat;
disp('Data preparation...')
image_start = 1;% frame number to start from
num_images = 100;
allImages = [];
% for k = 1:size(grayImages,3)
for k = image_start:image_start+num_images
image_k = grayImages(:,:,k);
% allImages(:,k) = double(image_k(:));
allImages = [allImages, double(image_k(:))];
end
XallPrescaled = [allImages(:,2:end);
allImages(:,1:end-1)];
% XallPrescaled = allImages;
% remove constant rows which make XallPrescaled lose rank
[XallPrescaledProcessed,ProcessSettings] = removeconstantrows(XallPrescaled);
XallPrescaledProcessed = XallPrescaledProcessed';
disp('DMD Regression...')
%% kernel dmd
disp('Scaling data...')
[Xall,scaleFactor,scaleOffset] = ScaleData(XallPrescaledProcessed,'zscore'); % zscore may cause problems with body_length, which is constant
% Xall = XallPrescaledProcessed;
% scaleFactor = 1;
% scaleOffset = 0;
X = Xall(1:end-1,:);
X2 = Xall(2:end,:);
%% Kernel DMD
disp('Doing Kernel DMD...')
% kernel function
% inputs: x1, x2 are vectors of the same size.
% kernel = @(x1,x2) (1 + dot(x1,x2))^10; % polynomial kernel, doesnt work that well. often fails during reconstruction
sigma2 = 1e6; % 36 works well for noise = 1e-6. but so does 169. Noise dependent?
kernel = @(x1,x2) exp(-norm(x1-x2)^2/sigma2); % Gausssian kernel
% for j = 1:size(X,1)
% disp(j)
% for k = 1:size(X2,1)
% Ahat(j,k) = kernel(X(k,:),X2(j,:)); % Y'Y2 is Ahat in Williams et al.
% Ghat(j,k) = kernel(X(k,:),X(j,:)); % Y*Y is the Gramian Ghat in Williams et al.
% end
% end
Ahat = GaussianKernel(X,X2,sqrt(sigma2));
Ghat = GaussianKernel(X,X,sqrt(sigma2));
%%
% TODO: truncate to get low-order model.
% use Ghat to compute Sigma (called 'S') and V
% [Qfull,S2full] = eig(Ghat); % since it's true that Ghat*Q = Q*Sigma^2
tic;
[Qfull, S2full] = eigs(Ghat,size(Ghat,1),'largestabs','Tolerance',1e-19); % use increased tolerance with GaussianKernel
toc;
% S2full = flipud(fliplr(S2full)); % make largest singular values first instead of largest singular values last
% Qfull = fliplr(Qfull);
Sfull = sqrtm(S2full);
% truncate
r = size(Ghat,1)-1; % number of dimensions to keep
% r = floor(size(Ghat,1)/2);
Q = Qfull(:,1:r);
S = Sfull(1:r,1:r);
figure(2);
clf;
semilogy(diag(Sfull),'o');
hold on
semilogy(diag(S),'.');
% Sinv = diag(ones(size(S,1),1)./diag(S)); % better numerical stability?
% Khat = (Sinv*Q')*Ahat*(Q*Sinv);
Khat = (S\Q')*(Ahat)*(Q/S); % Khat, an approximation of the Koopman operator
[Vhat, Lambda] = eig(Khat);
if(rank(Vhat) < size(Vhat,1))
error('Vhat is not full rank (rank = %d). I didnt code up the case where Vhat isnt.', rank(Vhat));
end
Phi = Q*S*Vhat; % eigenfunctions of Khat
Xi = Phi\X;
X2hat = Phi*Lambda*Xi;
if(norm(imag(X2hat)) > 1e-3)
error('X2hat has non-negligible imaginary component.')
end
X2hat = real(X2hat); % this is quite an accurate reconstruction of X2.
disp('Finished computing kernel-DMD regression. Attempting simulation from IC.');
%% simulate forward
num_modes = size(Q,1); % i THINK this is the correct one
tic;
xhat(1,:) = X(1,:);
% xhat(1,1) = xhat(1,1) + 0.1;
% xhat(1,:) = xhat(1,:) + 0.001*randn(1,size(xhat,2));
for t = 2:2*size(X,1)
% calculate phi given x
prev_x = xhat(t-1,:);
% kernelmat = nan(1,num_modes);
% for M = 1:num_modes
% kernelmat(M) = kernel(prev_x,X(M,:));
% end
kernelmat = GaussianKernel(prev_x,X, sqrt(sigma2));
kernelmat = kernelmat(1:num_modes)';
phi_at_t = kernelmat*Q/S*Vhat;
% estimate
xnext = phi_at_t*Lambda*Xi;
if(norm(imag(xnext)) > 1e-3)
error('xnext isnt real (has non-negligble imaginary component)')
end
xhat(t,:) = real(xnext);
end
toc;
%% Check
figure(1)
clf
subplot(2,1,1)
plot(Xall(:,1));
hold on
plot([nan(1);X2hat(:,1)],'--');
plot(xhat(:,1),'--');
legend('true','1-step recon', 'n-step recon');
title('Reconstruction element 1')
subplot(2,1,2)
plot(Xall(:,6));
hold on
plot([nan(1);X2hat(:,6)],'--');
plot(xhat(:,6),'--');
legend('true','1-step recon', 'n-step recon');
title('Reconstruction element 6');
disp('Simulated from IC. Unscaling and casting data.');
%%
% offsetx = repmat(scaleOffset,size(xhat,1),1);
% reconstruction = xhat*diag(scaleFactor) + offsetx;
for k = 1:size(xhat,1)
xhatRescaled(k,:) = xhat(k,:).*scaleFactor + scaleOffset;
end
xhatRescaled = xhatRescaled';
xhatRescaled = removeconstantrows('reverse',xhatRescaled,ProcessSettings); % add removed rows back in.
% reconstruction = reshape(xhatRescaled,size(grayImages,1),size(grayImages,2),num_images);
for k = 1:size(xhatRescaled,2)
reconstruction(:,:,k) = reshape(xhatRescaled(1:size(allImages,1),k),size(grayImages,1),size(grayImages,2));
end
disp('Done.')
%% replay
reconsructionHdl = implay(uint8(reconstruction));
set(reconsructionHdl.Parent,'Name',sprintf('Reconstruction: %d modes, sigma2 = %.2e.',r,sigma2));
originalHdl = implay(grayImages(:,:,image_start:image_start+num_images));
set(originalHdl.Parent,'Name','Original data');
%%
% figure(3);
% clf
% mode_number = 1;
% % dont use uint8 and imshow, U0 is unitary so columns have very small
% % values
% singleMode = surf(flipud(reshape(Qfull(:,mode_number),size(grayImages,1),size(grayImages,2))),'LineStyle','none');
% % singleMode = surf(flipud(reshape(U0(:,mode_number),size(grayImages,1),size(grayImages,2))),'LineStyle','none');
% colormap(flipud(gray))
% modeEig = Lambda(mode_number,mode_number);
% title(sprintf('Mode %d, eig %.3f + %.3fi', mode_number, real(modeEig), imag(modeEig)));
% % view from above
% axis([0 360 -0.001 288 -1 0])
% view(0,90)
function F = GaussianKernel(Xin,Yin,sigma)
X = Xin./sigma;
Y = Yin./sigma;
% each term is |xi - yj|^2. Expanding:
% |x-y|^2 = x'x - 2*x'y + y'y. these three lines are the three terms.
X2 = sum(X.^2,2); %x'x as a column vector
Y2 = sum(Y.^2,2); %y'y as a column vector
XY = bsxfun(@minus, X2, (2*X)*Y.'); % add 2x'y terms
total = bsxfun(@plus, Y2.', XY); % add y'y terms
F = exp(-total)';
end