0001 function [co, cb, r, dispatch, success] = ...
0002 smartmkt(mpc, offers, bids, mkt, mpopt)
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 if nargin < 5
0039 mpopt = mpoption;
0040 end
0041
0042
0043 verbose = mpopt(31);
0044
0045
0046 G = find( ~isload(mpc.gen) );
0047 L = find( isload(mpc.gen) );
0048 nL = length(L);
0049 if isfield(offers, 'Q') || isfield(bids, 'Q')
0050 haveQ = 1;
0051 else
0052 haveQ = 0;
0053 end
0054
0055 if haveQ && mkt.auction_type ~= 0 && mkt.auction_type ~= 5
0056 error(['smartmkt: Combined active/reactive power markets ', ...
0057 'are only implemented for auction types 0 and 5']);
0058 end
0059
0060
0061 mpopt = mpoption(mpopt, 'PF_DC', strcmp(mkt.OPF, 'DC'));
0062
0063
0064 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0065 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0066 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0067 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0068 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0069 [PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;
0070 [QUANTITY, PRICE, FCOST, VCOST, SCOST, PENALTY] = idx_disp;
0071
0072
0073 mkt.lim = pricelimits(mkt.lim, isfield(offers, 'Q') || isfield(bids, 'Q'));
0074 [gen, genoffer] = off2case(mpc.gen, mpc.gencost, offers, bids, mkt.lim);
0075
0076
0077
0078
0079 if any(find(genoffer(:, MODEL) == PW_LINEAR))
0080 gg = find( ~isload(gen) );
0081 gen(gg, PMIN) = gen(gg, PMIN) - 100 * mpopt(16) * ones(size(gg));
0082 gen(gg, PMAX) = gen(gg, PMAX) + 100 * mpopt(16) * ones(size(gg));
0083 end
0084
0085
0086
0087 mpc2 = mpc;
0088 mpc2.gen = gen;
0089 mpc2.gencost = genoffer;
0090 [r, success] = uopf(mpc2, mpopt);
0091 [bus, gen] = deal(r.bus, r.gen);
0092 if verbose && ~success
0093 fprintf('\nSMARTMARKET: non-convergent UOPF');
0094 end
0095
0096
0097
0098 ng = size(gen, 1);
0099 if success
0100
0101 i2e = bus(:, BUS_I);
0102 e2i = sparse(max(i2e), 1);
0103 e2i(i2e) = (1:size(bus, 1))';
0104
0105
0106 gbus = e2i(gen(:, GEN_BUS));
0107 nPo = size(offers.P.qty, 2);
0108 nPb = size(bids.P.qty, 2);
0109 nP = max([ nPo nPb ]);
0110 lamP = sparse(1:ng, 1:ng, bus(gbus, LAM_P), ng, ng) * ones(ng, nP);
0111 lamQ = sparse(1:ng, 1:ng, bus(gbus, LAM_Q), ng, ng) * ones(ng, nP);
0112
0113
0114 pf = zeros(length(L), 1);
0115 Qlim = (gen(L, QMIN) == 0) .* gen(L, QMAX) + ...
0116 (gen(L, QMAX) == 0) .* gen(L, QMIN);
0117 pf = Qlim ./ gen(L, PMIN);
0118
0119 gtee_prc.offer = 1;
0120 Poffer = offers.P;
0121 Poffer.lam = lamP(G,1:nPo);
0122 Poffer.total_qty = gen(G, PG);
0123
0124 Pbid = bids.P;
0125 Pbid.total_qty = -gen(L, PG);
0126 if haveQ
0127 Pbid.lam = lamP(L,1:nPb);
0128 gtee_prc.bid = 0;
0129 else
0130 Pbid.lam = lamP(L,1:nPb) + sparse(1:nL, 1:nL, pf, nL, nL) * lamQ(L,1:nPb);
0131 gtee_prc.bid = 1;
0132 end
0133
0134 [co.P, cb.P] = auction(Poffer, Pbid, mkt.auction_type, mkt.lim.P, gtee_prc);
0135
0136 if haveQ
0137 nQo = size(offers.Q.qty, 2);
0138 nQb = size(bids.Q.qty, 2);
0139 nQ = max([ nQo nQb ]);
0140
0141
0142 lamQ = sparse(1:ng, 1:ng, bus(gbus, LAM_Q), ng, ng) * ones(ng, nQ);
0143
0144 Qoffer = offers.Q;
0145 Qoffer.lam = lamQ(:,1:nQo);
0146 Qoffer.total_qty = (gen(:, QG) > 0) .* gen(:, QG);
0147
0148 Qbid = bids.Q;
0149 Qbid.lam = lamQ(:,1:nQb);
0150 Qbid.total_qty = (gen(:, QG) < 0) .* -gen(:, QG);
0151
0152
0153
0154 [co.Q, cb.Q] = auction(Qoffer, Qbid, mkt.auction_type, mkt.lim.Q, gtee_prc);
0155 end
0156
0157 quantity = gen(:, PG);
0158 price = zeros(ng, 1);
0159 price(G) = co.P.prc(:, 1);
0160 price(L) = cb.P.prc(:, 1);
0161 if nP == 1
0162 k = find( co.P.qty );
0163 price(G(k)) = co.P.prc(k, :);
0164 k = find( cb.P.qty );
0165 price(L(k)) = cb.P.prc(k, :);
0166 else
0167 k = find( sum( co.P.qty' )' );
0168 price(G(k)) = sum( co.P.qty(k, :)' .* co.P.prc(k, :)' )' ./ sum( co.P.qty(k, :)' )';
0169 k = find( sum( cb.P.qty' )' );
0170 price(L(k)) = sum( cb.P.qty(k, :)' .* cb.P.prc(k, :)' )' ./ sum( cb.P.qty(k, :)' )';
0171 end
0172 else
0173 quantity = zeros(ng, 1);
0174 price = mkt.lim.P.max_offer * ones(ng, 1);
0175 co.P.qty = zeros(size(offers.P.qty));
0176 co.P.prc = zeros(size(offers.P.prc));
0177 cb.P.qty = zeros(size(bids.P.qty));
0178 cb.P.prc = zeros(size(bids.P.prc));
0179 if haveQ
0180 co.Q.qty = zeros(size(offers.Q.qty));
0181 co.Q.prc = zeros(size(offers.Q.prc));
0182 cb.Q.qty = zeros(size(bids.Q.qty));
0183 cb.Q.prc = zeros(size(bids.Q.prc));
0184 end
0185 end
0186
0187
0188
0189 fcost = mkt.t * totcost(mpc.gencost, zeros(ng, 1) );
0190 vcost = mkt.t * totcost(mpc.gencost, quantity ) - fcost;
0191 scost = (~mkt.u0 & gen(:, GEN_STATUS) > 0) .* ...
0192 mpc.gencost(:, STARTUP) + ...
0193 ( mkt.u0 & gen(:, GEN_STATUS) <= 0) .* ...
0194 mpc.gencost(:, SHUTDOWN);
0195
0196
0197 dispatch = zeros(ng, PENALTY);
0198 dispatch(:, [QUANTITY PRICE FCOST VCOST SCOST]) = [quantity price fcost vcost scost];