0001 function out = sgvm_minqflow(mpc, opt)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 if nargin < 2
0016 mpopt = mpoption('opf.dc.solver', 'MIPS', 'opf.ac.solver', 'IPOPT', 'mips.step_control', 1);
0017 mpopt.out.all = 0;
0018 mpopt.verbose = 0;
0019 opt.limqflow = [];
0020
0021
0022
0023 elseif ~isfield(opt, 'limqflow')
0024 mpopt = opt.mpopt;
0025 opt.limqflow = [];
0026 end
0027 opt.limqflow = opt_default(opt.limqflow);
0028 dqmax = opt.limqflow.shunt_max/mpc.baseMVA;
0029 percent_lines= opt.limqflow.percent_lines;
0030 percent_pick = opt.limqflow.percent_pick;
0031 tmag = opt.limqflow.tmag;
0032
0033 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0034 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0035 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0036 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0037 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0038 nb = size(mpc.bus,1);
0039 nl = size(mpc.branch,1);
0040 out = mpc;
0041
0042
0043 if QF > size(mpc.branch,2)
0044
0045 if isfield(mpc, 'softlims')
0046 mpc = rmfield(mpc, 'softlims');
0047 end
0048 mpopt.opf.softlims.default = 0;
0049 mpc.softlims.RATE_A.hl_mod = 'remove';
0050 mpc.softlims.VMAX.hl_mod = 'remove';
0051 mpc.softlims.VMIN = struct('hl_mod', 'replace', 'hl_val', 0);
0052 if ~toggle_softlims(mpc, 'status')
0053 mpc = toggle_softlims(mpc,'on');
0054 end
0055 r = runopf(mpc,mpopt);
0056 if ~r.success
0057 error('sgvm_minqflow: could not solve OPF even after enabling soft limits.')
0058 end
0059 qold = r.branch(:,QF)/r.baseMVA;
0060 H = sgvm_acptdf(r);
0061 else
0062 qold = mpc.branch(:,QF)/mpc.baseMVA;
0063 H = sgvm_acptdf(mpc);
0064 end
0065
0066 tmp = quantile(abs(qold), 1 - percent_lines);
0067 nluse = find(abs(qold) > tmp);
0068
0069 Hq = H(nl+nluse,nb+1:end);
0070 clear H;
0071 nl = length(nluse);
0072
0073 vars = struct('qnew', (1:nl)', 'dqinj', (nl+1:nl+nb)', 'dqabs', (nl+nb+1:nl+2*nb)');
0074 total_vars = nl + 2*nb;
0075
0076
0077
0078
0079
0080
0081
0082 prob.A = [speye(nl) , -Hq , sparse(nl,nb);
0083 speye(nl) , +Hq , sparse(nl,nb);
0084 sparse(nb,nl), -speye(nb), speye(nb) ;
0085 sparse(nb,nl), +speye(nb), speye(nb)];
0086 prob.l = [qold; -qold; zeros(2*nb,1)];
0087 prob.u = Inf(2*nl + 2*nb,1);
0088
0089
0090
0091 prob.c = sparse([vars.qnew; vars.dqabs], 1, 1, total_vars,1);
0092
0093
0094
0095
0096
0097 prob.xmin = [zeros(nl,1); -dqmax*ones(nb,1); zeros(nb,1)];
0098 prob.xmax = [Inf(nl,1); dqmax*ones(nb,1); Inf(nb,1)];
0099
0100
0101 [x, f, eflag, output, lambda] = qps_matpower(prob);
0102
0103 if eflag
0104 dqinj = x(vars.dqinj)*mpc.baseMVA;
0105 dqabs = x(vars.dqabs)*mpc.baseMVA;
0106
0107
0108 threshold = quantile(dqabs,1-percent_pick);
0109 dqinj(dqabs <= threshold) = 0;
0110
0111
0112
0113
0114 mask = (abs(dqinj) > 0) & (abs(dqinj) < tmag);
0115 dqinj(mask) = sign(dqinj(mask))*tmag;
0116 out.bus(:,BS) = out.bus(:,BS) + dqinj;
0117 else
0118 error('sgvm_minqflow: optimization failed to converge.')
0119 end
0120
0121
0122 function opt = opt_default(opt)
0123
0124 optdef = struct();
0125 optdef.shunt_max = 200;
0126 optdef.percent_lines = 0.5;
0127 optdef.percent_pick = 0.1;
0128 optdef.tmag = 0.1;
0129
0130 if ~isempty(opt)
0131 opt = struct_compare(optdef, opt);
0132 else
0133 opt = optdef;
0134 end
0135
0136 function b = struct_compare(a, b)
0137
0138
0139
0140
0141 for f = fieldnames(a).'
0142 if ~isfield(b, f{:})
0143 b.(f{:}) = a.(f{:});
0144 elseif isstruct(a.(f{:}))
0145 b.(f{:}) = struct_compare(a.(f{:}), b.(f{:}));
0146 end
0147 end