├── 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()