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 npP = max([ size(offers.P.qty, 2) size(bids.P.qty, 2) ]);
0108 lamP = sparse(1:ng, 1:ng, bus(gbus, LAM_P), ng, ng) * ones(ng, npP);
0109 lamQ = sparse(1:ng, 1:ng, bus(gbus, LAM_Q), ng, ng) * ones(ng, npP);
0110
0111
0112 pf = zeros(length(L), 1);
0113 Qlim = (gen(L, QMIN) == 0) .* gen(L, QMAX) + ...
0114 (gen(L, QMAX) == 0) .* gen(L, QMIN);
0115 pf = Qlim ./ gen(L, PMIN);
0116
0117 gtee_prc.offer = 1;
0118 Poffer = offers.P;
0119 Poffer.lam = lamP(G,:);
0120 Poffer.total_qty = gen(G, PG);
0121
0122 Pbid = bids.P;
0123 Pbid.total_qty = -gen(L, PG);
0124 if haveQ
0125 Pbid.lam = lamP(L,:);
0126 gtee_prc.bid = 0;
0127 else
0128 Pbid.lam = lamP(L,:) + sparse(1:nL, 1:nL, pf, nL, nL) * lamQ(L,:);
0129 gtee_prc.bid = 1;
0130 end
0131
0132 [co.P, cb.P] = auction(Poffer, Pbid, mkt.auction_type, mkt.lim.P, gtee_prc);
0133
0134 if haveQ
0135 npQ = max([ size(offers.Q.qty, 2) size(bids.Q.qty, 2) ]);
0136
0137
0138 lamQ = sparse(1:ng, 1:ng, bus(gbus, LAM_Q), ng, ng) * ones(ng, npQ);
0139
0140 Qoffer = offers.Q;
0141 Qoffer.lam = lamQ;
0142 Qoffer.total_qty = (gen(:, QG) > 0) .* gen(:, QG);
0143
0144 Qbid = bids.Q;
0145 Qbid.lam = lamQ;
0146 Qbid.total_qty = (gen(:, QG) < 0) .* -gen(:, QG);
0147
0148
0149
0150 [co.Q, cb.Q] = auction(Qoffer, Qbid, mkt.auction_type, mkt.lim.Q, gtee_prc);
0151 end
0152
0153 quantity = gen(:, PG);
0154 price = zeros(ng, 1);
0155 price(G) = co.P.prc(:, 1);
0156 price(L) = cb.P.prc(:, 1);
0157 if npP == 1
0158 k = find( co.P.qty );
0159 price(G(k)) = co.P.prc(k, :);
0160 k = find( cb.P.qty );
0161 price(L(k)) = cb.P.prc(k, :);
0162 else
0163 k = find( sum( co.P.qty' )' );
0164 price(G(k)) = sum( co.P.qty(k, :)' .* co.P.prc(k, :)' )' ./ sum( co.P.qty(k, :)' )';
0165 k = find( sum( cb.P.qty' )' );
0166 price(L(k)) = sum( cb.P.qty(k, :)' .* cb.P.prc(k, :)' )' ./ sum( cb.P.qty(k, :)' )';
0167 end
0168 else
0169 quantity = zeros(ng, 1);
0170 price = mkt.lim.P.max_offer * ones(ng, 1);
0171 co.P.qty = zeros(size(offers.P.qty));
0172 co.P.prc = zeros(size(offers.P.prc));
0173 cb.P.qty = zeros(size(bids.P.qty));
0174 cb.P.prc = zeros(size(bids.P.prc));
0175 if haveQ
0176 co.Q.qty = zeros(size(offers.Q.qty));
0177 co.Q.prc = zeros(size(offers.Q.prc));
0178 cb.Q.qty = zeros(size(bids.Q.qty));
0179 cb.Q.prc = zeros(size(bids.Q.prc));
0180 end
0181 end
0182
0183
0184
0185 fcost = mkt.t * totcost(mpc.gencost, zeros(ng, 1) );
0186 vcost = mkt.t * totcost(mpc.gencost, quantity ) - fcost;
0187 scost = (~mkt.u0 & gen(:, GEN_STATUS) > 0) .* ...
0188 mpc.gencost(:, STARTUP) + ...
0189 ( mkt.u0 & gen(:, GEN_STATUS) <= 0) .* ...
0190 mpc.gencost(:, SHUTDOWN);
0191
0192
0193 dispatch = zeros(ng, PENALTY);
0194 dispatch(:, [QUANTITY PRICE FCOST VCOST SCOST]) = [quantity price fcost vcost scost];