├── Code ├── Microgrid_Task1.m ├── Microgrid_Task_2.m ├── conl_param.m ├── cost_functions.m ├── generator_param.m ├── quadratic_function.m ├── storage_param.m └── trading_param.m ├── Distributed_Dual_GT_Microgrid_Control.pdf └── README.md /Code/Microgrid_Task1.m: -------------------------------------------------------------------------------- 1 | % 2 | % Distributed Control System 3 | % Course Project 2020 4 | % Distributed Dual Gradient Tracking for Microgrid Control 5 | % 6 | % Task 1 7 | % 8 | % Bologna, 24/01/2020 9 | % 10 | 11 | %% Initialization 12 | clear all; 13 | clc; close all; 14 | rng(1) 15 | 16 | NN = 5; 17 | 18 | p = 0.1; 19 | I_NN = eye(NN,NN); 20 | notI = ~I_NN; 21 | 22 | %% Graph creation 23 | 24 | while 1 25 | Adj = binornd(1,p,NN,NN); % Randomly generated matrix 26 | 27 | Adj = Adj.*notI; % Set diagonal to 0 (remove self-loops) 28 | Adj = or(Adj,Adj'); % Symmetrize 29 | 30 | % Test connection 31 | test = (I_NN+Adj)^NN; 32 | if ~any(any(~test)) 33 | fprintf('the graph is connected\n'); 34 | break 35 | else 36 | fprintf('the graph is not connected\n'); 37 | end 38 | end 39 | 40 | % Doubly stochastic 41 | 42 | DEGREE = sum(Adj); 43 | WW = zeros(NN,NN); 44 | 45 | for ii = 1:NN 46 | N_ii = find(Adj(:,ii) == 1)'; 47 | for jj = N_ii 48 | WW(ii,jj) = 1/(1 + max(DEGREE(ii),DEGREE(jj) )); 49 | end 50 | WW(ii,ii) = 1 - sum(WW(ii,:)); 51 | end 52 | 53 | %% Quadratic cost parameters initialization 54 | 55 | % q_i(x) = - (x^T Q_i x + R_i^T x) 56 | % grad_q_i(x) = - (2*(Q_i+Q_i^T) x + R_i) 57 | % we change the problem to a minimazion one considering -q(x) instead of 58 | % q(x) 59 | 60 | SS = 3; % x in R^S 61 | 62 | QQ = zeros(SS,SS,NN); 63 | RR = zeros(SS,NN); 64 | a = 1; b = 10; 65 | c = -5; d = 5; 66 | for ii = 1:NN 67 | diag_matrix = diag((b-a)*rand(SS,1) + a); % entries unif. in [a,b] 68 | T = orth(rand(SS,SS)); % change of coordinates 69 | QQ(:,:,ii) = T*diag_matrix*T'; 70 | QQ(:,:,ii) = (QQ(:,:,ii)'+QQ(:,:,ii))/2; % Symmetrize 71 | 72 | RR(:,ii) = (d-c)*rand(SS,1) + c; % entries unif. in [c,d] 73 | end 74 | 75 | %% Centralized solution 76 | 77 | QQ_centr = sum(QQ,3); %summing over the last column the elements of QQ 78 | RR_centr = sum(RR,2); 79 | 80 | % min_x q = - \sum q_i = x^T (sum_i Q_i) x + ( sum_i R_i)^T*x 81 | [xopt,qopt] = quadprog(2*QQ_centr,RR_centr); 82 | 83 | %% Distributed setup 84 | 85 | MAXITERS = 1e4; 86 | 87 | XX = zeros(SS,NN,MAXITERS); 88 | YY = zeros(SS,NN,MAXITERS); 89 | 90 | values = zeros(MAXITERS,1); 91 | consensus_err = zeros(MAXITERS,1); 92 | tracking_err = zeros(MAXITERS,1); 93 | 94 | x_init = rand(SS,NN); 95 | XX(:,:,1) = x_init; 96 | 97 | % initialize the tracker YY 98 | for ii=1:NN 99 | [~,YY(:,ii,1)] = quadratic_function(XX(:,ii,1),QQ(:,:,ii),RR(:,ii)); 100 | end 101 | % initialization of a constant stepsize 102 | gamma = 1*1e-3; 103 | 104 | for tt = 1:MAXITERS-1 105 | fprintf('iteration %d\n',tt); 106 | 107 | % Solution estimate update 108 | for ii=1:NN 109 | N_ii = find(Adj(:,ii) == 1)'; 110 | 111 | % x_i^t+1 = sum_{j \in N_i U { i } } w_ij x_j^t - gamma* y_i^t 112 | XX(:,ii,tt+1) = WW(ii,ii)*XX(:,ii,tt); 113 | 114 | for jj = N_ii 115 | XX(:,ii,tt+1) = XX(:,ii,tt+1) + WW(ii,jj)*XX(:,jj,tt); 116 | end 117 | 118 | XX(:,ii,tt+1) = XX(:,ii,tt+1) - gamma*YY(:,ii,tt); 119 | end 120 | 121 | % Tracker update 122 | for ii=1:NN 123 | N_ii = find(Adj(:,ii) == 1)'; 124 | 125 | YY(:,ii,tt+1) = WW(ii,ii)*YY(:,ii,tt); 126 | 127 | for jj = N_ii 128 | YY(:,ii,tt+1) = YY(:,ii,tt+1) + WW(ii,jj)*YY(:,jj,tt); 129 | end 130 | 131 | [~,grad_f_ii_new] = quadratic_function(XX(:,ii,tt+1),QQ(:,:,ii),RR(:,ii)); 132 | [~,grad_f_ii_old] = quadratic_function(XX(:,ii,tt), QQ(:,:,ii),RR(:,ii)); 133 | 134 | YY(:,ii,tt+1) = YY(:,ii,tt+1) + (grad_f_ii_new-grad_f_ii_old); 135 | end 136 | 137 | % Performance check 138 | XX_avg = mean(XX(:,:,tt),2); 139 | YY_avg = mean(YY(:,:,tt),2); 140 | 141 | for ii=1:NN 142 | [q_ii,~] = quadratic_function(XX(:,ii,tt),QQ(:,:,ii),RR(:,ii)); 143 | values(tt) = values(tt) + q_ii; 144 | consensus_err(tt) = consensus_err(tt) + norm(XX(:,ii,tt) - XX_avg); 145 | tracking_err(tt) = tracking_err(tt) + norm(YY(:,ii,tt) - YY_avg); 146 | end 147 | end 148 | 149 | % Last value [for plot] 150 | tt = MAXITERS; 151 | XX_avg = mean(XX(:,:,tt),2); 152 | YY_avg = mean(YY(:,:,tt),2); 153 | 154 | for ii=1:NN 155 | q_ii = quadratic_function(XX(:,ii,tt),QQ(:,:,ii),RR(:,ii)); 156 | values(tt) = values(tt) + q_ii; 157 | consensus_err(tt) = consensus_err(tt) + norm(XX(:,ii,tt) - XX_avg); 158 | tracking_err(tt) = tracking_err(tt) + norm(YY(:,ii,tt) - YY_avg); 159 | end 160 | 161 | %% Plot of the results 162 | 163 | figure 164 | semilogy(1:MAXITERS,abs(values(1:MAXITERS)-qopt), 'LineWidth',2); 165 | hold on, grid on 166 | xlabel('t') 167 | ylabel('cost error') 168 | 169 | figure 170 | semilogy(1:MAXITERS,consensus_err(1:MAXITERS), 'LineWidth',2); 171 | hold on, grid on 172 | xlabel('t') 173 | ylabel('consensus error') 174 | 175 | figure 176 | semilogy(1:MAXITERS,tracking_err(1:MAXITERS), 'LineWidth',2); 177 | hold on, grid on 178 | xlabel('t') 179 | ylabel('tracking error') 180 | 181 | 182 | figure 183 | plot(1:MAXITERS, squeeze(XX(1,:,1:MAXITERS)),'LineWidth',2); 184 | hold on, grid on 185 | plot(1:MAXITERS, xopt(1)*ones(MAXITERS,1),'--','LineWidth',2); 186 | hold on, grid on 187 | plot(1:MAXITERS, squeeze(XX(2,:,1:MAXITERS)),'LineWidth',2); 188 | hold on, grid on 189 | plot(1:MAXITERS, xopt(2)*ones(MAXITERS,1),'--','LineWidth',2); 190 | hold on, grid on 191 | plot(1:MAXITERS, squeeze(XX(3,:,1:MAXITERS)),'LineWidth',2); 192 | hold on, grid on 193 | plot(1:MAXITERS, xopt(3)*ones(MAXITERS,1),'--','LineWidth',2); 194 | xlabel('t') 195 | ylabel('x_i^t, x^*') 196 | 197 | 198 | -------------------------------------------------------------------------------- /Code/Microgrid_Task_2.m: -------------------------------------------------------------------------------- 1 | % Distributed Control System 2 | % Course Project 2020 3 | % Distributed Dual Gradient Tracking for Microgrid Control 4 | % 5 | % Task 2 6 | % Version 10 7 | % 8 | % Bologna, 10/02/2020 9 | % 10 | clear all; 11 | clc; close all; 12 | rng(1) 13 | 14 | %% General initializations 15 | 16 | GG = 4; %number of GENERATORS in the Network 17 | SS = 3; %number of STORAGES in the Network 18 | CC = 2; %number of CONTROLLABLE_LOADs in the Network 19 | NN = GG+SS+CC+1; %total number of nodes in the Network 20 | TT = 12; % p_i in R^(T+1) 21 | 22 | p = 0.1; 23 | I_NN = eye(NN,NN); 24 | notI = ~I_NN; 25 | 26 | %% Graph creation 27 | 28 | while 1 29 | Adj = binornd(1,p,NN,NN); % Randomly generated matrix 30 | 31 | Adj = Adj.*notI; % Set diagonal to 0 (remove self-loops) 32 | Adj = or(Adj,Adj'); % Symmetrize 33 | 34 | % Test connection 35 | test = (I_NN+Adj)^NN; 36 | if ~any(any(~test)) 37 | fprintf('the graph is connected\n'); 38 | break 39 | else 40 | fprintf('the graph is not connected\n'); 41 | end 42 | end 43 | 44 | % Doubly stochastic 45 | 46 | DEGREE = sum(Adj); 47 | WW = zeros(NN,NN); 48 | 49 | for ii = 1:NN 50 | N_ii = find(Adj(:,ii) == 1)'; 51 | for jj = N_ii 52 | WW(ii,jj) = 1/(1 + max(DEGREE(ii),DEGREE(jj) )); 53 | end 54 | WW(ii,ii) = 1 - sum(WW(ii,:)); 55 | end 56 | %% Definition of the Network 57 | 58 | % Matrices for Centralized Solution 59 | AA_tot = []; 60 | bb_tot = []; 61 | QQ_centr = []; 62 | RR_centr = []; 63 | 64 | % Matrices for the Cost Functions 65 | QQ_g =[]; 66 | RR_g =[]; 67 | QQ_s =[]; 68 | RR_s =[]; 69 | QQ_c =[]; 70 | RR_c =[]; 71 | 72 | % Matrices for the Local Constraints 73 | AA_g =[]; 74 | bb_g =[]; 75 | AA_s =[]; 76 | bb_s =[]; 77 | AA_c =[]; 78 | bb_c =[]; 79 | 80 | %% GENERATORS parameters initialization 81 | 82 | % [AA_tot,bb_tot,QQ_centr,RR_centr] = generator_param(GG,alpha1,alpha2,ub_1_g,lb_2_g,ub_3_g,lb_4_g); 83 | [AA_tot,bb_tot,QQ_centr,RR_centr,AA_g,bb_g,QQ_g,RR_g] = generator_param(TT,GG,1,1,5,-1,5,-1,AA_tot,bb_tot,QQ_centr,RR_centr); 84 | 85 | %% STORAGEs parameters initialization 86 | 87 | % [AA_tot,bb_tot,QQ_centr,RR_centr] = storage_param(SS,epsilon,ub_1_s,lb_2_s,ub_3_s,lb_4_s); 88 | [AA_tot,bb_tot,QQ_centr,RR_centr,AA_s,bb_s,QQ_s,RR_s] = storage_param(TT,SS,1,3,-0.5,4,0,AA_tot,bb_tot,QQ_centr,RR_centr); 89 | 90 | %% CONTROLLABLE_LOADs parameters initialization 91 | 92 | % [AA_tot,bb_tot,QQ_centr,RR_centr,AA_c,bb_c,QQ_c,RR_c] = conl_param(TT,CC,epsilon,beta,P_des,P_bound,AA_tot_in,bb_tot_in,QQ_centr_in,RR_centr_in) 93 | time = [0:TT-1]; 94 | P_des = []; 95 | for ii=1:CC 96 | P_des = [P_des,(sin(time)+1*rand)']; 97 | end 98 | 99 | [AA_tot,bb_tot,QQ_centr,RR_centr,AA_c,bb_c,QQ_c,RR_c] = conl_param(TT,CC,2,3,P_des,5,AA_tot,bb_tot,QQ_centr,RR_centr); 100 | 101 | %% POWER TRADING COST parameter initialization 102 | 103 | %[AA_tot,bb_tot,QQ_centr,RR_centr,AA_t,bb_t,QQ_t,RR_t] = trading_param(TT,epsilon,c1,c2,E,AA_tot_in,bb_tot_in,QQ_centr_in,RR_centr_in) 104 | [AA_tot,bb_tot,QQ_centr,RR_centr,AA_t,bb_t,QQ_t,RR_t] = trading_param(TT,1,2,3,5,AA_tot,bb_tot,QQ_centr,RR_centr); 105 | 106 | %% Centralized solution 107 | options_qp = optimoptions('quadprog','Display','none'); 108 | 109 | % min_p f = \sum f_i(p_i) = p_i^T Q_i x + R_i^T p_i) 110 | % subject to [1...1]*[p_1 ... p_N]^T = 0 (globabl constraints) 111 | % p_i belonging to X_i (local constraints) 112 | 113 | %definition of the EQUALITY constraint (in our case: coupling 114 | %constraints) 115 | 116 | % Construction of AA_eq for the GENERATORS 117 | aux_r_g = zeros(1,2*GG*TT); 118 | aux_r_g(1,1)=1; 119 | for ii=1:(GG-1) 120 | aux_r_g(1,(ii*(2*TT))+1)=1; 121 | end 122 | AA_eq_g(1,:) = aux_r_g; 123 | for ii=1:(TT-1) 124 | AA_eq_g(ii+1,:) = circshift(aux_r_g,ii); 125 | end 126 | 127 | %Construction of AA_eq for the STORAGES 128 | aux_r_s = zeros(1,2*SS*TT); 129 | aux_r_s(1,1)=1; 130 | for ii=1:(SS-1) 131 | aux_r_s(1,(ii*(2*TT))+1)=1; 132 | end 133 | AA_eq_s(1,:) = aux_r_s; 134 | for ii=1:(TT-1) 135 | AA_eq_s(ii+1,:) = circshift(aux_r_s,ii); 136 | end 137 | 138 | % Construction of AA_eq for the CONTROLLABLE_LOADs 139 | aux_r_c = zeros(1,2*CC*TT); 140 | aux_r_c(1,1)=1; 141 | for ii=1:(CC-1) 142 | aux_r_c(1,(ii*(2*TT))+1)=1; 143 | end 144 | AA_eq_c(1,:) = aux_r_c; 145 | for ii=1:(TT-1) 146 | AA_eq_c(ii+1,:) = circshift(aux_r_c,ii); 147 | end 148 | 149 | % Construction of AA_eq for the POWER TRADING COST (only last agent) 150 | AA_eq_t = [eye(TT,TT),zeros(TT,TT)]; 151 | 152 | % Costruction of Final AA_eq and DD (that is the b for quadprog!) 153 | AA_eq = [AA_eq_g,AA_eq_s,AA_eq_c,AA_eq_t]; %to be modified 154 | 155 | time = [0:TT-1]; 156 | DD = (sin(time)+5)'; 157 | 158 | %Definition of the CENTRALIZED OPTIMIZATION 159 | [zopt,fopt,exit_flag] = quadprog(2*QQ_centr,RR_centr,AA_tot,bb_tot,AA_eq,DD,[],[],[],options_qp); 160 | 161 | if exit_flag ~= 1 162 | fprintf(2,'The problem %.4g problem occurred in the centralized solution\n',exit_flag); 163 | return; 164 | end 165 | 166 | fprintf('Centralized optimal cost is %.4g\n',fopt); 167 | 168 | %Extraction of Popt from the augmented state variable Zopt 169 | popt = []; 170 | popt(1:TT,1)=zopt(1:TT,1); 171 | for ii=1:NN-1 172 | popt=[popt;zopt((ii*2*TT)+1:(ii*2*TT)+TT,1)]; 173 | end 174 | 175 | %% Distributed solution 176 | 177 | % Initializations 178 | MAXITERS = 15*1e3; 179 | 180 | LMD = rand(TT,NN,MAXITERS); 181 | PP = zeros(TT,NN,MAXITERS); 182 | dd = zeros(TT,NN,MAXITERS); 183 | 184 | ZZ = zeros(2*TT,CC,MAXITERS); %variables for CONLs 185 | 186 | KK = zeros(2*TT,MAXITERS); %variable for POWER TRADING COST 187 | 188 | primal_cost = zeros(MAXITERS,1); 189 | dual_cost = zeros(MAXITERS,1); 190 | 191 | consensus_err = zeros(MAXITERS,1); 192 | tracking_err = zeros(MAXITERS,1); 193 | state_diff = zeros(MAXITERS,1); 194 | feasibility = zeros(TT,MAXITERS); 195 | 196 | LMD_init = rand(TT,NN); 197 | LMD(:,:,1)= LMD_init; 198 | 199 | %State initialization 200 | for ii= 1:GG 201 | p_init = quadprog(2*QQ_g(:,:,ii),RR_g(:,ii),AA_g(:,:,ii),bb_g(:,ii),[],[],[],[],[],options_qp); 202 | PP(:,ii,1) = p_init; 203 | end 204 | for ii= GG+1:SS+GG 205 | p_init = quadprog(2*QQ_s(:,:,ii-GG),RR_s(:,ii-GG),AA_s(:,:,ii-GG),bb_s(:,ii-GG),[],[],[],[],[],options_qp); 206 | PP(:,ii,1) = p_init; 207 | end 208 | for ii= GG+SS+1:NN-1 209 | ZZ(:,ii-GG-SS,1) = quadprog(2*QQ_c(:,:,ii-GG-SS),RR_c(:,ii-GG-SS),AA_c(:,:,ii-GG-SS),bb_c(:,ii-GG-SS),[],[],[],[],[],options_qp); 210 | p_init = ZZ(1:TT,ii-GG-SS,1); 211 | PP(:,ii,1) = p_init; 212 | end 213 | KK(:,1) = quadprog(2*QQ_t,RR_t,AA_t,bb_t,[],[],[],[],[],options_qp); 214 | p_init = KK(1:TT,1); 215 | PP(:,NN,1) = p_init; 216 | 217 | %Gradient initialization 218 | for ii = 1:NN-1 219 | dd(:,ii,1)=PP(:,ii,1); 220 | end 221 | dd(:,NN,1)=PP(:,NN,1)-DD; 222 | 223 | %Initialization of a constant stepsize 224 | gamma = 6*1e-3; 225 | 226 | for tt = 1:MAXITERS-1 227 | fprintf('iteration %d\n',tt); 228 | jj=0; 229 | %update of lamda 230 | for ii=1:NN 231 | N_ii = find(Adj(:,ii) == 1)'; 232 | 233 | % LMD_i^t+1 = sum_{j \in N_i U { i } } w_ij LMD_j^t + gamma dd_i^t 234 | LMD(:,ii,tt+1) = WW(ii,ii)*LMD(:,ii,tt); %the WW are what we called a_ij 235 | 236 | for jj = N_ii 237 | LMD(:,ii,tt+1) = LMD(:,ii,tt+1) + WW(ii,jj)*LMD(:,jj,tt); 238 | end 239 | 240 | LMD(:,ii,tt+1) = LMD(:,ii,tt+1) + gamma*dd(:,ii,tt); 241 | end 242 | 243 | %update of PP, the state 244 | for ii = 1:GG 245 | PP(:,ii,tt+1) = quadprog(2*QQ_g(:,:,ii),RR_g(:,ii)+LMD(:,ii,tt+1),AA_g(:,:,ii),bb_g(:,ii),[],[],[],[],[],options_qp); 246 | end 247 | for ii = GG+1:SS+GG 248 | PP(:,ii,tt+1) = quadprog(2*QQ_s(:,:,ii-GG),RR_s(:,ii-GG)+LMD(:,ii,tt+1),AA_s(:,:,ii-GG),bb_s(:,ii-GG),[],[],[],[],[],options_qp); 249 | end 250 | for ii = GG+SS+1:NN-1 251 | ZZ(:,ii-GG-SS,tt+1) = quadprog(2*QQ_c(:,:,ii-GG-SS),RR_c(:,ii-GG-SS)+[LMD(:,ii,tt+1);zeros(TT,1)],AA_c(:,:,ii-GG-SS),bb_c(:,ii-GG-SS),[],[],[],[],[],options_qp); 252 | PP(:,ii,tt+1) = ZZ(1:TT,ii-GG-SS,tt+1); 253 | end 254 | KK(:,tt+1) = quadprog(2*QQ_t,RR_t+[LMD(:,NN,tt+1);zeros(TT,1)],AA_t,bb_t,[],[],[],[],[],options_qp); 255 | PP(:,NN,tt+1) = KK(1:TT,tt+1); 256 | 257 | %update of dd, the estimate of the gradient 258 | for ii=1:NN 259 | N_ii = find(Adj(:,ii) == 1)'; 260 | 261 | % dd_i^t+1 = sum_{j \in N_i U { i } } w_ij dd_j^t + (p_i^t+1 - 262 | % p_i^t) 263 | dd(:,ii,tt+1) = WW(ii,ii)*dd(:,ii,tt); %the WW are what we called a_ij 264 | 265 | for jj = N_ii 266 | dd(:,ii,tt+1) = dd(:,ii,tt+1) + WW(ii,jj)*dd(:,jj,tt); 267 | end 268 | 269 | dd(:,ii,tt+1) = dd(:,ii,tt+1) + PP(:,ii,tt+1)- PP(:,ii,tt); 270 | end 271 | 272 | % Performance check 273 | LMD_avg = mean(LMD(:,:,tt),2); 274 | dd_avg = mean(dd(:,:,tt),2); 275 | for ii=1:GG 276 | [ff_ii,~] = cost_functions(PP(:,ii,tt),QQ_g(:,:,ii),RR_g(:,ii)); 277 | primal_cost(tt) = primal_cost(tt) + ff_ii; 278 | 279 | qq_ii = ff_ii + LMD(:,ii,tt)'*(PP(:,ii,tt)); 280 | dual_cost(tt) = dual_cost(tt) + qq_ii; 281 | 282 | tracking_err(tt) = tracking_err(tt) + norm(dd(:,ii,tt) - dd_avg); 283 | consensus_err(tt) = consensus_err(tt) + norm(LMD(:,ii,tt) - LMD_avg); 284 | 285 | state_diff(tt) = state_diff(tt) + norm(PP(:,ii,tt)-popt((1+TT*(ii-1)):(TT*ii))); 286 | feasibility(:,tt) = feasibility(:,tt) + PP(:,ii,tt); 287 | end 288 | for ii=GG+1:SS+GG 289 | [ff_ii,~] = cost_functions(PP(:,ii,tt),QQ_s(:,:,ii-GG),RR_s(:,ii-GG)); 290 | primal_cost(tt) = primal_cost(tt) + ff_ii; 291 | 292 | qq_ii = ff_ii + LMD(:,ii,tt)'*(PP(:,ii,tt)); 293 | dual_cost(tt) = dual_cost(tt) + qq_ii; 294 | 295 | tracking_err(tt) = tracking_err(tt) + norm(dd(:,ii,tt) - dd_avg); 296 | consensus_err(tt) = consensus_err(tt) + norm(LMD(:,ii,tt) - LMD_avg); 297 | 298 | state_diff(tt) = state_diff(tt) + norm(PP(:,ii,tt)-popt((1+TT*(ii-1)):(TT*ii))); 299 | feasibility(:,tt) = feasibility(:,tt) + PP(:,ii,tt); 300 | end 301 | for ii=GG+SS+1:NN-1 302 | [ff_ii,~] = cost_functions(ZZ(:,ii-GG-SS,tt),QQ_c(:,:,ii-GG-SS),RR_c(:,ii-GG-SS)); 303 | primal_cost(tt) = primal_cost(tt) + ff_ii; 304 | 305 | qq_ii = ff_ii + LMD(:,ii,tt)'*(PP(:,ii,tt)); 306 | dual_cost(tt) = dual_cost(tt) + qq_ii; 307 | 308 | tracking_err(tt) = tracking_err(tt) + norm(dd(:,ii,tt) - dd_avg); 309 | consensus_err(tt) = consensus_err(tt) + norm(LMD(:,ii,tt) - LMD_avg); 310 | 311 | state_diff(tt) = state_diff(tt) + norm(PP(:,ii,tt)-popt((1+TT*(ii-1)):(TT*ii))); 312 | feasibility(:,tt) = feasibility(:,tt) + PP(:,ii,tt); 313 | end 314 | [ff_ii,~] = cost_functions(KK(:,tt),QQ_t,RR_t); 315 | primal_cost(tt) = primal_cost(tt) + ff_ii; 316 | qq_ii = ff_ii + LMD(:,NN,tt)'*((PP(:,NN,tt))-DD); 317 | dual_cost(tt) = dual_cost(tt) + qq_ii; 318 | 319 | tracking_err(tt) = tracking_err(tt) + norm(dd(:,NN,tt) - dd_avg); 320 | consensus_err(tt) = consensus_err(tt) + norm(LMD(:,NN,tt) - LMD_avg); 321 | 322 | state_diff(tt) = state_diff(tt) + norm(PP(:,NN,tt)-popt((1+TT*(NN-1)):(TT*NN))); 323 | feasibility(:,tt) = feasibility(:,tt) + PP(:,NN,tt)-DD; 324 | end 325 | 326 | for ii=1:GG 327 | 328 | [ff_ii,~] = cost_functions(PP(:,ii,MAXITERS),QQ_g(:,:,ii),RR_g(:,ii)); 329 | 330 | 331 | primal_cost(MAXITERS) = primal_cost(MAXITERS) + ff_ii; 332 | 333 | qq_ii = ff_ii + LMD(:,ii,MAXITERS)'*(PP(:,ii,MAXITERS)); 334 | dual_cost(MAXITERS) = dual_cost(MAXITERS) + qq_ii; 335 | 336 | tracking_err(MAXITERS) = tracking_err(MAXITERS) + norm(dd(:,ii,MAXITERS) - dd_avg); 337 | consensus_err(MAXITERS) = consensus_err(MAXITERS) + norm(LMD(:,ii,MAXITERS) - LMD_avg); 338 | 339 | state_diff(MAXITERS) = state_diff(MAXITERS) + norm(PP(:,ii,MAXITERS)-popt((1+TT*(ii-1)):(TT*ii))); 340 | feasibility(:,MAXITERS) = feasibility(:,MAXITERS) + PP(:,ii,MAXITERS); 341 | end 342 | for ii=GG+1:SS+GG 343 | 344 | [ff_ii,~] = cost_functions(PP(:,ii,MAXITERS),QQ_s(:,:,ii-GG),RR_s(:,ii-GG)); 345 | 346 | 347 | primal_cost(MAXITERS) = primal_cost(MAXITERS) + ff_ii; 348 | 349 | qq_ii = ff_ii + LMD(:,ii,MAXITERS)'*(PP(:,ii,MAXITERS)); 350 | dual_cost(MAXITERS) = dual_cost(MAXITERS) + qq_ii; 351 | 352 | tracking_err(MAXITERS) = tracking_err(MAXITERS) + norm(dd(:,ii,MAXITERS) - dd_avg); 353 | consensus_err(MAXITERS) = consensus_err(MAXITERS) + norm(LMD(:,ii,MAXITERS) - LMD_avg); 354 | 355 | state_diff(MAXITERS) = state_diff(MAXITERS) + norm(PP(:,ii,MAXITERS)-popt((1+TT*(ii-1)):(TT*ii))); 356 | feasibility(:,MAXITERS) = feasibility(:,MAXITERS) + PP(:,ii,MAXITERS); 357 | end 358 | for ii=GG+SS+1:NN-1 359 | 360 | [ff_ii,~] = cost_functions(ZZ(:,ii-GG-SS,MAXITERS),QQ_c(:,:,ii-GG-SS),RR_c(:,ii-GG-SS)); 361 | 362 | 363 | primal_cost(MAXITERS) = primal_cost(MAXITERS) + ff_ii; 364 | 365 | qq_ii = ff_ii + LMD(:,ii,MAXITERS)'*(PP(:,ii,MAXITERS)); 366 | dual_cost(MAXITERS) = dual_cost(MAXITERS) + qq_ii; 367 | 368 | tracking_err(MAXITERS) = tracking_err(MAXITERS) + norm(dd(:,ii,MAXITERS) - dd_avg); 369 | consensus_err(MAXITERS) = consensus_err(MAXITERS) + norm(LMD(:,ii,MAXITERS) - LMD_avg); 370 | 371 | state_diff(MAXITERS) = state_diff(MAXITERS) + norm(PP(:,ii,MAXITERS)-popt((1+TT*(ii-1)):(TT*ii))); 372 | feasibility(:,MAXITERS) = feasibility(:,MAXITERS) + PP(:,ii,MAXITERS); 373 | end 374 | [ff_ii,~] = cost_functions(KK(:,MAXITERS),QQ_t,RR_t); 375 | primal_cost(MAXITERS) = primal_cost(MAXITERS) + ff_ii; 376 | qq_ii = ff_ii + LMD(:,NN,MAXITERS)'*((PP(:,NN,MAXITERS))-DD); 377 | dual_cost(MAXITERS) = dual_cost(MAXITERS) + qq_ii; 378 | 379 | tracking_err(MAXITERS) = tracking_err(MAXITERS) + norm(dd(:,NN,MAXITERS) - dd_avg); 380 | consensus_err(MAXITERS) = consensus_err(MAXITERS) + norm(LMD(:,NN,MAXITERS) - LMD_avg); 381 | 382 | state_diff(MAXITERS) = state_diff(MAXITERS) + norm(PP(:,NN,MAXITERS)-popt((1+TT*(NN-1)):(TT*NN))); 383 | 384 | feasibility(:,MAXITERS) = feasibility(:,MAXITERS) + PP(:,NN,MAXITERS)-DD; 385 | 386 | 387 | 388 | %% 389 | figure 390 | semilogy(1:MAXITERS,abs(primal_cost(1:MAXITERS)-fopt), 'LineWidth',2); 391 | hold on, grid on, zoom on 392 | semilogy(1:MAXITERS,abs(dual_cost(1:MAXITERS)-fopt), 'LineWidth',2); 393 | xlabel('t') 394 | ylabel('cost error') 395 | legend('primal cost','dual cost') 396 | 397 | %% 398 | figure 399 | semilogy(1:MAXITERS,state_diff(1:MAXITERS), 'LineWidth',2); 400 | hold on, grid on 401 | xlabel('t') 402 | ylabel('state error') 403 | %% 404 | figure 405 | semilogy(1:MAXITERS-1,consensus_err(1:MAXITERS-1), 'LineWidth',2); 406 | hold on, grid on, zoom on 407 | xlabel('t') 408 | ylabel('consensus error') 409 | 410 | %% 411 | figure 412 | semilogy(1:MAXITERS,tracking_err(1:MAXITERS), 'LineWidth',2); 413 | hold on, grid on 414 | xlabel('t') 415 | ylabel('tracking error') 416 | 417 | 418 | %% 419 | feasibile_norm = []; 420 | for ii=1:MAXITERS 421 | feasibile_norm(ii) = norm(feasibility(:,ii)); 422 | end 423 | figure 424 | semilogy(1:MAXITERS,feasibile_norm(1:MAXITERS), 'LineWidth',2); 425 | hold on, grid on 426 | xlabel('t') 427 | ylabel('|| p_1 + ... + p_N - D ||') 428 | 429 | 430 | -------------------------------------------------------------------------------- /Code/conl_param.m: -------------------------------------------------------------------------------- 1 | function [AA_tot,bb_tot,QQ_centr,RR_centr,AA_c,bb_c,QQ_c,RR_c] = conl_param(TT,CC,epsilon,beta,P_des,P_bound,AA_tot_in,bb_tot_in,QQ_centr_in,RR_centr_in) 2 | % CONTROLLABE LOAD parameters initialization 3 | % Given the function and gradient for the CONLs: 4 | % f_i(p_i) = p_i^T Q_i p_i + R_i^T p_i) 5 | % grad_f_i(p_i) = (Q_i+Q_i^T) p_i + R_i) 6 | % This function RETURNS the matrices (consider quadprog): 7 | % AA_tot --> block diagonal matrix, describes the unequality constraint A 8 | % bb_tot --> column vector, describes the unequality constraint b 9 | % QQ_centr --> block diagonal matrix, describe the cost function matrix Q 10 | % RR_centr --> matrix, describe the cost function matrix R 11 | % 12 | % Good values for the inputs are: 13 | % epsilon = 2 14 | % beta = 3 15 | % P_bound = 5 16 | 17 | 18 | % Matrices QQ and RR of the cost function for the CONTROLLABLE_LOADs 19 | aux = zeros(2*TT,2*TT); 20 | for ii=1:TT 21 | aux(ii,ii) = epsilon; 22 | end 23 | 24 | QQ_c = repmat(aux, 1,1,CC); 25 | RR_c = repmat([zeros(TT,1);beta*ones(TT,1)],1,CC); 26 | 27 | % Constraints matrix creation 28 | AA_1_c = repmat(-[eye(TT,TT),eye(TT,TT)], 1,1,CC); 29 | bb_1_c = P_des; %P_des must be of dimension (TT)*CC and it must be given in input 30 | 31 | AA_2_c = repmat(-[zeros(TT,TT),eye(TT,TT)], 1,1,CC); 32 | bb_2_c = zeros(TT,CC); 33 | 34 | AA_3_c = repmat([eye(TT,TT),zeros(TT,TT)], 1,1,CC); 35 | bb_3_c = P_bound*ones(TT,CC); 36 | 37 | AA_4_c = repmat(-[eye(TT,TT),zeros(TT,TT)], 1,1,CC); 38 | bb_4_c = P_bound*ones(TT,CC); 39 | 40 | AA_tot = AA_tot_in; 41 | bb_tot = bb_tot_in; 42 | QQ_centr = QQ_centr_in; 43 | RR_centr = RR_centr_in; 44 | 45 | % Matrices containing the local constraints for CONTROLLABLE_LOADs 46 | AA_c = [AA_1_c;AA_2_c;AA_3_c;AA_4_c]; 47 | bb_c = [bb_1_c;bb_2_c;bb_3_c;bb_4_c]; 48 | 49 | % Matrices for the CENTRALIZED SOLUTION 50 | for i = 1:CC 51 | AA_tot = blkdiag(AA_tot,[AA_1_c(:,:,i);AA_2_c(:,:,i);AA_3_c(:,:,i);AA_4_c(:,:,i)]); 52 | bb_tot = [bb_tot;bb_1_c(:,i);bb_2_c(:,i);bb_3_c(:,i);bb_4_c(:,i)]; 53 | QQ_centr = blkdiag(QQ_centr,QQ_c(:,:,i)); 54 | RR_centr = [RR_centr;RR_c(:,i)]; 55 | end 56 | 57 | end -------------------------------------------------------------------------------- /Code/cost_functions.m: -------------------------------------------------------------------------------- 1 | function [f_val,f_grad] = cost_functions(p,Q,r) 2 | %function only of the GENERATOR 3 | f_val = p'*Q*p+r'*p; 4 | f_grad = (Q+Q')*p+r; %attention 5 | end -------------------------------------------------------------------------------- /Code/generator_param.m: -------------------------------------------------------------------------------- 1 | function [AA_tot,bb_tot,QQ_centr,RR_centr,AA_g,bb_g,QQ_g,RR_g] = generator_param(TT,GG,alpha1,alpha2,ub_1_g,lb_2_g,ub_3_g,lb_4_g,AA_tot_in,bb_tot_in,QQ_centr_in,RR_centr_in) 2 | % GENERATORS parameters initialization 3 | % Given the function and gradient for the Generators: 4 | % f_i(p_i) = p_i^T Q_i p_i + R_i^T p_i) 5 | % grad_f_i(p_i) = (Q_i+Q_i^T) p_i + R_i) 6 | % This function RETURNS the matrices (consider quadprog): 7 | % AA_tot --> block diagonal matrix, describes the unequality constraint A 8 | % bb_tot --> column vector, describes the unequality constraint b 9 | % QQ_centr --> block diagonal matrix, describe the cost function matrix Q 10 | % RR_centr --> matrix, describe the cost function matrix R 11 | % 12 | % Good values for the inputs are: 13 | % alpha1 = 1 14 | % alpha1 = 2 15 | % ub_1_g = 5 16 | % lb_2_g = -1 17 | % ub_3_g = 5 18 | % lb_4_g = -1 19 | 20 | % Matrices RR and QQ for the cost function of the GENERATORS 21 | RR_g = alpha1*ones(TT,GG); 22 | QQ_g = repmat(alpha2*eye(TT,TT), 1,1,GG); 23 | 24 | % Constraints matrix creation 25 | AA_1_g = repmat(eye(TT,TT), 1,1,GG); 26 | bb_1_g = ub_1_g*ones(TT,GG); 27 | 28 | AA_2_g = repmat(-1*eye(TT,TT), 1,1,GG); 29 | bb_2_g = -1*lb_2_g*ones(TT,GG); 30 | 31 | Aux = -1*eye(TT-1,TT) + (triu(ones(TT-1,TT),1)-triu(ones(TT-1,TT),2)); 32 | AA_3_g = repmat(Aux, 1,1,GG); 33 | bb_3_g = ub_3_g*ones(TT-1,GG); 34 | 35 | AA_4_g = repmat(-Aux, 1,1,GG); 36 | bb_4_g = -1*lb_4_g*ones(TT-1,GG); 37 | 38 | AA_tot = AA_tot_in; 39 | bb_tot = bb_tot_in; 40 | QQ_centr = QQ_centr_in; 41 | RR_centr = RR_centr_in; 42 | 43 | % Matrices containing the local constraints for GENERATORS 44 | AA_g = [AA_1_g;AA_2_g;AA_3_g;AA_4_g]; 45 | bb_g = [bb_1_g;bb_2_g;bb_3_g;bb_4_g]; 46 | 47 | % Matrices for the CENTRALIZED SOLUTION 48 | for i = 1:GG 49 | AA_tot = blkdiag(AA_tot,[blkdiag(AA_1_g(:,:,i),zeros(TT,TT));blkdiag(AA_2_g(:,:,i),zeros(TT,TT));blkdiag(AA_3_g(:,:,i),zeros(TT-1,TT));blkdiag(AA_4_g(:,:,i),zeros(TT-1,TT))]); 50 | bb_tot = [bb_tot;bb_1_g(:,i);zeros(TT,1);bb_2_g(:,i);zeros(TT,1);bb_3_g(:,i);zeros(TT-1,1);bb_4_g(:,i);zeros(TT-1,1)]; 51 | QQ_centr = blkdiag(QQ_centr,QQ_g(:,:,i),zeros(TT,TT)); %we added 0s to consider also the Y of the CONL 52 | RR_centr = [RR_centr;RR_g(:,i);zeros(TT,1)]; %we added 0s to consider also the Y of the CONL 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /Code/quadratic_function.m: -------------------------------------------------------------------------------- 1 | function [f_val,f_grad] = quadratic_function(x,Q,r) 2 | f_val = x'*Q*x+r'*x; 3 | f_grad = 2*Q*x+r; 4 | end -------------------------------------------------------------------------------- /Code/storage_param.m: -------------------------------------------------------------------------------- 1 | function [AA_tot,bb_tot,QQ_centr,RR_centr,AA_s,bb_s,QQ_s,RR_s] = storage_param(TT,SS,epsilon,ub_1_s,lb_2_s,ub_3_s,lb_4_s,AA_tot_in,bb_tot_in,QQ_centr_in,RR_centr_in) 2 | % STORAGE parameters initialization 3 | % Given the function and gradient for the Storage: 4 | % f_i(p_i) = p_i^T Q_i p_i 5 | % grad_f_i(p_i) = (Q_i+Q_i^T) p_i 6 | % This function RETURNS the matrices (consider quadprog): 7 | % AA_tot --> block diagonal matrix, describes the unequality constraint A 8 | % bb_tot --> column vector, describes the unequality constraint b 9 | % QQ_centr --> block diagonal matrix, describe the cost function matrix Q 10 | % RR_centr --> matrix, describe the cost function matrix R 11 | % 12 | % Good values for the inputs are: 13 | % epsilon = 1 14 | % ub_1_s = 3 15 | % lb_2_s = -0.5 16 | % ub_3_s = 4 17 | % lb_4_s = 0 18 | 19 | % Matrices QQ and RR of the cost function for the STORAGS 20 | QQ_s = repmat(epsilon*eye(TT,TT), 1,1,SS); 21 | RR_s = zeros(TT,SS); 22 | 23 | % Constraints matrix creation 24 | AA_1_s = repmat(eye(TT,TT), 1,1,SS); 25 | bb_1_s = ub_1_s*ones(TT,SS); 26 | 27 | AA_2_s = repmat(-1*eye(TT,TT), 1,1,SS); 28 | bb_2_s = -lb_2_s*ones(TT,SS); 29 | 30 | Aux = -1*eye(TT-1,TT) + (triu(ones(TT-1,TT),1)-triu(ones(TT-1,TT),2)); 31 | Aux2 = pinv(Aux); 32 | Aux3 = [eye(TT-1,TT-1),zeros((TT-1),1)]; 33 | AA_3_s = repmat(Aux2*Aux3, 1,1,SS); 34 | bb_3_s = ub_3_s*ones(TT,SS); 35 | 36 | AA_4_s = repmat(-Aux2*Aux3, 1,1,SS); 37 | bb_4_s = lb_4_s*ones(TT,SS); 38 | 39 | AA_tot = AA_tot_in; 40 | bb_tot = bb_tot_in; 41 | QQ_centr = QQ_centr_in; 42 | RR_centr = RR_centr_in; 43 | 44 | % Matrices containing the local constraints for STORAGES 45 | AA_s = [AA_1_s;AA_2_s;AA_3_s;AA_4_s]; 46 | bb_s = [bb_1_s;bb_2_s;bb_3_s;bb_4_s]; 47 | 48 | % Matrices for the CENTRALIZED SOLUTION 49 | for i = 1:SS %we added 0s to consider also the Y of the CONL 50 | AA_tot = blkdiag(AA_tot,[blkdiag(AA_1_s(:,:,i),zeros(TT,TT));blkdiag(AA_2_s(:,:,i),zeros(TT,TT));blkdiag(AA_3_s(:,:,i),zeros(TT,TT));blkdiag(AA_4_s(:,:,i),zeros(TT,TT))]); 51 | bb_tot = [bb_tot;bb_1_s(:,i);zeros(TT,1);bb_2_s(:,i);zeros(TT,1);bb_3_s(:,i);zeros(TT,1);bb_4_s(:,i);zeros(TT,1)]; 52 | QQ_centr = blkdiag(QQ_centr,QQ_s(:,:,i),zeros(TT,TT)); 53 | RR_centr = [RR_centr;RR_s(:,i);zeros(TT,1)]; 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /Code/trading_param.m: -------------------------------------------------------------------------------- 1 | function [AA_tot,bb_tot,QQ_centr,RR_centr,AA_t,bb_t,QQ_t,RR_t] = trading_param(TT,epsilon,c1,c2,E,AA_tot_in,bb_tot_in,QQ_centr_in,RR_centr_in) 2 | % POWER TRADING COST parameters initialization 3 | % Given the function and gradient for the POWER TRADING COST: 4 | % f_i(p_i) = p_i^T Q_i p_i + R_i^T p_i) 5 | % grad_f_i(p_i) = (Q_i+Q_i^T) p_i + R_i) 6 | % This function RETURNS the matrices (consider quadprog): 7 | % AA_tot --> block diagonal matrix, describes the unequality constraint A 8 | % bb_tot --> column vector, describes the unequality constraint b 9 | % QQ_centr --> block diagonal matrix, describe the cost function matrix Q 10 | % RR_centr --> matrix, describe the cost function matrix R 11 | % 12 | % Good values for the inputs are: 13 | % epsilon = 1 14 | % c1 = 2 15 | % c2 = 3 16 | % E = 5 17 | 18 | % Matrices QQ and RR of the cost function for the POWER TRADING COST 19 | aux = zeros(2*TT,2*TT); 20 | for ii=1:TT 21 | aux(ii,ii) = epsilon; 22 | end 23 | 24 | QQ_t = aux; 25 | RR_t = [-c1*ones(TT,1);c2*ones(TT,1)]; 26 | 27 | % Constraints matrix creation 28 | AA_1_t = [eye(TT,TT),-eye(TT,TT)]; 29 | bb_1_t = zeros(TT,1); 30 | 31 | AA_2_t = -[zeros(TT,TT),eye(TT,TT)]; 32 | bb_2_t = zeros(TT,1); 33 | 34 | AA_3_t = [eye(TT,TT),zeros(TT,TT)]; 35 | bb_3_t = E*ones(TT,1); 36 | 37 | AA_4_t = -[eye(TT,TT),zeros(TT,TT)]; 38 | bb_4_t = E*ones(TT,1); 39 | 40 | AA_tot = AA_tot_in; 41 | bb_tot = bb_tot_in; 42 | QQ_centr = QQ_centr_in; 43 | RR_centr = RR_centr_in; 44 | 45 | % Matrices containing the local constraints for POWER TRADING COST 46 | AA_t = [AA_1_t;AA_2_t;AA_3_t;AA_4_t]; 47 | bb_t = [bb_1_t;bb_2_t;bb_3_t;bb_4_t]; 48 | 49 | % Matrices for the CENTRALIZED SOLUTION 50 | 51 | AA_tot = blkdiag(AA_tot,[AA_1_t;AA_2_t;AA_3_t;AA_4_t]); 52 | bb_tot = [bb_tot;bb_1_t;bb_2_t;bb_3_t;bb_4_t]; 53 | QQ_centr = blkdiag(QQ_centr,QQ_t); 54 | RR_centr = [RR_centr;RR_t]; 55 | 56 | 57 | end -------------------------------------------------------------------------------- /Distributed_Dual_GT_Microgrid_Control.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alessandrositta/Distributed_Dual_GT_Microgrid_Control/1081a7c506dc75da0248fb717bfe13b400f4a264/Distributed_Dual_GT_Microgrid_Control.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Distributed Dual Gradient Tracking for Microgrid Control 2 | 3 | ## Abstract :bookmark_tabs: 4 | Energy efficiency and renewable energy are pushing towards rethinking the idea of grids. Not only conventional power supplies are present nowadays, but also other sources of energy e.g. solar panel, biomass generator and wind turbines. The notion of microgrid enters here, as a localized group of electricity sources and sinks that operates with macrogrid. The main advantageous point is that the microgrid can operate autonomously from the conventional power generators. In other words, it represents a distributed energy resources and loads that can operate in a coordinate way. Such challenging distributed optimization set-up consider each node of the network as an agent whose overall goal is to minimize the sum of the local cost functions. As in a realworld application, each function depends on a local variable that will be subjected to local and coupling constraints. Duality theory helps to handle the distributed algorithm in a simple and intuitive manner. In the paper a network of N agents, arranged in generator, storage units, controllable loads and a trade node, that must solve a microgrid control problem is considered. The solution is carried out introducing the Dual Method and then applying the Distributed Gradient Tracking Algorithm on the cost-coupled problem 5 | 6 | ## Contributions :bar_chart: 7 | Refer to the [Complete Document](Distributed_Dual_GT_Microgrid_Control.pdf) for details on the considered framework, the proposed solution and numerical results. 8 | 9 | ## Contacts :speech_balloon: 10 | The project has been developed by Leonardo Fiocchi and Alessandro Sitta (me) in the context of the course "Distributed Control Systems" at the University of Bologna. 11 | 12 | If you have any questions, feel free to ask: 13 | 14 | :email: [alessandro.sitta@live.it](mailto:alessandro.sitta@live.it) 15 | 16 | Github: https://github.com/alessandrositta 17 | 18 | LinkedIn: https://www.linkedin.com/in/alessandro-sitta/ 19 | --------------------------------------------------------------------------------