0001 function [MVAbase, bus, gen, branch, success, et] = ...
0002 runpf(casedata, mpopt, fname, solvedcase)
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0074 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0075 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0076 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0077 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0078 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0079 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0080 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0081
0082
0083 if nargin < 4
0084 solvedcase = '';
0085 if nargin < 3
0086 fname = '';
0087 if nargin < 2
0088 mpopt = mpoption;
0089 if nargin < 1
0090 casedata = 'case9';
0091 end
0092 end
0093 end
0094 end
0095
0096
0097 qlim = mpopt.pf.enforce_q_lims;
0098 dc = strcmp(upper(mpopt.model), 'DC');
0099
0100
0101 mpc = loadcase(casedata);
0102
0103
0104 if size(mpc.branch,2) < QT
0105 mpc.branch = [ mpc.branch zeros(size(mpc.branch, 1), QT-size(mpc.branch,2)) ];
0106 end
0107
0108
0109 mpc = ext2int(mpc, mpopt);
0110 [baseMVA, bus, gen, branch] = deal(mpc.baseMVA, mpc.bus, mpc.gen, mpc.branch);
0111
0112 if ~isempty(mpc.bus)
0113
0114 [ref, pv, pq] = bustypes(bus, gen);
0115
0116
0117 on = find(gen(:, GEN_STATUS) > 0);
0118 gbus = gen(on, GEN_BUS);
0119
0120
0121 t0 = tic;
0122 its = 0;
0123 if mpopt.verbose > 0
0124 v = mpver('all');
0125 fprintf('\nMATPOWER Version %s, %s', v.Version, v.Date);
0126 end
0127 if dc
0128 if mpopt.verbose > 0
0129 fprintf(' -- DC Power Flow\n');
0130 end
0131
0132 Va0 = bus(:, VA) * (pi/180);
0133
0134
0135 [B, Bf, Pbusinj, Pfinj] = makeBdc(baseMVA, bus, branch);
0136
0137
0138
0139 Pbus = real(makeSbus(baseMVA, bus, gen)) - Pbusinj - bus(:, GS) / baseMVA;
0140
0141
0142 [Va, success] = dcpf(B, Pbus, Va0, ref, pv, pq);
0143 its = 1;
0144
0145
0146 branch(:, [QF, QT]) = zeros(size(branch, 1), 2);
0147 branch(:, PF) = (Bf * Va + Pfinj) * baseMVA;
0148 branch(:, PT) = -branch(:, PF);
0149 bus(:, VM) = ones(size(bus, 1), 1);
0150 bus(:, VA) = Va * (180/pi);
0151
0152
0153
0154
0155 refgen = zeros(size(ref));
0156 for k = 1:length(ref)
0157 temp = find(gbus == ref(k));
0158 refgen(k) = on(temp(1));
0159 end
0160 gen(refgen, PG) = gen(refgen, PG) + (B(ref, :) * Va - Pbus(ref)) * baseMVA;
0161 else
0162 alg = upper(mpopt.pf.alg);
0163 switch alg
0164 case 'NR-SC'
0165 mpopt = mpoption(mpopt, 'pf.current_balance', 0, 'pf.v_cartesian', 1);
0166 case 'NR-IP'
0167 mpopt = mpoption(mpopt, 'pf.current_balance', 1, 'pf.v_cartesian', 0);
0168 case 'NR-IC'
0169 mpopt = mpoption(mpopt, 'pf.current_balance', 1, 'pf.v_cartesian', 1);
0170 end
0171 if mpopt.verbose > 0
0172 switch alg
0173 case 'NR'
0174 solver = 'Newton';
0175 case 'NR-SC'
0176 solver = 'Newton-SC';
0177 case 'NR-IP'
0178 solver = 'Newton-IP';
0179 case 'NR-IC'
0180 solver = 'Newton-IC';
0181 case 'FDXB'
0182 solver = 'fast-decoupled, XB';
0183 case 'FDBX'
0184 solver = 'fast-decoupled, BX';
0185 case 'GS'
0186 solver = 'Gauss-Seidel';
0187 case 'PQSUM'
0188 solver = 'Power Summation';
0189 case 'ISUM'
0190 solver = 'Current Summation';
0191 case 'YSUM'
0192 solver = 'Admittance Summation';
0193 otherwise
0194 solver = 'unknown';
0195 end
0196 fprintf(' -- AC Power Flow (%s)\n', solver);
0197 end
0198 switch alg
0199 case {'NR', 'NR-SC', 'NR-IP', 'NR-IC'}
0200 otherwise
0201 if mpopt.pf.current_balance || mpopt.pf.v_cartesian
0202 error('runpf: power flow algorithm ''%s'' only supports power balance, polar version\nI.e. both ''pf.current_balance'' and ''pf.v_cartesian'' must be set to 0.');
0203 end
0204 end
0205 if have_zip_loads(mpopt)
0206 if mpopt.pf.current_balance || mpopt.pf.v_cartesian
0207 warnstr = 'Newton algorithm (current or cartesian versions) do';
0208 elseif strcmp(alg, 'GS')
0209 warnstr = 'Gauss-Seidel algorithm does';
0210 else
0211 warnstr = '';
0212 end
0213 if warnstr
0214 warning('runpf: %s not support ZIP load model. Converting to constant power loads.', warnstr);
0215 mpopt = mpoption(mpopt, 'exp.sys_wide_zip_loads', ...
0216 struct('pw', [], 'qw', []));
0217 end
0218 end
0219
0220
0221
0222 V0 = bus(:, VM) .* exp(1j * pi/180 * bus(:, VA));
0223 vcb = ones(size(V0));
0224 vcb(pq) = 0;
0225 k = find(vcb(gbus));
0226 V0(gbus(k)) = gen(on(k), VG) ./ abs(V0(gbus(k))).* V0(gbus(k));
0227
0228 if qlim
0229 ref0 = ref;
0230 Varef0 = bus(ref0, VA);
0231 limited = [];
0232 fixedQg = zeros(size(gen, 1), 1);
0233 end
0234
0235
0236 [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch);
0237
0238 repeat = 1;
0239 while (repeat)
0240
0241
0242 Sbus = @(Vm)makeSbus(baseMVA, bus, gen, mpopt, Vm);
0243
0244
0245 switch alg
0246 case {'NR', 'NR-SC', 'NR-IP', 'NR-IC'}
0247 if mpopt.pf.current_balance
0248 if mpopt.pf.v_cartesian
0249 newtonpf_fcn = @newtonpf_I_cart;
0250 else
0251 newtonpf_fcn = @newtonpf_I_polar;
0252 end
0253 else
0254 if mpopt.pf.v_cartesian
0255 newtonpf_fcn = @newtonpf_S_cart;
0256 else
0257 newtonpf_fcn = @newtonpf;
0258 end
0259 end
0260 [V, success, iterations] = newtonpf_fcn(Ybus, Sbus, V0, ref, pv, pq, mpopt);
0261 case {'FDXB', 'FDBX'}
0262 [Bp, Bpp] = makeB(baseMVA, bus, branch, alg);
0263 [V, success, iterations] = fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, mpopt);
0264 case 'GS'
0265 [V, success, iterations] = gausspf(Ybus, Sbus([]), V0, ref, pv, pq, mpopt);
0266 case {'PQSUM', 'ISUM', 'YSUM'}
0267 [mpc, success, iterations] = radial_pf(mpc, mpopt);
0268 otherwise
0269 error('runpf: ''%s'' is not a valid power flow algorithm. See ''pf.alg'' details in MPOPTION help.', alg);
0270 end
0271 its = its + iterations;
0272
0273
0274 switch alg
0275 case {'NR', 'NR-SC', 'NR-IP', 'NR-IC', 'FDXB', 'FDBX', 'GS'}
0276 [bus, gen, branch] = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq, mpopt);
0277 case {'PQSUM', 'ISUM', 'YSUM'}
0278 bus = mpc.bus;
0279 gen = mpc.gen;
0280 branch = mpc.branch;
0281 end
0282
0283 if success && qlim
0284
0285 mx = find( gen(:, GEN_STATUS) > 0 ...
0286 & gen(:, QG) > gen(:, QMAX) + mpopt.opf.violation );
0287 mn = find( gen(:, GEN_STATUS) > 0 ...
0288 & gen(:, QG) < gen(:, QMIN) - mpopt.opf.violation );
0289
0290 if ~isempty(mx) || ~isempty(mn)
0291
0292 infeas = union(mx', mn')';
0293
0294 remaining = find( gen(:, GEN_STATUS) > 0 & ...
0295 ( bus(gen(:, GEN_BUS), BUS_TYPE) == PV | ...
0296 bus(gen(:, GEN_BUS), BUS_TYPE) == REF ));
0297 if length(infeas) == length(remaining) && all(infeas == remaining) && ...
0298 (isempty(mx) || isempty(mn))
0299
0300
0301 if mpopt.verbose
0302 fprintf('All %d remaining gens exceed their Q limits : INFEASIBLE PROBLEM\n', length(infeas));
0303 end
0304 success = 0;
0305 break;
0306 end
0307
0308
0309 if qlim == 2
0310 [junk, k] = max([gen(mx, QG) - gen(mx, QMAX);
0311 gen(mn, QMIN) - gen(mn, QG)]);
0312 if k > length(mx)
0313 mn = mn(k-length(mx));
0314 mx = [];
0315 else
0316 mx = mx(k);
0317 mn = [];
0318 end
0319 end
0320
0321 if mpopt.verbose && ~isempty(mx)
0322 fprintf('Gen %d at upper Q limit, converting to PQ bus\n', mx);
0323 end
0324 if mpopt.verbose && ~isempty(mn)
0325 fprintf('Gen %d at lower Q limit, converting to PQ bus\n', mn);
0326 end
0327
0328
0329 fixedQg(mx) = gen(mx, QMAX);
0330 fixedQg(mn) = gen(mn, QMIN);
0331 mx = [mx;mn];
0332
0333
0334 gen(mx, QG) = fixedQg(mx);
0335 gen(mx, GEN_STATUS) = 0;
0336 for i = 1:length(mx)
0337 bi = gen(mx(i), GEN_BUS);
0338 bus(bi, [PD,QD]) = ...
0339 bus(bi, [PD,QD]) - gen(mx(i), [PG,QG]);
0340 end
0341 if length(ref) > 1 && any(bus(gen(mx, GEN_BUS), BUS_TYPE) == REF)
0342 error('runpf: Sorry, MATPOWER cannot enforce Q limits for slack buses in systems with multiple slacks.');
0343 end
0344 bus(gen(mx, GEN_BUS), BUS_TYPE) = PQ;
0345
0346
0347 ref_temp = ref;
0348 [ref, pv, pq] = bustypes(bus, gen);
0349
0350
0351
0352 if ref ~= ref_temp
0353 bus(ref, BUS_TYPE) = REF;
0354 bus( pv, BUS_TYPE) = PV;
0355 if mpopt.verbose
0356 fprintf('Bus %d is new slack bus\n', ref);
0357 end
0358 end
0359 limited = [limited; mx];
0360 else
0361 repeat = 0;
0362 end
0363 else
0364 repeat = 0;
0365 end
0366 end
0367 if qlim && ~isempty(limited)
0368
0369 gen(limited, QG) = fixedQg(limited);
0370 for i = 1:length(limited)
0371 bi = gen(limited(i), GEN_BUS);
0372 bus(bi, [PD,QD]) = ...
0373 bus(bi, [PD,QD]) + gen(limited(i), [PG,QG]);
0374 end
0375 gen(limited, GEN_STATUS) = 1;
0376 if ref ~= ref0
0377
0378 bus(:, VA) = bus(:, VA) - bus(ref0, VA) + Varef0;
0379 end
0380 end
0381 end
0382 else
0383 t0 = tic;
0384 success = 0;
0385 its = 0;
0386 if mpopt.verbose
0387 fprintf('Power flow not valid : MATPOWER case contains no connected buses');
0388 end
0389 end
0390 mpc.et = toc(t0);
0391 mpc.success = success;
0392 mpc.iterations = its;
0393
0394
0395
0396 [mpc.bus, mpc.gen, mpc.branch] = deal(bus, gen, branch);
0397 results = int2ext(mpc);
0398
0399
0400 if ~isempty(results.order.gen.status.off)
0401 results.gen(results.order.gen.status.off, [PG QG]) = 0;
0402 end
0403 if ~isempty(results.order.branch.status.off)
0404 results.branch(results.order.branch.status.off, [PF QF PT QT]) = 0;
0405 end
0406
0407 if fname
0408 [fd, msg] = fopen(fname, 'at');
0409 if fd == -1
0410 error(msg);
0411 else
0412 if mpopt.out.all == 0
0413 printpf(results, fd, mpoption(mpopt, 'out.all', -1));
0414 else
0415 printpf(results, fd, mpopt);
0416 end
0417 fclose(fd);
0418 end
0419 end
0420 printpf(results, 1, mpopt);
0421
0422
0423 if solvedcase
0424 savecase(solvedcase, results);
0425 end
0426
0427 if nargout == 1 || nargout == 2
0428 MVAbase = results;
0429 bus = success;
0430 elseif nargout > 2
0431 [MVAbase, bus, gen, branch, et] = ...
0432 deal(results.baseMVA, results.bus, results.gen, results.branch, results.et);
0433
0434 end
0435
0436 function TorF = have_zip_loads(mpopt)
0437 if (~isempty(mpopt.exp.sys_wide_zip_loads.pw) && ...
0438 any(mpopt.exp.sys_wide_zip_loads.pw(2:3))) || ...
0439 (~isempty(mpopt.exp.sys_wide_zip_loads.qw) && ...
0440 any(mpopt.exp.sys_wide_zip_loads.qw(2:3)))
0441 TorF = 1;
0442 else
0443 TorF = 0;
0444 end