????????博客中所有內容均來源于自己學習過程中積累的經驗以及對yalmip官方文檔的翻譯:https://yalmip.github.io/tutorials/
????????這篇博客將詳細介紹使用yalmip工具箱編程過程中的常見錯誤和相應的解決辦法。
1.optimize的輸出參數
????????眾所周知,optimize是yalmip用來求解優化問題的函數,其使用格式為:
sol = optimize(Constraints,Objective,options)
????????optimize函數的返回值sol是一個包含六個字段的結構體:
>> solsol = 包含以下字段的 struct:yalmipversion: '20210331'matlabversion: '9.1.0.441655 (R2016b)'yalmiptime: 0.0851solvertime: 0.0439info: 'Successfully solved (GUROBI-GUROBI)'problem: 0
? ? ? ?其中,yalmipversion表示Yalmip工具箱的版本,matlabversion表示Matlab的版本,yalmiptime表示Yalmip的建模時間,solvertime表示求解器的求解時間,info表示返回的信息,problem為求解成功的標志,0表示求解成功,1表示求解失敗。
????????其中最重要的參數就是problem和info,可以顯示求解是否成功,以及可能遇到的問題。因此通常可以在optimize函數求解之后再加一部分代碼來展示是否求解成功和求解失敗的原因:
if sol.problem == 0disp('求解成功')
else disp('求解失敗,失敗原因為:')disp(sol.info)
end
????????以下的代碼是一個能求解成功的例子:
x = sdpvar(2,1);
Constraints = [x <= 3 , x(1) >= 2 , x(2) >= 1];
Objective = [1 3]*x;
ops = sdpsettings;
sol = optimize(Constraints , Objective , ops);
if sol.problem == 0disp('求解成功')
else disp('求解失敗,失敗原因為:')disp(sol.info)
end
????????下面的例子是一個求解失敗的代碼:
x = sdpvar(2,1);
Constraints = [x <= 1 , x(1) >= 2 , x(2) >= 1];
Objective = [1 3]*x;
ops = sdpsettings;
sol = optimize(Constraints , Objective , ops);
if sol.problem == 0disp('求解成功')
else disp('求解失敗,失敗原因為:')disp(sol.info)
end
????????因為約束條件中x1≤1且x1≥2,所以導致優化問題無解。
????????在確保優化問題求解成功的情況下,可以采用value命令求出目標函數或者決策變量的取值,例如:
x = sdpvar(2,1);
Constraints = [x <= 3 , x(1) >= 2 , x(2) >= 1];
Objective = [1 3]*x;
ops = sdpsettings;
sol = optimize(Constraints , Objective , ops);
if sol.problem == 0disp('求解成功')x1 = value(x(1))x2 = value(x(2))Objective = value(Objective)
elsedisp('求解失敗,失敗原因為:')disp(sol.info)
end
????????結果為:
????????表示這個優化問題的最優解為x1=2,x2=1,目標函數最小值為5。
2.根據info信息判斷判斷解決方法
????????由第一節可知,yalmip工具箱中出現的大部分錯誤的原因都可以從optimize輸出參數的info屬性中查看。
????????例如,下面這個圖是非常常見的錯誤:
主要原因是優化問題無解,optimize函數求解失敗,后續又用到了優化問題中的一些變量,就會出現圖中的報錯。解決方法就是需要確保optimize函數可以求解成功。下面分別介紹一些常見的錯誤以及相應的解決方法。
2.1 solver not found
????????這個錯誤很簡單,就是字面意思(沒有安裝求解器),也是私信問我的朋友中最常見的錯誤。
????????解決這個報錯也很簡單,沒有求解器的去安裝一個,或者換成已經安裝過的求解器就行了。
????????和這個報錯同類型的提示還有:
Solver license cannot be located
Solver license expired
Specified solver name not recognized
License problems in solver
????????上述提示均可采用相同的方式解決。
2.2 Solver not applicable
????????從字面意思看,這個提示就是說求解器不適用。可能這么說大家還是不太明白。舉個例子,LINPROG是matlab自帶的線性規劃求解器,不具備求解二次規劃的功能,如果我們用這個求解器來解二次規劃問題,yalmip就會報錯提示求解器不可用,如下面的代碼:
clc
clearx1 = sdpvar(1);
x2 = sdpvar(1);
Constraints = [x1 >= 1 , x1 <= 2 , x2 <= 5 ,x2 >= 1];
Objective = x1^2 +9*x2;
ops = sdpsettings('solver' , 'LINPROG' , 'verbose' , 3 );
sol = optimize(Constraints , -Objective , ops);
sol.info
????????輸出結果為:
ans ='Solver not applicable (linprog does not support nonconvex quadratic terms in objective)'
????????如果我們在求解優化問題的過程中出現上面的提示,就需要確定優化問題的類型,仔細檢查你所使用的求解器是否支持該類型優化問題。換一個能求解該類型問題的求解器即可。
????????比如gurobi可以用來求解二次規劃問題,我們可以把上面例子中的求解器改為gurobi:
clc
clearx1 = sdpvar(1);
x2 = sdpvar(1);
Constraints = [x1 >= 1 , x1 <= 2 , x2 <= 5 ,x2 >= 1];
Objective = x1^2 +9*x2;
ops = sdpsettings('solver' , 'gurobi' , 'verbose' , 3 );
sol = optimize(Constraints , -Objective , ops);
sol.info
????????這時候就可以求解成功了:
ans ='Successfully solved (GUROBI-NONCONVEX)'
2.3 Unbounded objective function
????????從字面意思看,這個提示就是指優化模型的目標函數是無界的。具體來說,就是目標函數中存在沒有邊界范圍的變量,使得目標函數無法取得最大值(或最小值)。例如下面的優化問題:
????????很明顯這是一個無界的優化問題,因為變量x沒有下界,因此無法找到2x的最小值,我們用yalmip求解試試:
clc
clearsdpvar x
Constraints = [x <= 1];
Objective = 2*x;
ops = sdpsettings('solver' , 'cplex' , 'verbose' , 3 );
sol = optimize(Constraints , Objective , ops);
sol.info
????????結果如下:
ans ='Unbounded objective function (CPLEX-IBM)'
????????針對目標函數無界的情況,調試的方法也很簡單。我們可以給定目標函數中涉及到的所有變量上下界,那么優化問題一般都可以從無解轉為有解,如果存在某些變量,無論上下界取何值,該變量的取值都處于我們給定的邊界上,那么就是因為這個變量沒有給定范圍,才導致目標函數無界。舉個例子:
clc
clearsdpvar x y zConstraints = [-1 <= [x y] <= 1, z <= 0];
Objective = x^2 + y + z;
ops = sdpsettings('solver' , 'cplex' , 'verbose' , 3 );
sol = optimize(Constraints , Objective , ops);
sol.info
????????這個優化問題也是無界,為了找到具體是哪個變量導致目標函數無界,我們可以按下面的步驟操作:
????????1)用allvariables函數取出目標函數中所有涉及的變量(注意,使用allvariables函數要求yalmip版本高于2021,舊版工具箱里面不存在該函數,舊版yalmip可以手動選取目標函數涉及的所有變量):
UsedInObjective = allvariables(Objective);
????????如果使用了較低版本的yalmip,可以把代碼改成下面這樣:
UsedInObjective = [x, y, z];
????????2)人為給定這些變量的上下限:
Constraints = [Constraints, -100 <= UsedInObjective <= 100];
????????3)求解修改后的優化問題,并查看所有變量的取值:
ops = sdpsettings('solver' , 'cplex' , 'verbose' , 3 );
sol = optimize(Constraints , Objective , ops);
value([x y z])
????????結果如下:
ans =0 -1 -100
????????4)修改這些變量的上下限,并重復步驟2和3:
Constraints = [Constraints, -1000 <= UsedInObjective <= 1000];
ops = sdpsettings('solver' , 'cplex' , 'verbose' , 3 );
sol = optimize(Constraints , Objective , ops);
value([x y z])
????????結果如下:
ans =0 -1 -1000
我們可以看到,無論我們給定多大的邊界,變量z取值都位于邊界,因此就是未定義變量z的范圍或相關的約束,導致模型的目標函數無界,給定變量z的范圍或相關的約束即可解決該問題。
2.4 Infeasible problem
????????這個提示的字面意思是“不可行的問題”,也就是優化問題是無解的。一般情況下,優化問題無解都是因為約束條件之間存在矛盾或者限制的太死,我們需要通過調試找到問題所在。對于大規模的優化問題,調試的過程是很痛苦的,我們在調試之前可以先做一些簡單的檢查。
2.4.1 一些簡單檢查
????????1)檢查變量的定義是否存在問題,如0-1變量是否用binvar函數定義,連續變量是否用sdpvar函數定義,整數變量是否用intvar函數定義。
????????2)對于多維變量,檢查是否添加了’full’屬性。由于yalmip在定義N×N維變量時,如果不添加’full’屬性,將默認變量是對稱的,定義多維變量時很容易忽視這一點,導致模型不可行。
????????舉個例子,我在之前的博客中提到了一個數獨問題(Yalmip入門教程(3)-約束條件的定義-CSDN博客):
????????求解該問題的代碼如下:
clc
clearA0 = [
0 4 7 0 5 0 0 0 8;
6 0 5 0 3 0 2 0 1;
0 0 0 7 0 6 0 3 0;
0 0 6 0 7 0 0 2 4;
9 0 0 8 0 4 0 0 6;
4 5 0 0 1 0 9 0 0;
0 1 0 5 0 2 0 0 0;
2 0 8 0 4 0 5 0 3;
5 0 0 0 9 0 7 1 0;
];A = binvar(9,9,9,'full');
F = [sum(A,1) == 1, sum(A,2) == 1, sum(A,3) == 1];for i = 1:9for j = 1:9if A0(i,j)F = [F, A(i,j,A0(i,j)) == 1];endend
endfor m = 1:3for n = 1:3for k = 1:9s = sum(sum(A((m-1)*3+(1:3),(n-1)*3+(1:3),k))); F = [F, s == 1];endend
enddiagnostics = optimize(F);Z = 0;
for i = 1:9Z = Z + i*value(A(:,:,i));
end
Z
????????運行結果如下:
Z =3 4 7 2 5 1 6 9 86 8 5 4 3 9 2 7 11 2 9 7 8 6 4 3 58 3 6 9 7 5 1 2 49 7 1 8 2 4 3 5 64 5 2 6 1 3 9 8 77 1 3 5 6 2 8 4 92 9 8 1 4 7 5 6 35 6 4 3 9 8 7 1 2
????????如果我們將變量A定義時的’full’屬性刪除,再次運行的結果如下:
????????3)確定模型是否真的無解,而不是目標函數無界。有時候求解器會提示Either infeasible or unbounded,無法確定是優化問題無解還是目標函數無界。這時候我們可以將目標函數設為空,如果修改后可以求解成功,說明是目標函數無界,按照本博客2.3小節提到的方法進行調試即可。如果修改后還是提示模型不可行,那么就需要我們繼續調試。
2.4.2 調試較大規模的不可行問題
????????簡單來說,調試較大規模的不可行問題的思路就是依次向優化問題中添加約束條件,確定具體是哪組約束條件導致模型不可行或者哪些約束條件存在矛盾導致模型不可行。
????????我之前的博客給出了一個基于混合整數二階錐(MISOCP)的配電網重構代碼(基于混合整數二階錐(MISOCP)的配電網重構(附matlab代碼)-CSDN博客),這是一個稍微有一丟丟復雜的優化問題,我悄咪咪地修改了其中一些參數,使得模型不可行,下面以修改后優化問題為例,講一下調試不可行問題的思路。
????????首先給出修改后的代碼:
%% 清除內存空間
clc
clear
close all
warning off
%% 系統參數
mpc = IEEE33;
nb=33; % 節點數
ns=1; % 電源節點數
nl=37; % 支路數
P_load=mpc.bus(:,3)/mpc.baseMVA; % 有功負荷
Q_load=mpc.bus(:,4)/mpc.baseMVA; % 無功負荷
r_ij=mpc.branch(:,3); % 線路電阻
x_ij=mpc.branch(:,4); % 線路電抗
M=1.06*1.06 - 0.94*0.94;
% 電源功率最大值
P_g_max=zeros(nb,1);
P_g_max(1)=10/mpc.baseMVA;
Q_g_max=zeros(nb,1);
Q_g_max(1)=10/mpc.baseMVA;
% 電源功率最小值
P_g_min=zeros(nb,1);
Q_g_min=[-10/mpc.baseMVA;zeros(nb-1,1)];
% 支路功率最大值
Sij_max=15/mpc.baseMVA;
% 最大電壓
Umax=[1;1.1*1.1*ones(32,1)];
Umin=[1;0.95*0.95*ones(32,1)];
% 流入節點的支路
branch_to_node=zeros(nb,nl);
% 流出節點的支路
branch_from_node=zeros(nb,nl);
for k=1:nlbranch_to_node(mpc.branch(k,2),k)=1;branch_from_node(mpc.branch(k,1),k)=1;
end%% 優化變量
z_ij=binvar(nl,1);% 支路開斷情況
U_i=sdpvar(nb,1);% 電壓的平方
L_ij=sdpvar(nl,1);% 電流的平方
P_ij=sdpvar(nl,1);% 線路有功功率
Q_ij=sdpvar(nl,1);% 線路無功功率
P_g=sdpvar(nb,1);% 電源有功出力
Q_g=sdpvar(nb,1);% 電源無功功率%% 約束條件
Constraints = [];
%% 1.潮流約束
m_ij=(1-z_ij)*M;
Constraints = [Constraints, P_g-P_load+branch_to_node*P_ij-branch_to_node*(L_ij.*r_ij)-branch_from_node*P_ij == 0];
Constraints = [Constraints, Q_g-Q_load+branch_to_node*Q_ij-branch_to_node*(L_ij.*x_ij)-branch_from_node*Q_ij == 0];
Constraints = [Constraints,U_i(mpc.branch(:,1))-U_i(mpc.branch(:,2))<= m_ij + 2*r_ij.*P_ij + 2*x_ij.*Q_ij - ((r_ij.^2 + x_ij.^2)).*L_ij];
Constraints = [Constraints,U_i(mpc.branch(:,1))-U_i(mpc.branch(:,2))>= -m_ij + 2*r_ij.*P_ij + 2*x_ij.*Q_ij - ((r_ij.^2 + x_ij.^2)).*L_ij];
for k=1:nlConstraints = [Constraints, cone([2*P_ij(k) 2*Q_ij(k) L_ij(k)-U_i(mpc.branch(k,1))],L_ij(k)+U_i(mpc.branch(k,1)))];
end
Constraints = [Constraints, Sij_max'.^2.*z_ij >= P_ij.^2+Q_ij.^2];%% 2.拓撲約束
Constraints = [Constraints , sum(z_ij) == nb-ns];%% 3.注入功率約束
Constraints = [Constraints, P_g>=P_g_min,P_g<=P_g_max];
Constraints = [Constraints, Q_g>=Q_g_min,Q_g<=Q_g_max];%% 4.電壓上下限約束
Constraints = [Constraints, Umin <= U_i,U_i <= Umax];%% 目標函數
objective = sum(L_ij.*r_ij);%網損最小%% 設求解器
% gurobi求解器
ops=sdpsettings('verbose', 3, 'solver', 'gurobi','showprogress',1,'debug',1);
ops.gurobi.TimeLimit=600; % 運行時間限制為10min
ops.gurobi.MIPGap=0.01; % 收斂精度限制為0.01sol=optimize(Constraints,objective,ops);
value(objective)%% 分析錯誤標志
if sol.problem == 0disp('求解成功');
elsedisp('運行出錯');yalmiperror(sol.problem)
end
????????數據文件如下:
function mpc = IEEE33%% MATPOWER Case Format : Version 2
mpc.version = '2';%%----- Power Flow Data -----%%
%% system MVA base
mpc.baseMVA = 10;%% bus data
% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
mpc.bus = [ %% (Pd and Qd are specified in kW & kVAr here, converted to MW & MVAr below)1 3 0 0 0 0 1 1 0 12.66 1 1 1;2 1 100 60 0 0 1 1 0 12.66 1 1.1 0.9;3 1 90 40 0 0 1 1 0 12.66 1 1.1 0.9;4 1 120 80 0 0 1 1 0 12.66 1 1.1 0.9;5 1 60 30 0 0 1 1 0 12.66 1 1.1 0.9;6 1 60 20 0 0 1 1 0 12.66 1 1.1 0.9;7 1 200 100 0 0 1 1 0 12.66 1 1.1 0.9;8 1 200 100 0 0 1 1 0 12.66 1 1.1 0.9;9 1 60 20 0 0 1 1 0 12.66 1 1.1 0.9;10 1 60 20 0 0 1 1 0 12.66 1 1.1 0.9;11 1 45 30 0 0 1 1 0 12.66 1 1.1 0.9;12 1 60 35 0 0 1 1 0 12.66 1 1.1 0.9;13 1 60 35 0 0 1 1 0 12.66 1 1.1 0.9;14 1 120 80 0 0 1 1 0 12.66 1 1.1 0.9;15 1 60 10 0 0 1 1 0 12.66 1 1.1 0.9;16 1 60 20 0 0 1 1 0 12.66 1 1.1 0.9;17 1 60 20 0 0 1 1 0 12.66 1 1.1 0.9;18 1 90 40 0 0 1 1 0 12.66 1 1.1 0.9;19 1 90 40 0 0 1 1 0 12.66 1 1.1 0.9;20 1 90 40 0 0 1 1 0 12.66 1 1.1 0.9;21 1 90 40 0 0 1 1 0 12.66 1 1.1 0.9;22 1 90 40 0 0 1 1 0 12.66 1 1.1 0.9;23 1 90 50 0 0 1 1 0 12.66 1 1.1 0.9;24 1 420 200 0 0 1 1 0 12.66 1 1.1 0.9;25 1 420 200 0 0 1 1 0 12.66 1 1.1 0.9;26 1 60 25 0 0 1 1 0 12.66 1 1.1 0.9;27 1 60 25 0 0 1 1 0 12.66 1 1.1 0.9;28 1 60 20 0 0 1 1 0 12.66 1 1.1 0.9;29 1 120 70 0 0 1 1 0 12.66 1 1.1 0.9;30 1 200 600 0 0 1 1 0 12.66 1 1.1 0.9;31 1 150 70 0 0 1 1 0 12.66 1 1.1 0.9;32 1 210 100 0 0 1 1 0 12.66 1 1.1 0.9;33 1 60 40 0 0 1 1 0 12.66 1 1.1 0.9;
];%% generator data
% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
mpc.gen = [1 0 0 10 -10 1 100 1 10 0 0 0 0 0 0 0 0 0 0 0 0;
];%% branch data
% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax
mpc.branch = [ %% (r and x specified in ohms here, converted to p.u. below)1 2 0.0922 0.0470 0 0 0 0 0 0 1 -360 360;2 3 0.4930 0.2511 0 0 0 0 0 0 1 -360 360;3 4 0.3660 0.1864 0 0 0 0 0 0 1 -360 360;4 5 0.3811 0.1941 0 0 0 0 0 0 1 -360 360;5 6 0.8190 0.7070 0 0 0 0 0 0 1 -360 360;6 7 0.1872 0.6188 0 0 0 0 0 0 1 -360 360;7 8 0.7114 0.2351 0 0 0 0 0 0 1 -360 360;8 9 1.0300 0.7400 0 0 0 0 0 0 1 -360 360;9 10 1.0440 0.7400 0 0 0 0 0 0 1 -360 360;10 11 0.1966 0.0650 0 0 0 0 0 0 1 -360 360;11 12 0.3744 0.1238 0 0 0 0 0 0 1 -360 360;12 13 1.4680 1.1550 0 0 0 0 0 0 1 -360 360;13 14 0.5416 0.7129 0 0 0 0 0 0 1 -360 360;14 15 0.5910 0.5260 0 0 0 0 0 0 1 -360 360;15 16 0.7463 0.5450 0 0 0 0 0 0 1 -360 360;16 17 1.2890 1.7210 0 0 0 0 0 0 1 -360 360;17 18 0.7320 0.5740 0 0 0 0 0 0 1 -360 360;2 19 0.1640 0.1565 0 0 0 0 0 0 1 -360 360;19 20 1.5042 1.3554 0 0 0 0 0 0 1 -360 360;20 21 0.4095 0.4784 0 0 0 0 0 0 1 -360 360;21 22 0.7089 0.9373 0 0 0 0 0 0 1 -360 360;3 23 0.4512 0.3083 0 0 0 0 0 0 1 -360 360;23 24 0.8980 0.7091 0 0 0 0 0 0 1 -360 360;24 25 0.8960 0.7011 0 0 0 0 0 0 1 -360 360;6 26 0.2030 0.1034 0 0 0 0 0 0 1 -360 360;26 27 0.2842 0.1447 0 0 0 0 0 0 1 -360 360;27 28 1.0590 0.9337 0 0 0 0 0 0 1 -360 360;28 29 0.8042 0.7006 0 0 0 0 0 0 1 -360 360;29 30 0.5075 0.2585 0 0 0 0 0 0 1 -360 360;30 31 0.9744 0.9630 0 0 0 0 0 0 1 -360 360;31 32 0.3105 0.3619 0 0 0 0 0 0 1 -360 360;32 33 0.3410 0.5302 0 0 0 0 0 0 1 -360 360;21 8 2.0000 2.0000 0 0 0 0 0 0 0 -360 360;9 15 2.0000 2.0000 0 0 0 0 0 0 0 -360 360;12 22 2.0000 2.0000 0 0 0 0 0 0 0 -360 360;18 33 0.5000 0.5000 0 0 0 0 0 0 0 -360 360;25 29 0.5000 0.5000 0 0 0 0 0 0 0 -360 360;
];%%----- OPF Data -----%%
%% generator cost data
% 1 startup shutdown n x1 y1 ... xn yn
% 2 startup shutdown n c(n-1) ... c0
mpc.gencost = [2 0 0 3 0 20 0;
];%% convert branch impedances from Ohms to p.u.
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
Vbase = mpc.bus(1, BASE_KV) * 1e3; %% in Volts
Sbase = mpc.baseMVA * 1e6; %% in VA
mpc.branch(:, [BR_R BR_X]) = mpc.branch(:, [BR_R BR_X]) / (Vbase^2 / Sbase);%% convert loads from kW to MW
mpc.bus(:, [PD, QD]) = mpc.bus(:, [PD, QD]) / 1e3;
????????運行上面的代碼,得到的結果如下:
????????提示我們優化問題無解或者是目標函數無界。按照2.4.1小節第3點所提到的,我們先把目標函數設置為空,確定一下具體是優化問題無解還是目標函數無界:
sol=optimize(Constraints,[],ops);
????????得到的結果如下:
????????OK,現在確定了是優化問題不可行而不是目標函數無界,我們可以繼續調試。
????????1)首先只保留第一條約束,將其他約束都設為注釋,查看模型是否可行:
%% 清除內存空間
clc
clear
close all
warning off
%% 系統參數
mpc = IEEE33;
nb=33; % 節點數
ns=1; % 電源節點數
nl=37; % 支路數
P_load=mpc.bus(:,3)/mpc.baseMVA; % 有功負荷
Q_load=mpc.bus(:,4)/mpc.baseMVA; % 無功負荷
r_ij=mpc.branch(:,3); % 線路電阻
x_ij=mpc.branch(:,4); % 線路電抗
M=1.06*1.06 - 0.94*0.94;
% 電源功率最大值
P_g_max=zeros(nb,1);
P_g_max(1)=10/mpc.baseMVA;
Q_g_max=zeros(nb,1);
Q_g_max(1)=10/mpc.baseMVA;
% 電源功率最小值
P_g_min=zeros(nb,1);
Q_g_min=[-10/mpc.baseMVA;zeros(nb-1,1)];
% 支路功率最大值
Sij_max=15/mpc.baseMVA;
% 最大電壓
Umax=[1;1.1*1.1*ones(32,1)];
Umin=[1;0.95*0.95*ones(32,1)];
% 流入節點的支路
branch_to_node=zeros(nb,nl);
% 流出節點的支路
branch_from_node=zeros(nb,nl);
for k=1:nlbranch_to_node(mpc.branch(k,2),k)=1;branch_from_node(mpc.branch(k,1),k)=1;
end%% 優化變量
z_ij=binvar(nl,1);% 支路開斷情況
U_i=sdpvar(nb,1);% 電壓的平方
L_ij=sdpvar(nl,1);% 電流的平方
P_ij=sdpvar(nl,1);% 線路有功功率
Q_ij=sdpvar(nl,1);% 線路無功功率
P_g=sdpvar(nb,1);% 電源有功出力
Q_g=sdpvar(nb,1);% 電源無功功率%% 約束條件
Constraints = [];
%% 1.潮流約束
m_ij=(1-z_ij)*M;
Constraints = [Constraints, P_g-P_load+branch_to_node*P_ij-branch_to_node*(L_ij.*r_ij)-branch_from_node*P_ij == 0];%% 目標函數
objective = sum(L_ij.*r_ij);%網損最小%% 設求解器
% gurobi求解器
ops=sdpsettings('verbose', 3, 'solver', 'gurobi','showprogress',1,'debug',1);
ops.gurobi.TimeLimit=600; % 運行時間限制為10min
ops.gurobi.MIPGap=0.01; % 收斂精度限制為0.01sol=optimize(Constraints, [], ops);
value(objective)%% 分析錯誤標志
if sol.problem == 0disp('求解成功');
elsedisp('運行出錯');yalmiperror(sol.problem)
end
????????運行結果如下:
????????這個結果,說明第一條約束沒問題,可以繼續添加約束。
????????2)只保留前2條約束,將其他約束都設為注釋,查看模型是否可行:
%% 清除內存空間
clc
clear
close all
warning off
%% 系統參數
mpc = IEEE33;
nb=33; % 節點數
ns=1; % 電源節點數
nl=37; % 支路數
P_load=mpc.bus(:,3)/mpc.baseMVA; % 有功負荷
Q_load=mpc.bus(:,4)/mpc.baseMVA; % 無功負荷
r_ij=mpc.branch(:,3); % 線路電阻
x_ij=mpc.branch(:,4); % 線路電抗
M=1.06*1.06 - 0.94*0.94;
% 電源功率最大值
P_g_max=zeros(nb,1);
P_g_max(1)=10/mpc.baseMVA;
Q_g_max=zeros(nb,1);
Q_g_max(1)=10/mpc.baseMVA;
% 電源功率最小值
P_g_min=zeros(nb,1);
Q_g_min=[-10/mpc.baseMVA;zeros(nb-1,1)];
% 支路功率最大值
Sij_max=15/mpc.baseMVA;
% 最大電壓
Umax=[1;1.1*1.1*ones(32,1)];
Umin=[1;0.95*0.95*ones(32,1)];
% 流入節點的支路
branch_to_node=zeros(nb,nl);
% 流出節點的支路
branch_from_node=zeros(nb,nl);
for k=1:nlbranch_to_node(mpc.branch(k,2),k)=1;branch_from_node(mpc.branch(k,1),k)=1;
end%% 優化變量
z_ij=binvar(nl,1);% 支路開斷情況
U_i=sdpvar(nb,1);% 電壓的平方
L_ij=sdpvar(nl,1);% 電流的平方
P_ij=sdpvar(nl,1);% 線路有功功率
Q_ij=sdpvar(nl,1);% 線路無功功率
P_g=sdpvar(nb,1);% 電源有功出力
Q_g=sdpvar(nb,1);% 電源無功功率%% 約束條件
Constraints = [];
%% 1.潮流約束
m_ij=(1-z_ij)*M;
Constraints = [Constraints, P_g-P_load+branch_to_node*P_ij-branch_to_node*(L_ij.*r_ij)-branch_from_node*P_ij == 0];
Constraints = [Constraints, Q_g-Q_load+branch_to_node*Q_ij-branch_to_node*(L_ij.*x_ij)-branch_from_node*Q_ij == 0];%% 目標函數
objective = sum(L_ij.*r_ij);%網損最小%% 設求解器
% gurobi求解器
ops=sdpsettings('verbose', 3, 'solver', 'gurobi','showprogress',1,'debug',1);
ops.gurobi.TimeLimit=600; % 運行時間限制為10min
ops.gurobi.MIPGap=0.01; % 收斂精度限制為0.01sol=optimize(Constraints, [], ops);
value(objective)%% 分析錯誤標志
if sol.problem == 0disp('求解成功');
elsedisp('運行出錯');yalmiperror(sol.problem)
end
??????????運行結果如下:
????????這個結果,說明前2條約束沒問題且不存在矛盾,可以繼續添加約束。
????????……
????????3)一直重復上述步驟,可以發現直到加入最后一條電壓上下限約束之前,模型都是可行的,而加入電壓上下限約束之后模型就變得不可行了。說明問題很大可能就出現在這個電壓約束上。可能是電壓上下限設置的太緊,我們可以嘗試將節點電壓標幺值的下限從0.95改成0.9,再重新運行模型。
Umin=[1;0.9*0.9*ones(32,1)];
????????這時候發現可以求解出優化結果了:
????????我們可以再次把目標函數添加到優化問題中,模型依舊可行。
????????所以,這個優化問題不可行的原因就是電壓約束設置的太緊,稍微松弛一些即可。
????????對于其他不可行的優化問題,也可以按照相同的方式進行調試,找到存在問題的約束或互相矛盾的約束,再進行針對性的調整。