├── README.md
├── fMRI
├── data_driven_fMRI.m
├── fMRI_data
│ ├── data.zip.001
│ ├── data.zip.002
│ ├── data.zip.003
│ ├── data.zip.004
│ ├── data.zip.005
│ ├── data.zip.006
│ ├── data.zip.007
│ └── unrelated_subjects_final.txt
└── plot_results.m
├── kuramoto
└── data_driven_kuramoto_ring.m
├── power grid
├── NE_test_parameters.m
└── data_driven_fault_recovery.m
└── synthetic
├── data_driven_LQ.m
├── data_driven_min_energy.m
├── data_driven_min_energy_approx.m
├── plot_comput_time_data_driven.m
├── plot_data_driven_LQ.m
├── plot_data_driven_min_energy.m
├── plot_data_driven_vs_subspace_id.m
├── randomgraph.m
├── scalefree.m
└── smallworld.m
/README.md:
--------------------------------------------------------------------------------
1 | # Data-Driven Control of Networks
2 |
3 | This repository contains the code used in the the paper:
4 |
5 | > G. Baggio, D. S. Bassett, F. Pasqualetti "Data-Driven Control of Complex Networks", Nature Communications, vol. 12, no. 1, pp. 1-13, 2021.
6 |
7 | - The folder `synthetic` contains the Matlab functions and scripts for computing optimal data-driven controls and for comparing the performance of model-based and data-driven controls in synthetic experimental settings.
8 |
9 | - The folder `fMRI` contains the code for computing optimal data-driven controls from task-based fMRI data.
10 |
11 | - The folder `power grid` contains the code for computing optimal data-driven controls for fault recovery in power grid networks.
12 |
13 | - The folder `kuramoto` contains the code for computing optimal data-driven controls for pattern synchronization in a ring of Kuramoto oscillators.
14 |
15 | ***
16 |
17 | Author : G. Baggio
18 | E-mail : baggio [dot] giacomo [at] gmail [dot] com
19 |
--------------------------------------------------------------------------------
/fMRI/data_driven_fMRI.m:
--------------------------------------------------------------------------------
1 | function [control_energy_mb, control_energy_dd, err_mb, err_dd] = data_driven_fMRI(subject_id)
2 | % DATA_DRIVEN_FMRI - Computes the control energies and errors in the final
3 | % state for the data-driven input and model-based input
4 | %
5 | % Task-fMRI has been data extracted from the HCP S1200 dataset:
6 | %
7 | % https://www.humanconnectome.org/study/hcp-young-adult/document/1200-subjects-data-release
8 | %
9 | % The model-based input is computed using a linear model estimated as in:
10 | %
11 | % C. O. Becker, D. S. Bassett, V. M. Preciado.
12 | % "Large-scale dynamic modeling of task-fMRI signals via subspace system identification."
13 | % Journal of neural engineering 15.6 (2018): 066016.
14 | %
15 | % Syntax: [control_energy_mb, control_energy_dd, err_mb, err_dd] = data_driven_fMRI(subject_id)
16 | %
17 | % Inputs:
18 | % subject_id - subject id of HCP dataset
19 | %
20 | % Outputs:
21 | % control_energy_mb - control energy model-based input
22 | % control_energy_dd - control energy data-driven input
23 | % err_mb - error of model-based input
24 | % err_dd - error of data-driven input
25 | %
26 | % Author: Giacomo Baggio
27 | % email: baggio [dot] giacomo [at] gmail [dot] com
28 | % March 2020; Last revision: 01-April-2020
29 |
30 | %------------- BEGIN CODE --------------
31 |
32 | %% Parameters
33 | r = 148; % number of brain regions
34 | L = 284; % total time horizon
35 | T = 100; % control horizon
36 | T_est = 150; % estimation horizon
37 | m = 6; % number of inputs
38 | p = 148; % number of outputs
39 |
40 | % filter design parameters
41 | A_stop1 = 20; % Attenuation in the first stopband [Hz]
42 | F_stop1 = 0.04; % Edge of the stopband [Hz]
43 | F_pass1 = 0.06; % Edge of the passband [Hz]
44 | F_pass2 = 0.12; % Closing edge of the passband [Hz]
45 | F_stop2 = 0.15; % Edge of the second stopband [Hz]
46 | A_stop2 = 20; % Attenuation in the second stopband [Hz]
47 | A_pass = 1; % Amount of ripple allowed in the passband [Hz]
48 |
49 | %% Construct data matrices
50 |
51 | % data for data-driven control
52 | U = [];
53 | Yf = [];
54 |
55 | % data for system identification
56 | Ui = [];
57 | Yi = [];
58 |
59 | % load data of subject subject_id
60 | BOLD = ['./fMRI_data/bold_' num2str(subject_id) '.txt'];
61 | CUES = ['./fMRI_data/cues_' num2str(subject_id) '.txt'];
62 | HEART = ['./fMRI_data/heart_' num2str(subject_id) '.txt'];
63 | RESP = ['./fMRI_data/resp_' num2str(subject_id) '.txt'];
64 |
65 | % crop data to interval [1,284]
66 | outputs = load(BOLD);
67 | outputs = outputs(:,1:284);
68 | inputs = load(CUES);
69 | heart = load(HEART)';
70 | heart = heart(1:284);
71 | resp = load(RESP)';
72 | resp = resp(1:284);
73 |
74 | % encode visual cues
75 | inputs(6,12) = 1; inputs(6,33) = 1; inputs(6,54) = 1; inputs(6,75) = 1;
76 | inputs(6,96) = 1; inputs(6,138) = 1; inputs(6,159) = 1; inputs(6,180) = 1;
77 | inputs(6,221) = 1; inputs(6,242) = 1;
78 |
79 | % rearrange inputs: 1) CUE 2) LF 3) LH 4) RF 5) RH 6) T
80 | inputs = inputs([6 4 3 2 5 1],1:284);
81 |
82 | % physiological signals
83 | U_P = [heart; resp];
84 |
85 | % physiologically regressed outputs
86 | outputs_r = outputs*(eye(L)-pinv(U_P)*U_P);
87 |
88 | % band-pass filter
89 | Hd = fdesign.bandpass('N,Fst1,Fp1,Fp2,Fst2',50,F_stop1,F_pass1,F_pass2,F_stop2);
90 | d = design(Hd,'equiripple');
91 |
92 | % filtered outputs
93 | outputs_rf = filter(d,outputs_r');
94 | outputs_rf = outputs_rf';
95 |
96 | inputs_tmp = [zeros(m,T-10),inputs];
97 | outputs_tmp = [zeros(p,T-10),outputs_rf];
98 |
99 | Yi = reshape(outputs_rf(:,1:T_est),[],1);
100 | Ui = reshape(inputs(:,1:T_est),[],1);
101 |
102 | for t_s =1:T
103 | inputs_sel = flip(inputs_tmp(:,t_s:t_s+T-1),2);
104 | inputs_r = reshape(inputs_sel,[],1);
105 | U = [U inputs_r];
106 | Yf = [Yf outputs_tmp(:,t_s+T)];
107 | end
108 |
109 | %% Model identification
110 |
111 | % subspace identification parameters
112 | s = 3;
113 | len = T_est+1-s;
114 | Yh = zeros(s*p,len);
115 | Uh = zeros(s*m,len);
116 |
117 | % convert data in Hankel form
118 | Y_tmp = Yi;
119 | U_tmp = Ui;
120 |
121 | for j = 1:len
122 | Yh(:,j) = Y_tmp(1+p*(j-1):p*(j-1)+s*p);
123 | Uh(:,j) = U_tmp(1+m*(j-1):m*(j-1)+s*m);
124 | end
125 |
126 | Uperp = eye(len) - Uh'*pinv(Uh*Uh')*Uh;
127 | M = Yh*Uperp;
128 | [Us,Sigma,Vs] = svd(M);
129 | % select model order
130 | nr = 20;
131 | %nr = max([20,min(find(diag(Sigma/len)<0.0115))])
132 | % extended observability estimate
133 | Un = Us(:,1:nr);
134 |
135 | % estimate A matrix
136 | Aest = pinv(Un(1:p*(s-1),1:nr))*Un((p+1):p*s,1:nr);
137 |
138 | % enforce stability of A
139 | if max(abs(eig(Aest)))>1
140 | Aest = Aest/(max(abs(eig(Aest)))+1e-2);
141 | end
142 |
143 | % estimate C matrix
144 | Cest = Un(1:p,1:nr);
145 |
146 | % compute matrix K
147 |
148 | Y_tmp = Yi;
149 | U_tmp = Ui;
150 | K = [];
151 |
152 | for j = 1:T_est
153 |
154 | K_tmp = zeros(p,nr*m);
155 |
156 | if j ~= 1
157 | for r = 2:j
158 | K_tmp = K_tmp+kron(U_tmp(m*(r-2)+1:m*(r-1))',Cest*Aest^(j-r));
159 | end
160 | end
161 |
162 | K = [K; K_tmp];
163 | end
164 |
165 | Yh_tot = Y_tmp;
166 |
167 | % estimate B matrix
168 | gamma = 5; % regularization parameter
169 | Best = inv(K'*K+gamma*eye(m*nr))*K'*Yh_tot;
170 | Best = reshape(Best,[nr,m]);
171 |
172 | % estimated system
173 | sys_est = ss(Aest,Best,Cest,[],-1);
174 |
175 |
176 | %% compute error and control energy
177 |
178 | % compute output controllability matrix
179 | Co = sys_est.C*sys_est.B;
180 |
181 | for jj=1:T-1
182 | Co = [Co sys_est.C*sys_est.A^jj*sys_est.B];
183 | end
184 |
185 | % set of target states
186 | reach_outputs = orth(Yf*pinv(U));
187 | n_reach = nr;
188 |
189 | control_energy_mb = zeros(n_reach,1);
190 | control_energy_dd = zeros(n_reach,1);
191 | err_mb = zeros(n_reach,1);
192 | err_dd = zeros(n_reach,1);
193 |
194 | for j=1:n_reach
195 |
196 | yf = reach_outputs(:,j);
197 |
198 | % model-based control
199 | u_mb = Co'*pinv(Co*Co')*yf;
200 | % data-driven control
201 | u_dd = pinv(Yf*pinv(U))*yf;
202 |
203 | y_mb = Co*u_mb;
204 | y_dd = Co*u_dd;
205 |
206 | % normalized error model-based
207 | err_mb(j) = norm(yf-y_mb)/p;
208 | % normalized error data-driven
209 | err_dd(j) = norm(yf-y_dd)/p;
210 |
211 | % control energy model-based
212 | control_energy_mb(j) = norm(u_mb);
213 | % control energy data-driven
214 | control_energy_dd(j) = norm(u_dd);
215 |
216 | end
217 |
218 | %------------- END OF CODE --------------
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.001:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.001
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.002:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.002
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.003:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.003
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.004:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.004
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.005:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.005
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.006:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.006
--------------------------------------------------------------------------------
/fMRI/fMRI_data/data.zip.007:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baggiogi/data_driven_control/f0c968df2db43c364edf1e3a87310c519ca3ba8b/fMRI/fMRI_data/data.zip.007
--------------------------------------------------------------------------------
/fMRI/fMRI_data/unrelated_subjects_final.txt:
--------------------------------------------------------------------------------
1 | 100206
2 | 100610
3 | 101006
4 | 101309
5 | 101915
6 | 102311
7 | 102513
8 | 103414
9 | 105115
10 | 106016
11 | 107321
12 | 107422
13 | 108121
14 | 108222
15 | 109830
16 | 110007
17 | 110411
18 | 110613
19 | 112112
20 | 112314
21 | 112920
22 | 113922
23 | 116524
24 | 118124
25 | 118528
26 | 119126
27 | 121416
28 | 122822
29 | 123117
30 | 124422
31 | 124826
32 | 127630
33 | 128632
34 | 129028
35 | 129129
36 | 129634
37 | 130316
38 | 130417
39 | 131217
40 | 131823
41 | 132017
42 | 134021
43 | 134223
44 | 134425
45 | 134728
46 | 135528
47 | 135730
48 | 135932
49 | 136732
50 | 137229
51 | 137633
52 | 138231
53 | 139233
54 | 139637
55 | 139839
56 | 140117
57 | 141119
58 | 141826
59 | 144125
60 | 144731
61 | 146129
62 | 146432
63 | 146533
64 | 146937
65 | 147030
66 | 148133
67 | 149236
68 | 149337
69 | 149842
70 | 150625
71 | 150928
72 | 152831
73 | 153227
74 | 154229
75 | 154532
76 | 154734
77 | 154835
78 | 154936
79 | 155635
80 | 155938
81 | 157942
82 | 159138
83 | 159239
84 | 159340
85 | 159441
86 | 160830
87 | 161731
88 | 162329
89 | 162733
90 | 163331
91 | 163836
92 | 164030
93 | 164939
94 | 167238
95 | 168240
96 | 169949
97 | 170631
98 | 171633
99 | 172938
100 | 173435
101 | 173536
102 | 173738
103 | 173839
104 | 173940
105 | 174437
106 | 175035
107 | 175237
108 | 175338
109 | 175439
110 | 175742
111 | 176037
112 | 178950
113 | 179346
114 | 180129
115 | 181131
116 | 181232
117 | 181636
118 | 182436
119 | 183034
120 | 185139
121 | 185442
122 | 186141
123 | 186444
124 | 187345
125 | 188448
126 | 188549
127 | 188751
128 | 189450
129 | 191033
130 | 192035
131 | 192136
132 | 192843
133 | 194645
134 | 194746
135 | 195445
136 | 195849
137 | 195950
138 | 197348
139 | 198855
140 | 199453
141 | 199958
142 | 200008
143 | 200311
144 | 200614
145 | 201515
146 | 202719
147 | 203418
148 | 203923
149 | 204319
150 | 204521
151 | 204622
152 | 205119
153 | 206222
154 | 207123
155 | 208125
156 | 208327
157 | 209228
158 | 210415
159 | 211215
160 | 211316
161 | 211922
162 | 212015
163 | 212419
164 | 213421
165 | 214221
166 | 214423
167 | 214524
168 | 220721
169 | 221319
170 | 227432
171 | 228434
172 | 233326
173 | 248339
174 | 250427
175 | 250932
176 | 255639
177 | 257542
178 | 257845
179 | 268850
180 | 285446
181 | 293748
182 | 295146
183 | 297655
184 | 299154
185 | 300618
186 | 303119
187 | 304727
188 | 308331
189 | 309636
190 | 310621
191 | 316633
192 | 316835
193 | 318637
194 | 336841
195 | 352132
196 | 361941
197 | 371843
198 | 377451
199 | 380036
200 | 381038
201 | 386250
202 | 387959
203 | 393247
204 | 393550
205 | 395251
206 | 395756
207 | 397154
208 | 412528
209 | 414229
210 | 432332
211 | 433839
212 | 436845
213 | 449753
214 | 459453
215 | 465852
216 | 479762
217 | 495255
218 | 499566
219 | 510326
220 | 517239
221 | 520228
222 | 524135
223 | 525541
224 | 529549
225 | 529953
226 | 553344
227 | 555348
228 | 555651
229 | 559053
230 | 561444
231 | 562345
232 | 567052
233 | 567961
234 | 568963
235 | 571144
236 | 573249
237 | 576255
238 | 580044
239 | 580751
240 | 581349
241 | 585256
242 | 587664
243 | 597869
244 | 598568
245 | 599065
246 | 599671
247 | 604537
248 | 611938
249 | 616645
250 | 618952
251 | 622236
252 | 627549
253 | 633847
254 | 638049
255 | 645450
256 | 654350
257 | 654754
258 | 656253
259 | 656657
260 | 657659
261 | 660951
262 | 663755
263 | 664757
264 | 667056
265 | 671855
266 | 672756
267 | 679568
268 | 679770
269 | 690152
270 | 695768
271 | 715950
272 | 724446
273 | 725751
274 | 729557
275 | 731140
276 | 735148
277 | 744553
278 | 749058
279 | 753150
280 | 756055
281 | 769064
282 | 770352
283 | 782561
284 | 789373
285 | 792867
286 | 800941
287 | 803240
288 | 812746
289 | 816653
290 | 820745
291 | 825048
292 | 833148
293 | 833249
294 | 835657
295 | 837560
296 | 849264
297 | 849971
298 | 865363
299 | 872562
300 | 877269
301 | 889579
302 | 894067
303 | 894774
304 | 898176
305 | 899885
306 | 901442
307 | 907656
308 | 912447
309 | 919966
310 | 922854
311 | 923755
312 | 930449
313 | 947668
314 | 952863
315 | 955465
316 | 957974
317 | 966975
318 | 984472
319 | 987983
320 | 993675
321 | 994273
--------------------------------------------------------------------------------
/fMRI/plot_results.m:
--------------------------------------------------------------------------------
1 | % PLOT_RESULTS_FMRI - Plots average error and control energy of model-based
2 | % and data-driven controls of task-based fMRI dynamics
3 | %
4 | % Other m-files required: data_driven_fMRI.m
5 | %
6 | % Author: Giacomo Baggio
7 | % email: baggio [dot] giacomo [at] gmail [dot] com
8 | % March 2020; Last revision: 01-April-2020
9 |
10 | %------------- BEGIN CODE --------------
11 |
12 | clear all
13 | close all
14 | clc
15 |
16 | % number of subjects
17 | N = 1;
18 | % number of target states
19 | nr = 20;
20 |
21 | % load task-fMRI data
22 | load ./fMRI_data/unrelated_subjects_final.txt
23 | % pick N subjects randomly
24 | subjects_tot = datasample(1:280,N,'Replace',false);
25 |
26 | err_mb_tot = zeros(nr,N);
27 | err_dd_tot = zeros(nr,N);
28 | control_energy_mb_tot = zeros(nr,N);
29 | control_energy_dd_tot = zeros(nr,N);
30 |
31 | %% compute errors and control energies
32 | for ii = 1:N
33 |
34 | subject_id = unrelated_subjects_final(subjects_tot(ii));
35 | [control_energy_mb, control_energy_dd, err_mb, err_dd] = data_driven_fMRI(subject_id);
36 |
37 | err_mb_tot(:,ii) = err_mb;
38 | err_dd_tot(:,ii) = err_dd;
39 | control_energy_mb_tot(:,ii) = control_energy_mb;
40 | control_energy_dd_tot(:,ii) = control_energy_dd;
41 |
42 | end
43 |
44 | %% plot results
45 | figure
46 | subplot(2,1,1)
47 |
48 | mean_err_mb = sum(err_mb_tot,2)/N;
49 | std_err_mb = std(err_mb_tot,[],2);
50 | mean_err_dd = sum(err_dd_tot,2)/N;
51 | std_err_dd = std(err_dd_tot,[],2);
52 | mean_control_energy_mb = sum(control_energy_mb_tot,2)/N;
53 | std_control_energy_mb = std(control_energy_mb_tot,[],2);
54 | mean_control_energy_dd = sum(control_energy_dd_tot,2)/N;
55 | std_control_energy_dd = std(control_energy_dd_tot,[],2);
56 |
57 | bar([mean_err_mb mean_err_dd])
58 | legend('model-based','data-driven')
59 | title('norm of the error on final output')
60 | subplot(2,1,2)
61 | bar([mean_control_energy_mb mean_control_energy_dd])
62 | title('control energy')
63 | legend('model-based','data-driven')
64 |
65 | %------------- END OF CODE --------------
66 |
--------------------------------------------------------------------------------
/kuramoto/data_driven_kuramoto_ring.m:
--------------------------------------------------------------------------------
1 | % DATA_DRIVEN_KURAMOTO_RING - compute optimal data-driven control input
2 | % to enforce a prescribed phase-locked pattern in a Kuramoto ring network
3 | %
4 | % Author: Giacomo Baggio
5 | % email: baggio [dot] giacomo [at] gmail [dot] com
6 | % October 2020; Last revision: 16-November-2020
7 |
8 | %------------- BEGIN CODE --------------
9 |
10 | clear all
11 | close all
12 | clc
13 |
14 | %% generate ring network and set Kuramoto parameters
15 |
16 | % network size
17 | n = 10;
18 | % control node size
19 | m = 10;
20 | % control nodes
21 | %m_set = [4 5 6];
22 | m_set = [1 2 3 4 5 6 7 8 9 10];
23 | % number of neighbors per node
24 | k = 2;
25 |
26 | % define patterns
27 | for i = 1:n
28 |
29 | theta1(i,1) = wrapTo2Pi(0*pi*i/n); % initial phase-locked pattern
30 | theta2(i,1) = wrapTo2Pi(2*pi*i/n); % final phase-locked pattern
31 |
32 | end
33 |
34 | % natural frequencies
35 | omega = zeros(1,n)';
36 |
37 | % Construct a regular ring lattice: a graph with n nodes, each connected to k neighbors, k/2 on each side
38 | A = zeros(n);
39 | kHalf = k/2;
40 | rows = reshape(repmat([1:n]', 1, k), n*k, 1);
41 | columns = rows+reshape(repmat([[1:kHalf] [n-kHalf:n-1]], n, 1), n*k, 1);
42 | columns = mod(columns-1, n) + 1;
43 | A = sparse(rows, columns, ones(n*k, 1));
44 | A = full(A);
45 |
46 | %% generate data
47 |
48 | % number of data
49 | N = 2000;
50 |
51 | X0 = [];
52 | X_f = [];
53 | X_bar = [];
54 | U = [];
55 |
56 | tspan = [0 0.5]; % control times
57 | h = 0.01; % discretization step
58 | T = tspan(end)/h;
59 |
60 | for l=1:N
61 |
62 | theta = theta1+0.1*randn(n,1); % initial condition
63 |
64 | for t = 1 : tspan(end)/h - 1
65 |
66 | u(:,t) = 0.1*randn(m,1);
67 |
68 | p=1;
69 |
70 | for node = 1 : n
71 |
72 | if ismember(node,m_set)
73 | theta(node,t+1) = theta(node,t) + h*omega(node) + h*u(p,t);
74 | p=p+1;
75 | else
76 | theta(node,t+1) = theta(node,t) + h*omega(node);
77 | end
78 |
79 | for neighbor = 1 : n
80 | theta(node,t+1) = theta(node,t+1) + h*A(node,neighbor)*sin(theta(neighbor,t) - theta(node,t));
81 | end
82 |
83 | end
84 | end
85 |
86 | X0 = [X0 theta(:,1)];
87 | U = [U reshape(fliplr(u),[m*(tspan(end)/h-1),1])];
88 | X_bar = [X_bar reshape(theta(:,2:end-1),[n*(tspan(end)/h-2),1])];
89 | X_f = [X_f theta(:,end)];
90 |
91 | end
92 |
93 | K_X0 = null(X0,1e-10);
94 | K_U = null(U,1e-10);
95 | xf_c = (theta2-(X_f*K_U*pinv(X0*K_U,1e-10))*theta1);
96 |
97 | U = U*K_X0;
98 | X_bar = X_bar*K_X0;
99 | X_f = X_f*K_X0;
100 |
101 | % compute data-driven input
102 | K_f = null(X_f,1e-10);
103 | Q = 50*eye(n*(tspan(end)/h-2));
104 | R = 1*eye(m*(tspan(end)/h-1));
105 | L = cholcov(X_bar'*Q*X_bar+U'*R*U);
106 | [W,S,V]=svds(L*K_f,m*(T-1)-n);
107 |
108 | u_opt = U*pinv(X_f,1e-10)*xf_c-U*K_f*pinv(W*S*V',1e-10)*L*pinv(X_f,1e-10)*xf_c;
109 |
110 |
111 | %% simulate controlled system
112 |
113 | u_opt_seq = fliplr(reshape(u_opt,[m,(tspan(end)/h-1)]));
114 |
115 | theta = theta1;
116 | tspan = [0 9];
117 |
118 | for t = 1 : tspan(end)/h - 1
119 | N = size(theta,1);
120 |
121 | if t<50
122 | u(:,t) = u_opt_seq(:,t);
123 | else
124 | u(:,t) = zeros(m,1);
125 | end
126 |
127 | p=1;
128 | for node = 1 : n
129 |
130 | if ismember(node,m_set)
131 | theta(node,t+1) = theta(node,t) + h*omega(node) + h*u(p,t);
132 | p=p+1;
133 | else
134 | theta(node,t+1) = theta(node,t) + h*omega(node);
135 | end
136 |
137 | for neighbor = 1 : n
138 | theta(node,t+1) = theta(node,t+1) + h*A(node,neighbor)*sin(theta(neighbor,t) - theta(node,t));
139 | end
140 |
141 | end
142 | end
143 |
144 |
145 | theta_tot = [theta1.*ones(n,100) theta];
146 | figure
147 | plot(1:(tspan(end)/h+100), theta_tot)
148 | xlabel('time');
149 | ylabel('phases');
150 |
151 |
152 | %------------- END OF CODE --------------
153 |
--------------------------------------------------------------------------------
/power grid/NE_test_parameters.m:
--------------------------------------------------------------------------------
1 | % NE_TEST_PARAMETERS - Parameters of New England 39-bus 10-generator Test case
2 | % from Y. Susuki, I. Mezic, T. Hikihara, "Coherent Swing Instability of
3 | % Power Grids", J Nonlinear Sci, 2011
4 |
5 | %------------- BEGIN CODE --------------
6 |
7 | % initial phase angles at t=0 (generators' order: 10 2 3 4 5 6 7 8 9)
8 | y0 = [ 0.0193 0.1757 0.1998 0.1824 0.3329 0.2016 0.2042 0.1844 0.3145 0 0 0 0 0 0 0 0 0 ]';
9 |
10 | % inertia matrix / pi / 60 Hz
11 | H = diag([0.2228 0.1607 0.1899 0.1517 0.1379 0.1846 0.1401 0.1289 0.1830 2.6526]);
12 |
13 | % mechanical input power
14 | P = [ 1.2500 2.4943 3.2500 3.1600 2.5400 3.2500 2.8000 2.7000 4.1500 5.0000 ]';
15 |
16 | % damping matrix
17 | D = diag([ 0.0050 0.0050 0.0050 0.0050 0.0050 0.0050 0.0050 0.0050 0.0050 0.0050 ]);
18 |
19 | % terminal voltages
20 | E = abs([ 1.0568+0.0204i 0.9974+0.1770i 0.9842+0.1993i 0.9804+0.1809i 1.0855+0.3753i 1.0569+0.2160i 1.0423+0.2158i 0.9742+0.1817i 0.9352+0.3043i 1.0205-0.0431i ])';
21 |
22 | % network impedance matrix G+B*i (pre fault)
23 | Y3 = [ 0.7239-15.0009i 0.2080+0.9484i 0.2536+1.2183i 0.2565+1.2209i 0.1033+0.4161i 0.2348+1.0950i 0.1950+0.9237i 0.0670+2.9064i 0.1961+1.5928i 0.6099+4.8881i
24 | 0.2080+0.9484i 0.2519-9.1440i 0.2603+1.8170i 0.1657+0.6891i 0.0655+0.2346i 0.1513+0.6180i 0.1259+0.5214i 0.0916+0.5287i 0.1150+0.4400i 0.4159+2.7502i
25 | 0.2536+1.2183i 0.2603+1.8170i 0.3870-10.9096i 0.2142+0.9763i 0.0857+0.3326i 0.1959+0.8756i 0.1629+0.7386i 0.1144+0.6848i 0.1471+0.5888i 0.4569+2.9961i
26 | 0.2565+1.2209i 0.1657+0.6891i 0.2142+0.9763i 0.8131-12.0737i 0.2843+1.9774i 0.3178+1.7507i 0.2633+1.4766i 0.1608+0.7478i 0.2104+0.8320i 0.3469+1.6513i
27 | 0.1033+0.4161i 0.0655+0.2346i 0.0857+0.3326i 0.2843+1.9774i 0.1964-5.5114i 0.1309+0.5973i 0.1088+0.5038i 0.0645+0.2548i 0.0826+0.2831i 0.1397+0.5628i
28 | 0.2348+1.0950i 0.1513+0.6180i 0.1959+0.8756i 0.3178+1.7507i 0.1309+0.5973i 0.4550-11.1674i 0.3366+3.1985i 0.1471+0.6707i 0.1920+0.7461i 0.3175+1.4810i
29 | 0.1950+0.9237i 0.1259+0.5214i 0.1629+0.7386i 0.2633+1.4766i 0.1088+0.5038i 0.3366+3.1985i 0.4039-9.6140i 0.1223+0.5657i 0.1599+0.6294i 0.2638+1.2493i
30 | 0.0670+2.9064i 0.0916+0.5287i 0.1144+0.6848i 0.1608+0.7478i 0.0645+0.2548i 0.1471+0.6707i 0.1223+0.5657i 0.6650-10.0393i 0.3225+1.2618i 0.0991+2.5318i
31 | 0.1961+1.5928i 0.1150+0.4400i 0.1471+0.5888i 0.2104+0.8320i 0.0826+0.2831i 0.1920+0.7461i 0.1599+0.6294i 0.3225+1.2618i 0.9403-7.5882i 0.2377+1.5792i
32 | 0.6099+4.8881i 0.4159+2.7502i 0.4569+2.9961i 0.3469+1.6513i 0.1397+0.5628i 0.3175+1.4810i 0.2638+1.2493i 0.0991+2.5318i 0.2377+1.5792i 5.9222-18.6157i ];
33 |
34 |
35 | % network impedance matrix (fault on)
36 | Y32 = [ 0.5383-15.7638i 0.0901+0.5182i 0.0994+0.6084i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i -0.0490+2.4392i 0.0472+1.0736i 0.3589+3.8563i
37 | 0.0901+0.5182i 0.1779-9.3864i 0.1628+1.4731i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0180+0.2653i 0.0219+0.1476i 0.2564+2.1683i
38 | 0.0994+0.6084i 0.1628+1.4731i 0.2591-11.3971i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0181+0.3113i 0.0241+0.1739i 0.2483+2.1712i
39 | 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.4671-14.0254i 0.1411+1.3115i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i
40 | 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.1411+1.3115i 0.1389-5.7383i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i
41 | 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.1633-12.7378i 0.0947+1.8739i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i
42 | 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0947+1.8739i 0.2035-10.7312i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i
43 | -0.0490+2.4392i 0.0180+0.2653i 0.0181+0.3113i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.5925-10.3254i 0.2297+0.9440i -0.0579+1.8999i
44 | 0.0472+1.0736i 0.0219+0.1476i 0.0241+0.1739i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.2297+0.9440i 0.8235-7.9409i 0.0363+0.8770i
45 | 0.3589+3.8563i 0.2564+2.1683i 0.2483+2.1712i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i 0.0000+0.0000i -0.0579+1.8999i 0.0363+0.8770i 5.5826-20.0113i ];
46 |
47 |
48 | % network impedance matrix (post fault)
49 | Y33 = [ 0.8012-14.3511i 0.2163+0.9784i 0.2559+1.1997i 0.1629+0.5591i 0.0629+0.1900i 0.1483+0.5013i 0.1237+0.4230i 0.1385+3.3322i 0.3015+2.1485i 0.6576+5.3495i
50 | 0.2163+0.9784i 0.2525-9.1427i 0.2603+1.8161i 0.1565+0.6587i 0.0619+0.2243i 0.1429+0.5908i 0.1189+0.4984i 0.0980+0.5482i 0.1239+0.4653i 0.4214+2.7715i
51 | 0.2559+1.1997i 0.2603+1.8161i 0.3868-10.9091i 0.2124+0.9954i 0.0853+0.3392i 0.1943+0.8927i 0.1615+0.7530i 0.1153+0.6724i 0.1479+0.5726i 0.4586+2.9829i
52 | 0.1629+0.5591i 0.1565+0.6587i 0.2124+0.9954i 0.9236-11.4000i 0.3306+2.2074i 0.4194+2.3551i 0.3474+1.9863i 0.0782+0.3146i 0.0903+0.2669i 0.2878+1.1812i
53 | 0.0629+0.1900i 0.0619+0.2243i 0.0853+0.3392i 0.3306+2.2074i 0.2151-5.4330i 0.1734+0.8035i 0.1440+0.6778i 0.0308+0.1071i 0.0343+0.0905i 0.1135+0.4020i
54 | 0.1483+0.5013i 0.1429+0.5908i 0.1943+0.8927i 0.4194+2.3551i 0.1734+0.8035i 0.5485-10.6253i 0.4139+3.6557i 0.0714+0.2821i 0.0820+0.2392i 0.2627+1.0592i
55 | 0.1237+0.4230i 0.1189+0.4984i 0.1615+0.7530i 0.3474+1.9863i 0.1440+0.6778i 0.4139+3.6557i 0.4679-9.2284i 0.0594+0.2380i 0.0685+0.2019i 0.2187+0.8936i
56 | 0.1385+3.3322i 0.0980+0.5482i 0.1153+0.6724i 0.0782+0.3146i 0.0308+0.1071i 0.0714+0.2821i 0.0594+0.2380i 0.7257-9.7609i 0.4096+1.6248i 0.1451+2.8344i
57 | 0.3015+2.1485i 0.1239+0.4653i 0.1479+0.5726i 0.0903+0.2669i 0.0343+0.0905i 0.0820+0.2392i 0.0685+0.2019i 0.4096+1.6248i 1.0644-7.1152i 0.3063+1.9743i
58 | 0.6576+5.3495i 0.4214+2.7715i 0.4586+2.9829i 0.2878+1.1812i 0.1135+0.4020i 0.2627+1.0592i 0.2187+0.8936i 0.1451+2.8344i 0.3063+1.9743i 5.9509-18.2881i ];
59 |
60 | %------------- END OF CODE --------------
61 |
62 |
--------------------------------------------------------------------------------
/power grid/data_driven_fault_recovery.m:
--------------------------------------------------------------------------------
1 | % DATA_DRIVEN_FAULT_RECOVERY - compute optimal data-driven control input
2 | % for fault recovery in the New England 10-unit 39-bus Test case
3 | %
4 | % Other m-files required: NE_test_parameters.m
5 | %
6 | % Author: Giacomo Baggio
7 | % email: baggio [dot] giacomo [at] gmail [dot] com
8 | % July 2020; Last revision: 26-July-2020
9 |
10 | %------------- BEGIN CODE --------------
11 |
12 | clc
13 | clear all
14 | close all
15 |
16 | global H P D E Y3 Y32 T_fault_in T_fault_end
17 |
18 | % load grid parameters
19 | NE_test_parameters
20 |
21 | % initial stable state
22 | y0 = [0.1564 0.1806 0.1631 0.3135 0.1823 0.1849 0.1652 0.2953 -0.06165 0 0 0 0 0 0 0 0 0]';
23 | y0 = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]';
24 |
25 | % sampling time
26 | delta_t = 2.5e-4;
27 | % final simulation time
28 | T_sim = 15;
29 | % vector of simulation times
30 | tspan = 0:delta_t:T_sim;
31 | % fault initial time
32 | T_fault_in = 2;
33 | % fault final time
34 | T_fault_end = 2.525;
35 | % number of inputs
36 | m = 9;
37 | % number of states
38 | n = 18;
39 | % control horizon
40 | T = 0.1;
41 | % final stable state
42 | xf = y0;
43 | % control starting time
44 | t_c = 3;
45 |
46 | k = 1;
47 |
48 | %% simulate fault (discretized swing equations)
49 |
50 | for t = tspan
51 | yy(:,k) = swing(t,delta_t,y0,zeros(1,m));
52 | y0 = yy(:,k);
53 | k = k+1;
54 | end
55 |
56 | % initial state control
57 | x0 = yy(:,round(t_c/delta_t));
58 |
59 | % plot results
60 | figure(1)
61 | subplot(2,2,1)
62 | plot(tspan,yy(1:9,:))
63 | hold on
64 | fill([T_fault_in T_fault_in T_fault_end T_fault_end], [-20 200 200 -20], 'r','FaceAlpha',0.25,'LineStyle','none');
65 | ylabel('phase');
66 | xlabel('time t');
67 | legend('gen 10','gen 2','gen 3','gen 4','gen 5','gen 6','gen 7','gen 8','gen 9')
68 | subplot(2,2,3)
69 | plot(tspan,yy(10:18,:))
70 | hold on
71 | fill([T_fault_in T_fault_in T_fault_end T_fault_end], [-20 60 60 -20], 'r','FaceAlpha',0.25,'LineStyle','none');
72 | ylabel('frequency');
73 | xlabel('time t');
74 | legend('gen 10','gen 2','gen 3','gen 4','gen 5','gen 6','gen 7','gen 8','gen 9')
75 |
76 |
77 | %% generate data for control
78 |
79 | % number of samples
80 | N = 5000;
81 | % variance of inital states
82 | sigma = 0.01;
83 | % data matrices
84 | U = [];
85 | X0 = [];
86 | X1T = [];
87 | XT = [];
88 |
89 | for i=1:N
90 |
91 | k = 1;
92 |
93 | % random input
94 | u = 1e-3*randn(m,round(T/delta_t));
95 | % random initial state
96 | y0 = [0.1564+sigma*randn 0.1806+sigma*randn 0.1631+sigma*randn 0.3135+sigma*randn 0.1823+sigma*randn 0.1849+sigma*randn 0.1652+sigma*randn 0.2953+sigma*randn -0.06165+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn 0+sigma*randn]';
97 |
98 | y0 = [sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn sigma*randn]';
99 | y0_data = y0;
100 |
101 | for t = 0:delta_t:T-delta_t
102 | y_data(:,k) = swing(t,delta_t,y0_data,u(:,k));
103 | y0_data = y_data(:,k);
104 | k = k+1;
105 | end
106 |
107 | U = [U reshape(fliplr(u),[m*round(T/delta_t),1])];
108 | X0 = [X0 y0];
109 | X1T = [X1T reshape(fliplr(y_data(:,1:round(T/delta_t-1))),[n*round(T/delta_t-1),1])];
110 | XT = [XT y_data(:,end)];
111 | end
112 |
113 |
114 | %% compute data-driven control
115 |
116 | U = U(:,1:3750);
117 | XT = XT(:,1:3750);
118 | X0 = X0(:,1:3750);
119 | X1T = X1T(:,1:3750);
120 |
121 | K_X0 = null(X0,1e-10);
122 | K_U = null(U,1e-10);
123 | xf_c = (xf-(XT*K_U*pinv(X0*K_U,1e-10))*x0);
124 |
125 | U = U*K_X0;
126 | X1T = X1T*K_X0;
127 | XT = XT*K_X0;
128 |
129 | K_U = null(U,1e-10);
130 | K_XT = null(XT,1e-10);
131 | Q = 5e-3;
132 | R = 1;
133 |
134 | L2 = Q*((X1T)'*(X1T))+R*(U'*U);
135 | L = cholcov(L2);
136 | [W,S,V]=svds(L*K_XT,m*round(T/delta_t)-n);
137 |
138 | u_opt = U*pinv(XT,1e-10)*xf_c-U*K_XT*pinv(W*S*V',1e-10)*L*pinv(XT,1e-10)*xf_c;
139 | u_opt_seq = fliplr(reshape(u_opt,[m,round(T/delta_t)]));
140 |
141 | %% apply control for fault recovery
142 |
143 | u_opt_seq = [zeros(9,round(t_c/delta_t+1)) u_opt_seq zeros(9,round(500/delta_t))];
144 | y0 = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]';
145 |
146 | k = 1;
147 | tspan = 0:delta_t:500;
148 |
149 | for t = tspan
150 | yy(:,k) = swing(t,delta_t,y0,u_opt_seq(:,k));
151 | y0 = yy(:,k);
152 | k = k+1;
153 | end
154 |
155 | % plot results
156 | figure(1)
157 | subplot(2,2,2)
158 | plot(0:delta_t:T_sim,yy(1:9,1:round(T_sim/delta_t)+1))
159 | hold on
160 | fill([T_fault_in T_fault_in T_fault_end T_fault_end], [-10 15 15 -10], 'r','FaceAlpha',0.25,'LineStyle','none');
161 | hold on
162 | fill([t_c t_c t_c+T t_c+T], [-10 15 15 -10], 'g','FaceAlpha',0.25,'LineStyle','none');
163 | ylabel('phase');
164 | xlabel('time t');
165 | legend('gen 10','gen 2','gen 3','gen 4','gen 5','gen 6','gen 7','gen 8','gen 9')
166 | subplot(2,2,4)
167 | plot(0:delta_t:T_sim,yy(10:18,1:round(T_sim/delta_t)+1))
168 | hold on
169 | fill([T_fault_in T_fault_in T_fault_end T_fault_end], [-10 15 15 -10], 'r','FaceAlpha',0.25,'LineStyle','none');
170 | hold on
171 | fill([t_c t_c t_c+T t_c+T], [-10 15 15 -10], 'g','FaceAlpha',0.25,'LineStyle','none');
172 | ylabel('frequency');
173 | xlabel('time t');
174 | legend('gen 10','gen 2','gen 3','gen 4','gen 5','gen 6','gen 7','gen 8','gen 9')
175 |
176 | %asymptotic behavior
177 | figure(2)
178 | subplot(2,1,1)
179 | plot(tspan,yy(1:9,:))
180 | hold on
181 | fill([2 2 2.4 2.4], [-10 15 15 -10], 'r','FaceAlpha',0.25,'LineStyle','none');
182 | hold on
183 | fill([t_c t_c t_c+T t_c+T], [-10 15 15 -10], 'g','FaceAlpha',0.25,'LineStyle','none');
184 | ylabel('phase');
185 | xlabel('time t');
186 | legend('gen 10','gen 2','gen 3','gen 4','gen 5','gen 6','gen 7','gen 8','gen 9')
187 | subplot(2,1,2)
188 | plot(tspan,yy(10:18,:))
189 | hold on
190 | fill([2 2 2.4 2.4], [-10 15 15 -10], 'r','FaceAlpha',0.25,'LineStyle','none');
191 | hold on
192 | fill([t_c t_c t_c+T t_c+T], [-10 15 15 -10], 'g','FaceAlpha',0.25,'LineStyle','none');
193 | ylabel('frequency');
194 | xlabel('time t');
195 | legend('gen 10','gen 2','gen 3','gen 4','gen 5','gen 6','gen 7','gen 8','gen 9')
196 |
197 |
198 | function yp= swing(t,delta_t,y,u)
199 | % simulate power generators swing dynamics
200 |
201 | global H P D E Y3 Y32 T_fault_in T_fault_end
202 |
203 | yp = zeros(18,1);
204 |
205 | Y = Y3;
206 | k = [delta_t*(1/H(2,2))*(P(2)-real(Y(2,2))*E(2)^2-E(2)*E(1)*real(Y(2,1))-E(2)*E(3)*real(Y(2,3))- E(2)*E(4)*(real(Y(2,4)))-E(2)*E(5)*(real(Y(2,5)))-E(2)*E(6)*(real(Y(2,6)))-E(2)*E(7)*(real(Y(2,7)))-E(2)*E(8)*(real(Y(2,8)))-E(2)*E(9)*(real(Y(2,9)))-E(2)*E(10)*(real(Y(2,10))));
207 | delta_t*(1/H(3,3))*(P(3)-real(Y(3,3))*E(3)^2-E(3)*E(1)*(real(Y(3,1)))-E(3)*E(2)*(real(Y(3,2)))-E(3)*E(4)*(real(Y(3,4)))-E(3)*E(5)*(real(Y(3,5)))-E(3)*E(6)*(real(Y(3,6)))-E(3)*E(7)*(real(Y(3,7)))-E(3)*E(8)*(real(Y(3,8)))-E(3)*E(9)*(real(Y(3,9)))-E(3)*E(10)*(real(Y(3,10))));
208 | delta_t*(1/H(4,4))*(P(4)-real(Y(4,4))*E(4)^2-E(4)*E(1)*(real(Y(4,1)))-E(4)*E(2)*(real(Y(4,2)))-E(4)*E(3)*(real(Y(4,3)))-E(4)*E(5)*(real(Y(4,5)))-E(4)*E(6)*(real(Y(4,6)))-E(4)*E(7)*(real(Y(4,7)))-E(4)*E(8)*(real(Y(4,8)))-E(4)*E(9)*(real(Y(4,9)))-E(4)*E(10)*(real(Y(4,10))));
209 | delta_t*(1/H(5,5))*(P(5)-real(Y(5,5))*E(5)^2-E(5)*E(1)*(real(Y(5,1)))-E(5)*E(2)*(real(Y(5,2)))-E(5)*E(3)*(real(Y(5,3)))-E(5)*E(4)*(real(Y(5,4)))-E(5)*E(6)*(real(Y(5,6)))-E(5)*E(7)*(real(Y(5,7)))-E(5)*E(8)*(real(Y(5,8)))-E(5)*E(9)*(real(Y(5,9)))-E(5)*E(10)*(real(Y(5,10))));
210 | delta_t*(1/H(6,6))*(P(6)-real(Y(6,6))*E(6)^2-E(6)*E(1)*(real(Y(6,1)))-E(6)*E(2)*(real(Y(6,2)))-E(6)*E(3)*(real(Y(6,3)))-E(6)*E(4)*(real(Y(6,4)))-E(6)*E(5)*(real(Y(6,5)))-E(6)*E(7)*(real(Y(6,7)))-E(6)*E(8)*(real(Y(6,8)))-E(6)*E(9)*(real(Y(6,9)))-E(6)*E(10)*(real(Y(6,10))));
211 | delta_t*(1/H(7,7))*(P(7)-real(Y(7,7))*E(7)^2-E(7)*E(1)*(real(Y(7,1)))-E(7)*E(2)*(real(Y(7,2)))-E(7)*E(3)*(real(Y(7,3)))-E(7)*E(4)*(real(Y(7,4)))-E(7)*E(5)*(real(Y(7,5)))-E(7)*E(6)*(real(Y(7,6)))-E(7)*E(8)*(real(Y(7,8)))-E(7)*E(9)*(real(Y(7,9)))-E(7)*E(10)*(real(Y(7,10))));
212 | delta_t*(1/H(8,8))*(P(8)-real(Y(8,8))*E(8)^2-E(8)*E(1)*(real(Y(8,1)))-E(8)*E(2)*(real(Y(8,2)))-E(8)*E(3)*(real(Y(8,3)))-E(8)*E(4)*(real(Y(8,4)))-E(8)*E(5)*(real(Y(8,5)))-E(8)*E(6)*(real(Y(8,6)))-E(8)*E(7)*(real(Y(8,7)))-E(8)*E(9)*(real(Y(8,9)))-E(8)*E(10)*(real(Y(8,10))));
213 | delta_t*(1/H(9,9))*(P(9)-real(Y(9,9))*E(9)^2-E(9)*E(1)*(real(Y(9,1)))-E(9)*E(2)*(real(Y(9,2)))-E(9)*E(3)*(real(Y(9,3)))-E(9)*E(4)*(real(Y(9,4)))-E(9)*E(5)*(real(Y(9,5)))-E(9)*E(6)*(real(Y(9,6)))-E(9)*E(7)*(real(Y(9,7)))-E(9)*E(8)*(real(Y(9,8)))-E(9)*E(10)*(real(Y(9,10))));
214 | delta_t*(1/H(10,10))*(P(10)-real(Y(10,10))*E(10)^2-E(10)*E(1)*(real(Y(10,1)))-E(10)*E(2)*(real(Y(10,2)))-E(10)*E(3)*(real(Y(10,3)))-E(10)*E(4)*(real(Y(10,4)))-E(10)*E(5)*(real(Y(10,5)))-E(10)*E(6)*(real(Y(10,6)))-E(10)*E(7)*(real(Y(10,7)))-E(10)*E(8)*(real(Y(10,8)))-E(10)*E(9)*(real(Y(10,9))))];
215 |
216 | if t<2
217 | Y = Y3;
218 | elseif t>=T_fault_in && t T-r
38 | H((r-1)*p+1:r*p,(k-1)*m+1:k*m) = sys.C*sys.A^(r-T+k-1)*sys.B;
39 | end
40 | end
41 | end
42 |
43 | % last block row Hankel matrix
44 | H_f = H(p*(T-1)+1:end,:);
45 |
46 | % output data in the interval [1,T-1]
47 | Y_bar = Y(1:(T-1)*p,:);
48 | % output data at time T
49 | Y_f = Y((T-1)*p+1:end,:);
50 |
51 | K_f = null(Y_f);
52 | L = cholcov(Y_bar'*Q*Y_bar+U'*R*U);
53 | [W,S,V]=svds(L*K_f,m*T-p);
54 |
55 | % data-driven control
56 | u_opt = U*pinv(Y_f,1e-8)*yf-U*K_f*pinv(W*S*V')*L*pinv(Y_f,1e-8)*yf;
57 |
58 | % error on final state
59 | err = norm(yf - H_f*u_opt);
60 | % input norm
61 | norm_u = norm(u_opt);
62 |
63 | end
64 |
65 | %------------- END OF CODE --------------
66 |
--------------------------------------------------------------------------------
/synthetic/data_driven_min_energy.m:
--------------------------------------------------------------------------------
1 | function [u_opt,norm_u,err] = data_driven_min_energy(U,Y,sys,T,yf)
2 | % DATA_DRIVEN_MIN_ENRGY - computes data-driven minimum-energy control
3 | %
4 | % Syntax: [u_opt,norm_u,err] = data_driven_min_energy(U,Y,T,yf)
5 | %
6 | % Inputs:
7 | % U - input data matrix
8 | % Y - output data matrix
9 | % sys - state space system
10 | % T - control time horizon
11 | % yf - target state
12 | %
13 | %
14 | % Outputs:
15 | % u_opt - minimum-energy input sequence
16 | % norm_u - norm minimum-energy input sequence
17 | % err_u - error in the final state
18 | %
19 | % Author: Giacomo Baggio
20 | % email: baggio [dot] giacomo [at] gmail [dot] com
21 | % March 2020; Last revision: 01-April-2020
22 |
23 | %------------- BEGIN CODE --------------
24 |
25 | % number of nodes
26 | n = size(sys.A,1);
27 | % number of inputs
28 | m = size(sys.B,2);
29 | % number of outputs
30 | p = size(sys.C,1);
31 |
32 | % compute (output) controllability matrix
33 | C_o = zeros(n,m*T);
34 |
35 | C_o(:,1:m) = sys.B;
36 |
37 | for k=1:T-1
38 |
39 | C_o(:,(m*k+1):(k+1)*m) = sys.A*C_o(:,((k-1)*m+1):m*k);
40 |
41 | end
42 |
43 | C_o = sys.C*C_o;
44 |
45 | % data-driven control
46 | K = null(Y);
47 | [W,S,V]=svds(U*K,m*T-p);
48 |
49 | % data-driven control
50 | u_opt = U*pinv(Y,1e-8)*yf-U*K*pinv(W*S*V')*U*pinv(Y,1e-8)*yf;
51 |
52 | % error on final state
53 | err = norm(yf - C_o*u_opt);
54 | % input norm
55 | norm_u = norm(u_opt);
56 |
57 |
58 | end
59 |
60 | %------------- END OF CODE --------------
61 |
--------------------------------------------------------------------------------
/synthetic/data_driven_min_energy_approx.m:
--------------------------------------------------------------------------------
1 | function [u_opt,norm_u,err] = data_driven_min_energy_approx(U,Y,sys,T,yf)
2 | % DATA_DRIVEN_MIN_ENRGY - computes approximate data-driven minimum-energy control
3 | %
4 | % Syntax: [u_opt,norm_u,err] = data_driven_min_energy_approx(U,Y,T,yf)
5 | %
6 | % Inputs:
7 | % U - input data matrix
8 | % Y - output data matrix
9 | % sys - state space system
10 | % T - control time horizon
11 | % yf - target state
12 | %
13 | %
14 | % Outputs:
15 | % u_opt - minimum-energy input sequence
16 | % norm_u - norm minimum-energy input sequence
17 | % err_u - error in the final state
18 | %
19 | % Author: Giacomo Baggio
20 | % email: baggio [dot] giacomo [at] gmail [dot] com
21 | % March 2020; Last revision: 01-April-2020
22 |
23 | %------------- BEGIN CODE --------------
24 |
25 | % number of nodes
26 | n = size(sys.A,1);
27 | % number of inputs
28 | m = size(sys.B,2);
29 |
30 | % compute (output) controllability matrix
31 | C_o = zeros(n,m*T);
32 |
33 | C_o(:,1:m) = sys.B;
34 |
35 | for k=1:T-1
36 |
37 | C_o(:,(m*k+1):(k+1)*m) = sys.A*C_o(:,((k-1)*m+1):m*k);
38 |
39 | end
40 |
41 | C_o = sys.C*C_o;
42 |
43 | % data-driven control
44 | u_opt = U*pinv(Y,1e-8)*yf;
45 |
46 | % error on final state
47 | err = norm(yf - C_o*u_opt);
48 | % input norm
49 | norm_u = norm(u_opt);
50 |
51 |
52 | end
53 |
54 | %------------- END OF CODE --------------
--------------------------------------------------------------------------------
/synthetic/plot_comput_time_data_driven.m:
--------------------------------------------------------------------------------
1 | % PLOT_DATA_COMPUTE_TIME_DATA_DRIVEN - Plots the computational times and errors
2 | % when computing minimum-energy controls using the data-driven strategies and
3 | % model-based ones for Erdős–Rényi dynamical networks as a function of
4 | % the network dimension
5 | %
6 | % Author: Giacomo Baggio
7 | % email: baggio [dot] giacomo [at] gmail [dot] com
8 | % March 2020; Last revision: 01-April-2020
9 |
10 | %------------- BEGIN CODE --------------
11 |
12 | clc
13 | clear all
14 | close all
15 |
16 | int_n = 1000:1000:10000; % network dimension
17 | epsilon = 0.05; % E-R edge density
18 |
19 | % computational times
20 | elapsedTime_mb = zeros(1,length(int_n));
21 | elapsedTime_dd = zeros(1,length(int_n));
22 | elapsedTime_dd_approx = zeros(1,length(int_n));
23 |
24 | % errors
25 | err_mb = zeros(1,length(int_n));
26 | err_dd = zeros(1,length(int_n));
27 | err_dd_approx = zeros(1,length(int_n));
28 |
29 | l = 1;
30 |
31 | for n = int_n
32 |
33 | n
34 | m = 0.01*n; % input dimension
35 | p = 0.01*n; % output dimension
36 | T = 0.01*n + 10; % control horizon
37 | N = m*T; % samples
38 | yf = randn(p,1); % target state
39 |
40 | % adjacency matrix E-R graph
41 | A = randomgraph(n,log(n)/n+epsilon);
42 | A = A/(norm(A)+0.01);
43 |
44 | % input matrix
45 | B = zeros(n,m);
46 |
47 | b_temp = randperm(n);
48 | b = b_temp(1:m);
49 |
50 | for q = 1:length(b)
51 |
52 | B(b(q),q) = 1;
53 |
54 | end
55 |
56 | % output matrix
57 | C = zeros(p,n);
58 |
59 | c_temp = randperm(n);
60 | c = c_temp(1:p);
61 |
62 | for q = 1:length(c)
63 |
64 | C(q,c(q)) = 1;
65 |
66 | end
67 |
68 | %% model-based computation
69 |
70 | % state space system
71 | sys = ss(A,B,C,[]);
72 |
73 | tic
74 | % compute (output) controllability matrix
75 | C_o = zeros(n,m*T);
76 |
77 | C_o(:,1:m) = B;
78 |
79 | for k=1:T-1
80 |
81 | C_o(:,(m*k+1):(k+1)*m) = sys.A*C_o(:,((k-1)*m+1):m*k);
82 |
83 | end
84 |
85 | C_o = sys.C*C_o;
86 |
87 | % minimum-energy model-based control
88 | u = pinv(C_o)*yf;
89 |
90 | elapsedTime_mb(l) = toc;
91 |
92 | err_mb(l) = norm(yf - C_o*u);
93 |
94 | %% data-driven computation
95 |
96 | U = randn(m*T,p);
97 | Y = C_o*U;
98 |
99 | tic
100 |
101 | % minimum-energy data-driven control
102 | u_dd = pinv(Y*pinv(U))*yf;
103 |
104 | elapsedTime_dd(l) = toc;
105 |
106 | err_dd(l) = norm(yf - C_o*u_dd);
107 |
108 | tic
109 |
110 | % approximate minimum-energy data-driven control
111 | u_dd_approx = U*pinv(Y)*yf;
112 |
113 | elapsedTime_dd_approx(l) = toc;
114 |
115 | err_dd_approx(l) = norm(yf - C_o*u_dd_approx);
116 |
117 | l = l+1;
118 |
119 | end
120 |
121 | figure
122 |
123 | plot(int_n,log10(elapsedTime_mb));
124 | hold on
125 | plot(int_n,log10(elapsedTime_dd));
126 | hold on
127 | plot(int_n,log10(elapsedTime_dd_approx));
128 | xlabel('dimension')
129 | ylabel('computational time (sec)')
130 | legend({'optimal','data-driven','data-driven approx'},'Location','best')
131 |
132 | figure
133 |
134 | plot(int_n,log10(err_mb));
135 | hold on
136 | plot(int_n,log10(err_dd));
137 | hold on
138 | plot(int_n,log10(err_dd_approx));
139 | xlabel('dimension')
140 | ylabel('error in final state')
141 | legend({'optimal','data-driven','data-driven approx'},'Location','best')
142 |
--------------------------------------------------------------------------------
/synthetic/plot_data_driven_LQ.m:
--------------------------------------------------------------------------------
1 | % PLOT_DATA_DRIVEN_LQ - Plots error and control energy of optimal model-based
2 | % and data-driven controls for Erdos-Renyi dynamical networks as a function
3 | % of the data size
4 | %
5 | % Other m-files required: data_driven_LQ.m
6 | %
7 | % Author: Giacomo Baggio
8 | % email: baggio [dot] giacomo [at] gmail [dot] com
9 | % March 2020; Last revision: 01-April-2020
10 |
11 | %------------- BEGIN CODE --------------
12 |
13 | clc
14 | clear all
15 | close all
16 |
17 | n = 100; % network dimension
18 | m = 5; % input dimension
19 | p = 20; % output dimension
20 | T = 10; % control horizon
21 | epsilon = 0.1; % E-R edge density
22 | int_N = 1:100; % samples
23 | Ntrials = 10; % number of trials
24 | yf = randn(p,1); % final state
25 | Q = eye(p*(T-1)); % output cost
26 | R = eye(m*T); % input cost
27 |
28 | % norm optimal model-based input
29 | norm_u_opt = zeros(1,length(int_N));
30 | % norm optimal data-driven input
31 | norm_u_data_driven = zeros(1,length(int_N));
32 |
33 | % error optimal model-based input
34 | err_opt = zeros(1,length(int_N));
35 | % error optimal data-driveninput
36 | err_data_driven = zeros(1,length(int_N));
37 |
38 | % generate E-R nework
39 | A = randomgraph(n,log(n)/n+epsilon);
40 | A_bin = A;
41 | A = A/sqrt(n);
42 |
43 | % generate input matrix
44 | B = zeros(n,m);
45 |
46 | b_temp = randperm(n);
47 | b = b_temp(1:m);
48 |
49 | for q = 1:length(b)
50 |
51 | B(b(q),q) = 1;
52 |
53 | end
54 |
55 | % generate output matrix
56 | C = zeros(p,n);
57 |
58 | c_temp = randperm(n);
59 | c = c_temp(1:p);
60 |
61 | for q = 1:length(c)
62 |
63 | C(q,c(q)) = 1;
64 |
65 | end
66 |
67 | % state space system
68 | sys = ss(A,B,C,[]);
69 |
70 | % compute T-steps system Hankel matrix
71 | H = zeros(p*T,m*T);
72 |
73 | for r=1:T
74 | for k=1:T
75 | if k > T-r
76 | H((r-1)*p+1:r*p,(k-1)*m+1:k*m) = sys.C*sys.A^(r-T+k-1)*sys.B;
77 | end
78 | end
79 | end
80 |
81 | H_bar = H(1:p*(T-1),:);
82 |
83 | % last block row Hankel matrix
84 | H_f = H(p*(T-1)+1:end,:);
85 |
86 | l=1;
87 |
88 | for N = int_N
89 |
90 | err_opt(l) = 0;
91 | norm_u_opt(l) = 0;
92 | err_data_driven(l) = 0;
93 | norm_u_data_driven(l) = 0;
94 |
95 | for q=1:Ntrials
96 |
97 | % create random data matrices
98 | U = randn(m*T,N);
99 | Y = H*U;
100 | Y_bar = Y(1:(T-1)*p,:);
101 | Y_f = Y((T-1)*p+1:end,:);
102 |
103 | % data-driven control
104 | [u_opt_dd,norm_u_dd,err_dd] = data_driven_LQ(U,Y,sys,T,yf,Q,R);
105 |
106 | % model-based control
107 | K_Hf = null(H_f);
108 | L_m = cholcov(H_bar'*Q*H_bar+R);
109 | u_opt = pinv(H_f,1e-8)*yf-K_Hf*pinv(L_m*K_Hf,1e-8)*L_m*pinv(H_f,1e-8)*yf;
110 |
111 | err_data_driven(l) = err_data_driven(l)+err_dd/Ntrials;
112 | norm_u_data_driven(l) = norm_u_data_driven(l)+norm_u_dd/Ntrials;
113 |
114 | err_opt(l) = err_opt(l)+norm(yf - H_f*u_opt)/Ntrials;
115 | norm_u_opt(l) = norm_u_opt(l)+norm(u_opt)/Ntrials;
116 |
117 | end
118 |
119 | l = l+1;
120 |
121 | end
122 |
123 | figure
124 |
125 | plot(int_N,log10(err_opt),'-o');
126 | hold on
127 | plot(int_N,log10(err_data_driven),'-*');
128 | xlabel('# samples')
129 | ylabel('error in final state')
130 | legend({'optimal','data-driven'},'Location','best')
131 |
132 | figure
133 |
134 | plot(int_N,log10(norm_u_opt),'-o');
135 | hold on
136 | plot(int_N,log10(norm_u_data_driven),'-*');
137 | xlabel('# samples')
138 | ylabel('control energy')
139 | legend({'optimal','data-driven'},'Location','best')
140 |
141 | %------------- END OF CODE --------------
142 |
--------------------------------------------------------------------------------
/synthetic/plot_data_driven_min_energy.m:
--------------------------------------------------------------------------------
1 | % PLOT_DATA_DRIVEN_MIN_ENERGY - Plots error and control energy of minimum-energy
2 | % model-based and data-driven controls for Erdős–Rényi dynamical networks
3 | % as a function of the data size
4 | %
5 | % Other m-files required: data_driven_min_energy.m, data_driven_min_energy_approx.m
6 | %
7 | % Author: Giacomo Baggio
8 | % email: baggio [dot] giacomo [at] gmail [dot] com
9 | % March 2020; Last revision: 01-April-2020
10 |
11 | %------------- BEGIN CODE --------------
12 |
13 | clc
14 | clear all
15 | close all
16 |
17 | n = 100; % network dimension
18 | m = 5; % input dimension
19 | p = 20; % output dimension
20 | T = 10; % control horizon
21 | epsilon = 0.1; % E-R edge density
22 | int_N = 1:100; % samples
23 | Ntrials = 10; % number of trials
24 | yf = randn(p,1); % final state
25 |
26 | % norm min-energy model-based input
27 | norm_u_opt = zeros(1,length(int_N));
28 | % norm min-energy data-driven input
29 | norm_u_data_driven = zeros(1,length(int_N));
30 | % norm approx min-energy data-driven input
31 | norm_u_data_driven_approx = zeros(1,length(int_N));
32 |
33 | % error min-energy model-based input
34 | err_opt = zeros(1,length(int_N));
35 | % error min-energy data-driven input
36 | err_data_driven = zeros(1,length(int_N));
37 | % error approx min-energy data-driven input
38 | err_data_driven_approx = zeros(1,length(int_N));
39 |
40 | % generate E-R nework
41 | A = randomgraph(n,log(n)/n+epsilon);
42 | A_bin = A;
43 | A = A/sqrt(n);
44 |
45 | % generate input matrix
46 | B = zeros(n,m);
47 |
48 | b_temp = randperm(n);
49 | b = b_temp(1:m);
50 |
51 | for q = 1:length(b)
52 |
53 | B(b(q),q) = 1;
54 |
55 | end
56 |
57 | % generate output matrix
58 | C = zeros(p,n);
59 |
60 | c_temp = randperm(n);
61 | c = c_temp(1:p);
62 |
63 | for q = 1:length(c)
64 |
65 | C(q,c(q)) = 1;
66 |
67 | end
68 |
69 | % state space system
70 | sys = ss(A,B,C,[]);
71 |
72 | % compute (output) controllability matrix
73 | C_o = zeros(n,m*T);
74 |
75 | C_o(:,1:m) = B;
76 |
77 | for k=1:T-1
78 |
79 | C_o(:,(m*k+1):(k+1)*m) = sys.A*C_o(:,((k-1)*m+1):m*k);
80 |
81 | end
82 |
83 | C_o = sys.C*C_o;
84 |
85 | l=1;
86 |
87 | for N = int_N
88 |
89 | err_opt(l) = 0;
90 | norm_u_opt(l) = 0;
91 | err_data_driven(l) = 0;
92 | norm_u_data_driven(l) = 0;
93 |
94 | for q=1:Ntrials
95 |
96 | % create random data matrices
97 | U = randn(m*T,N);
98 | Y = C_o*U;
99 |
100 | % data-driven control
101 | [u_opt_dd,norm_u_dd,err_dd] = data_driven_min_energy(U,Y,sys,T,yf);
102 | % approx data-driven control
103 | [u_opt_dd_approx,norm_u_dd_approx,err_dd_approx] = data_driven_min_energy_approx(U,Y,sys,T,yf);
104 |
105 | % model-based control
106 | u_opt = pinv(C_o)*yf;
107 |
108 | err_data_driven(l) = err_data_driven(l)+err_dd/Ntrials;
109 | norm_u_data_driven(l) = norm_u_data_driven(l)+norm_u_dd/Ntrials;
110 |
111 | err_data_driven_approx(l) = err_data_driven_approx(l)+err_dd_approx/Ntrials;
112 | norm_u_data_driven_approx(l) = norm_u_data_driven_approx(l)+norm_u_dd_approx/Ntrials;
113 |
114 | err_opt(l) = err_opt(l)+norm(yf - C_o*u_opt)/Ntrials;
115 | norm_u_opt(l) = norm_u_opt(l)+norm(u_opt)/Ntrials;
116 |
117 | end
118 |
119 | l = l+1;
120 |
121 | end
122 |
123 | figure
124 |
125 | plot(int_N,log10(err_opt),'-o');
126 | hold on
127 | plot(int_N,log10(err_data_driven),'-*');
128 | hold on
129 | plot(int_N,log10(err_data_driven_approx),'-x');
130 | xlabel('# samples')
131 | ylabel('error in final state')
132 | legend({'optimal','data-driven','data-driven approx'},'Location','best')
133 |
134 | figure
135 |
136 | plot(int_N,log10(norm_u_opt),'-o');
137 | hold on
138 | plot(int_N,log10(norm_u_data_driven),'-*');
139 | hold on
140 | plot(int_N,log10(norm_u_data_driven_approx),'-x');
141 | xlabel('# samples')
142 | ylabel('control energy')
143 | legend({'optimal','data-driven','data-driven approx'},'Location','best')
144 |
145 | %------------- END OF CODE --------------
146 |
--------------------------------------------------------------------------------
/synthetic/plot_data_driven_vs_subspace_id.m:
--------------------------------------------------------------------------------
1 | % PLOT_DATA_DRIVEN_VS_SUBSPACE_ID - Compares error of minimum-energy
2 | % model-based (where the models is estimated via subspace-based methods)
3 | % and data-driven controls for Erdős–Rényi dynamical networks as a
4 | % function of the network dimension
5 | %
6 | % Other m-files required: data_driven_min_energy.m
7 | %
8 | % Author: Giacomo Baggio
9 | % email: baggio [dot] giacomo [at] gmail [dot] com
10 | % March 2020; Last revision: 01-April-2020
11 |
12 | %------------- BEGIN CODE --------------
13 |
14 | clc
15 | clear all
16 | close all
17 |
18 | int_n = 50:10:200; % network dimension
19 | epsilon = 0.1; % E-R edge density
20 | Ntrials = 50; % number of trials
21 |
22 | norm_u_opt = zeros(Ntrials,length(int_n));
23 | norm_u_data_driven = zeros(Ntrials,length(int_n));
24 | norm_u_data_driven_sub = zeros(Ntrials,length(int_n));
25 |
26 | err_opt = zeros(Ntrials,length(int_n));
27 | err_data_driven = zeros(Ntrials,length(int_n));
28 | err_data_driven_sub = zeros(Ntrials,length(int_n));
29 |
30 | l=1;
31 |
32 | for n = int_n
33 |
34 | m = n/10; % input dimension
35 | p = n; % output dimension
36 | T = 20; % control horizon
37 | N = m*T+10; % samples
38 | yf = randn(p,1); % final state
39 |
40 | for q=1:Ntrials
41 |
42 | C_o = zeros(p,m*T);
43 | A = zeros(n);
44 | G = graph(A,'omitselfloops');
45 | [bins,binsize] = conncomp(G);
46 |
47 | % ensure that the E-R graph is always connected & controllable
48 | while min(svd(C_o))<1e-10 && length(binsize)>1
49 |
50 | % adjacency matrix E-R graph
51 | A = randomgraph(n,log(n)/n+epsilon);
52 | G = graph(A,'omitselfloops');
53 | [bins,binsize] = conncomp(G);
54 | A_bin = A;
55 | A = A/(sqrt(n));
56 |
57 | % input matrix
58 | B = zeros(n,m);
59 |
60 | b_temp = randperm(n);
61 | b = b_temp(1:m);
62 |
63 | for qq = 1:length(b)
64 |
65 | B(b(qq),qq) = 1;
66 |
67 | end
68 |
69 | % output matrix
70 | C = eye(n);
71 |
72 | % state space system
73 | sys = ss(A,B,C,[]);
74 |
75 | % compute (output) controllability matrix
76 | C_o = zeros(n,m*T);
77 |
78 | C_o(:,1:m) = B;
79 |
80 | for k=1:T-1
81 |
82 | C_o(:,(m*k+1):(k+1)*m) = sys.A*C_o(:,((k-1)*m+1):m*k);
83 |
84 | end
85 |
86 | C_o = sys.C*C_o;
87 |
88 | end
89 |
90 | % create random data matrices
91 | U = rand(m*T,N);
92 | Y = C_o*U;
93 |
94 | % data-driven control
95 | [u_opt_dd,norm_u_dd,err_dd] = data_driven_min_energy(U,Y,sys,T,yf);
96 |
97 | %% model identification via subspace method via controllability matrix
98 |
99 | % estimate controllability matrix
100 | Ctrb_est = Y*pinv(U);
101 | [Us,Sigma,Vs] = svd(Ctrb_est);
102 | % select model order
103 | nr = n;
104 |
105 | % estimate C
106 | C_est = eye(n);
107 | % estimate B
108 | B_est = Ctrb_est(:,1:m);
109 |
110 | Ctrb_est_p = Ctrb_est(:,m+1:end);
111 | Ctrb_est_m = Ctrb_est(:,1:(end-m));
112 | % estimate A
113 | A_est = Ctrb_est_p*pinv(Ctrb_est_m);
114 |
115 | % estimated system
116 | sys_est = ss(A_est,B_est,C_est,[],-1);
117 |
118 | % compute (output) controllability matrix estimated system
119 | C_o_est = zeros(n,m*T);
120 |
121 | C_o_est(:,1:m) = sys_est.B;
122 |
123 | for k=1:T-1
124 |
125 | C_o_est(:,(m*k+1):(k+1)*m) = sys_est.A*C_o_est(:,((k-1)*m+1):m*k);
126 |
127 | end
128 |
129 | C_o_est = sys_est.C*C_o_est;
130 |
131 | % model-based control
132 | u_opt = pinv(C_o_est)*yf;
133 |
134 |
135 | err_data_driven(q,l) = err_dd;
136 | norm_u_data_driven(q,l) = norm_u_dd;
137 |
138 | err_opt(q,l) = norm(yf - C_o*u_opt);
139 | norm_u_opt(q,l) = norm(u_opt);
140 |
141 | end
142 |
143 | l = l+1;
144 |
145 | end
146 |
147 | figure
148 |
149 | plot(int_n,log10(mean(err_opt,1)),'-o');
150 | hold on
151 | plot(int_n,log10(mean(err_data_driven,1)),'-*');
152 | xlabel('dimension')
153 | ylabel('error in final state')
154 | legend({'optimal','data-driven'},'Location','best')
155 |
156 | %------------- END OF CODE --------------
157 |
--------------------------------------------------------------------------------
/synthetic/randomgraph.m:
--------------------------------------------------------------------------------
1 | function final= randomgraph(n,p)
2 | % RANDOMGRAPH - generates an undirected random graph (without self-loops) of size n (as
3 | % described in the Erdoes-Renyi model)
4 | %
5 | % Inputs:
6 | % n - number of nodes
7 | % p - probability that node i and node j, i != j, are connected by an edge
8 | %
9 | % Outputs:
10 | % final - nxn full symmetric adjacency matrix representing the generated graph
11 | %
12 |
13 | %------------- BEGIN CODE --------------
14 |
15 | G = rand(n,n) < p;
16 | G = triu(G,1);
17 | G = G + G';
18 | final = G;
19 |
20 | end
21 |
22 | %------------- END OF CODE --------------
23 |
--------------------------------------------------------------------------------
/synthetic/scalefree.m:
--------------------------------------------------------------------------------
1 | function final = scalefree(n, m0, m)
2 | % SCALEFREE - Use the Barabasi-Albert model to generate a scale free graph of size n (as
3 | % described in Albert-Laszlo Barabasi & Reka Albert: "Emergence of scaling
4 | % in random networks")
5 | %
6 | % Inputs:
7 | % n: number of nodes
8 | % m0: number of initially placed nodes
9 | % m: number of nodes a new added node is connected to, 1 <= m < m0
10 | %
11 | % Outputs:
12 | % final: sparse symmetric adjacency matrix representing the generated graph
13 |
14 | %------------- BEGIN CODE --------------
15 | % Start with a graph of size m0 and add edges to this graph. Each of these m0
16 | % nodes is connected to at least m nodes.
17 | B = zeros(m0, m0);
18 | for i = 1:m0
19 | neighbors = randsample(m0-1, m);
20 | neighbors = neighbors + (neighbors>=i);
21 | B(i,neighbors) = 1;
22 | B(neighbors,i) = 1;
23 | end
24 |
25 | % Create a vector of edges added so far, i.e. nodes edge(2*i) and edge(2*i-1),
26 | % 1 <= i <= nEdges, are connected by an edge.
27 | [rows, columns] = find(triu(B));
28 | nEdges = size(rows, 1);
29 | edges = reshape([rows';columns'], 2*nEdges, 1);
30 | edges = [edges; zeros(2*(n-m0)*m,1)];
31 |
32 | % Add nodes m0+1:n, one at a time. Each node is connected to m existing nodes,
33 | % where each of the existing nodes is chosen with a probability that is
34 | % proportional to the number of nodes it is already connected to.
35 | used = zeros(n, 1); % is a node already used in a timestep?
36 | for i = m0+1:n
37 | neighbors = zeros(1, m);
38 | for j=1:m
39 | k = edges(randi(2*nEdges));
40 | while used(k)
41 | k = edges(randi(2*nEdges));
42 | end
43 | used(k) = 1;
44 | neighbors(j) = k;
45 | end
46 | used(neighbors) = 0;
47 | edges(2*nEdges+1:2*nEdges+2*m) = reshape([repmat(i, 1, m); neighbors], ...
48 | 1, 2*m);
49 | nEdges = nEdges+m;
50 | end
51 |
52 | % finally construct a symmetric adjacency matrix using the vector of edges
53 | edges = edges(1:2*nEdges);
54 | first = edges(1:2:end);
55 | second = edges(2:2:end);
56 | final = sparse([first;second], [second;first], ones(2*nEdges, 1), n, n);
57 |
58 | end
59 |
60 | %------------- END OF CODE --------------
61 |
--------------------------------------------------------------------------------
/synthetic/smallworld.m:
--------------------------------------------------------------------------------
1 | function final = smallworld(n, k, beta)
2 | % SMALLWORLD - Generate a small world graph using the "Watts and Strogatz model" as
3 | % described in Watts, D.J.; Strogatz, S.H.: "Collective dynamics of
4 | % 'small-world' networks."
5 | % A graph with n*k/2 edges is constructed, i.e. the nodal degree is n*k for
6 | % every node.
7 | %
8 | % Inputs:
9 | % n: number of nodes of the graph to be generated
10 | % k: mean degree (assumed to be an even integer)
11 | % beta: rewiring probability
12 | %
13 | % Outputs:
14 | % final: sparse symmetric adjacency matrix representing the generated graph
15 |
16 | %------------- BEGIN CODE --------------
17 |
18 | % Construct a regular lattice: a graph with n nodes, each connected to k
19 | % neighbors, k/2 on each side.
20 | kHalf = k/2;
21 | rows = reshape(repmat([1:n]', 1, k), n*k, 1);
22 | columns = rows+reshape(repmat([[1:kHalf] [n-kHalf:n-1]], n, 1), n*k, 1);
23 | columns = mod(columns-1, n) + 1;
24 | B = sparse(rows, columns, ones(n*k, 1));
25 | A = sparse([], [], [], n, n);
26 |
27 | % With probability beta rewire an edge avoiding loops and link duplication.
28 | % Until step i, only the columns 1:i are generated making implicit use of A's
29 | % symmetry.
30 | for i = [1:n]
31 | % The i-th column is stored full for fast access inside the following loop.
32 | col= [full(A(i, 1:i-1))'; full(B(i:end, i))];
33 | for j = i+find(col(i+1:end))'
34 | if (rand()