SCALE_LOAD Scales fixed and/or dispatchable loads. BUS = SCALE_LOAD(LOAD, BUS); [BUS, GEN] = SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT) [BUS, GEN, GENCOST] = ... SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT, GENCOST) Scales active (and optionally reactive) loads in each zone by a zone-specific ratio, i.e. R(k) for zone k. Inputs are ... LOAD - Each element specifies the amount of scaling for the corresponding load zone, either as a direct scale factor or as a target quantity. If there are nz load zones this vector has nz elements. BUS - standard BUS matrix with nb rows, where the fixed active and reactive loads available for scaling are specified in columns PD and QD GEN - (optional) standard GEN matrix with ng rows, where the dispatchable loads available for scaling are specified by columns PG, QG, PMIN, QMIN and QMAX (in rows for which ISLOAD(GEN) returns true). If GEN is empty, it assumes there are no dispatchable loads. LOAD_ZONE - (optional) nb element vector where the value of each element is either zero or the index of the load zone to which the corresponding bus belongs. If LOAD_ZONE(b) = k then the loads at bus b will be scaled according to the value of LOAD(k). If LOAD_ZONE(b) = 0, the loads at bus b will not be modified. If LOAD_ZONE is empty, the default is determined by the dimensions of the LOAD vector. If LOAD is a scalar, a single system-wide zone including all buses is used, i.e. LOAD_ZONE = ONES(nb, 1). If LOAD is a vector, the default LOAD_ZONE is defined as the areas specified in the BUS matrix, i.e. LOAD_ZONE = BUS(:, BUS_AREA), and LOAD should have dimension = MAX(BUS(:, BUS_AREA)). OPT - (optional) struct with three possible fields, 'scale', 'pq' and 'which' that determine the behavior as follows: OPT.scale (default is 'FACTOR') 'FACTOR' : LOAD consists of direct scale factors, where LOAD(k) = scale factor R(k) for zone k 'QUANTITY' : LOAD consists of target quantities, where LOAD(k) = desired total active load in MW for zone k after scaling by an appropriate R(k) OPT.pq (default is 'PQ') 'PQ' : scale both active and reactive loads 'P' : scale only active loads OPT.which (default is 'BOTH' if GEN is provided, else 'FIXED') 'FIXED' : scale only fixed loads 'DISPATCHABLE' : scale only dispatchable loads 'BOTH' : scale both fixed and dispatchable loads GENCOST - (optional) standard GENCOST matrix with ng (or 2*ng) rows, where the dispatchable load rows are determined by the GEN matrix. If included, the quantity axis of the marginal "cost" or benefit function of any dispatchable loads will be scaled with the size of the load itself (using MODCOST twice, once with MODTYPE equal to SCALE_F and once with SCALE_X). Examples: Scale all real and reactive fixed loads up by 10%. bus = scale_load(1.1, bus); Scale all active loads (fixed and dispatchable) at the first 10 buses so their total equals 100 MW, and at next 10 buses so their total equals 50 MW. load_zone = zeros(nb, 1); load_zone(1:10) = 1; load_zone(11:20) = 2; opt = struct('pq', 'P', 'scale', 'QUANTITY'); load = [100; 50]; [bus, gen] = scale_load(load, bus, gen, load_zone, opt); See also TOTAL_LOAD.
0001 function [bus, gen, gencost] = scale_load(load, bus, gen, load_zone, opt, gencost) 0002 %SCALE_LOAD Scales fixed and/or dispatchable loads. 0003 % BUS = SCALE_LOAD(LOAD, BUS); 0004 % [BUS, GEN] = SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT) 0005 % [BUS, GEN, GENCOST] = ... 0006 % SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT, GENCOST) 0007 % 0008 % Scales active (and optionally reactive) loads in each zone by a 0009 % zone-specific ratio, i.e. R(k) for zone k. Inputs are ... 0010 % 0011 % LOAD - Each element specifies the amount of scaling for the 0012 % corresponding load zone, either as a direct scale factor 0013 % or as a target quantity. If there are nz load zones this 0014 % vector has nz elements. 0015 % 0016 % BUS - standard BUS matrix with nb rows, where the fixed active 0017 % and reactive loads available for scaling are specified in 0018 % columns PD and QD 0019 % 0020 % GEN - (optional) standard GEN matrix with ng rows, where the 0021 % dispatchable loads available for scaling are specified by 0022 % columns PG, QG, PMIN, QMIN and QMAX (in rows for which 0023 % ISLOAD(GEN) returns true). If GEN is empty, it assumes 0024 % there are no dispatchable loads. 0025 % 0026 % LOAD_ZONE - (optional) nb element vector where the value of 0027 % each element is either zero or the index of the load zone 0028 % to which the corresponding bus belongs. If LOAD_ZONE(b) = k 0029 % then the loads at bus b will be scaled according to the 0030 % value of LOAD(k). If LOAD_ZONE(b) = 0, the loads at bus b 0031 % will not be modified. If LOAD_ZONE is empty, the default is 0032 % determined by the dimensions of the LOAD vector. If LOAD is 0033 % a scalar, a single system-wide zone including all buses is 0034 % used, i.e. LOAD_ZONE = ONES(nb, 1). If LOAD is a vector, the 0035 % default LOAD_ZONE is defined as the areas specified in the 0036 % BUS matrix, i.e. LOAD_ZONE = BUS(:, BUS_AREA), and LOAD 0037 % should have dimension = MAX(BUS(:, BUS_AREA)). 0038 % 0039 % OPT - (optional) struct with three possible fields, 'scale', 0040 % 'pq' and 'which' that determine the behavior as follows: 0041 % 0042 % OPT.scale (default is 'FACTOR') 0043 % 'FACTOR' : LOAD consists of direct scale factors, where 0044 % LOAD(k) = scale factor R(k) for zone k 0045 % 'QUANTITY' : LOAD consists of target quantities, where 0046 % LOAD(k) = desired total active load in MW for 0047 % zone k after scaling by an appropriate R(k) 0048 % 0049 % OPT.pq (default is 'PQ') 0050 % 'PQ' : scale both active and reactive loads 0051 % 'P' : scale only active loads 0052 % 0053 % OPT.which (default is 'BOTH' if GEN is provided, else 'FIXED') 0054 % 'FIXED' : scale only fixed loads 0055 % 'DISPATCHABLE' : scale only dispatchable loads 0056 % 'BOTH' : scale both fixed and dispatchable loads 0057 % 0058 % GENCOST - (optional) standard GENCOST matrix with ng (or 2*ng) 0059 % rows, where the dispatchable load rows are determined by 0060 % the GEN matrix. If included, the quantity axis of the marginal 0061 % "cost" or benefit function of any dispatchable loads will be 0062 % scaled with the size of the load itself (using MODCOST twice, 0063 % once with MODTYPE equal to SCALE_F and once with SCALE_X). 0064 % 0065 % Examples: 0066 % Scale all real and reactive fixed loads up by 10%. 0067 % 0068 % bus = scale_load(1.1, bus); 0069 % 0070 % Scale all active loads (fixed and dispatchable) at the first 10 0071 % buses so their total equals 100 MW, and at next 10 buses so their 0072 % total equals 50 MW. 0073 % 0074 % load_zone = zeros(nb, 1); 0075 % load_zone(1:10) = 1; 0076 % load_zone(11:20) = 2; 0077 % opt = struct('pq', 'P', 'scale', 'QUANTITY'); 0078 % load = [100; 50]; 0079 % [bus, gen] = scale_load(load, bus, gen, load_zone, opt); 0080 % 0081 % See also TOTAL_LOAD. 0082 0083 % MATPOWER 0084 % $Id: scale_load.m 2122 2013-03-13 20:08:01Z ray $ 0085 % by Ray Zimmerman, PSERC Cornell 0086 % Copyright (c) 2004-2010 by Power System Engineering Research Center (PSERC) 0087 % 0088 % This file is part of MATPOWER. 0089 % See http://www.pserc.cornell.edu/matpower/ for more info. 0090 % 0091 % MATPOWER is free software: you can redistribute it and/or modify 0092 % it under the terms of the GNU General Public License as published 0093 % by the Free Software Foundation, either version 3 of the License, 0094 % or (at your option) any later version. 0095 % 0096 % MATPOWER is distributed in the hope that it will be useful, 0097 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0098 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0099 % GNU General Public License for more details. 0100 % 0101 % You should have received a copy of the GNU General Public License 0102 % along with MATPOWER. If not, see <http://www.gnu.org/licenses/>. 0103 % 0104 % Additional permission under GNU GPL version 3 section 7 0105 % 0106 % If you modify MATPOWER, or any covered work, to interface with 0107 % other modules (such as MATLAB code and MEX-files) available in a 0108 % MATLAB(R) or comparable environment containing parts covered 0109 % under other licensing terms, the licensors of MATPOWER grant 0110 % you additional permission to convey the resulting work. 0111 0112 %% define constants 0113 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ... 0114 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus; 0115 %% purposely being backward compatible with older MATPOWER 0116 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, ... 0117 PMAX, PMIN, MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN] = idx_gen; 0118 0119 nb = size(bus, 1); %% number of buses 0120 0121 %%----- process inputs ----- 0122 if nargin < 6 0123 gencost = []; 0124 if nargin < 5 0125 opt = struct; 0126 if nargin < 4 0127 load_zone = []; 0128 if nargin < 3 0129 gen = []; 0130 end 0131 end 0132 end 0133 end 0134 0135 %% fill out and check opt 0136 if isempty(gen) 0137 opt.which = 'FIXED'; 0138 end 0139 if ~isfield(opt, 'pq') 0140 opt.pq = 'PQ'; %% 'PQ' or 'P' 0141 end 0142 if ~isfield(opt, 'which') 0143 opt.which = 'BOTH'; %% 'FIXED', 'DISPATCHABLE' or 'BOTH' 0144 end 0145 if ~isfield(opt, 'scale') 0146 opt.scale = 'FACTOR'; %% 'FACTOR' or 'QUANTITY' 0147 end 0148 if ~strcmp(opt.pq, 'P') && ~strcmp(opt.pq, 'PQ') 0149 error('scale_load: opt.pq must equal ''PQ'' or ''P'''); 0150 end 0151 if opt.which(1) ~= 'F' && opt.which(1) ~= 'D' && opt.which(1) ~= 'B' 0152 error('scale_load: opt.which should be ''FIXED'', ''DISPATCHABLE'' or ''BOTH'''); 0153 end 0154 if opt.scale(1) ~= 'F' && opt.scale(1) ~= 'Q' 0155 error('scale_load: opt.scale should be ''FACTOR'' or ''QUANTITY'''); 0156 end 0157 if isempty(gen) && opt.which(1) ~= 'F' 0158 error('scale_load: need gen matrix to scale dispatchable loads'); 0159 end 0160 if nargout < 3 && ~isempty(gencost) 0161 error('scale_load: missing gencost as output argument'); 0162 end 0163 if nargout > 2 && isempty(gencost) 0164 error('scale_load: missing gencost as input argument'); 0165 end 0166 0167 %% create dispatchable load connection matrix 0168 if ~isempty(gen) 0169 ng = size(gen, 1); 0170 is_ld = isload(gen) & gen(:, GEN_STATUS) > 0; 0171 ld = find(is_ld); 0172 0173 %% create map of external bus numbers to bus indices 0174 i2e = bus(:, BUS_I); 0175 e2i = sparse(max(i2e), 1); 0176 e2i(i2e) = (1:nb)'; 0177 0178 Cld = sparse(e2i(gen(:, GEN_BUS)), (1:ng)', is_ld, nb, ng); 0179 else 0180 ng = []; 0181 ld = []; 0182 end 0183 0184 if isempty(load_zone) 0185 if length(load) == 1 %% make a single zone of all load buses 0186 load_zone = zeros(nb, 1); %% initialize 0187 load_zone(bus(:, PD) ~= 0 | bus(:, QD) ~= 0) = 1; %% FIXED loads 0188 if ~isempty(gen) 0189 load_zone(e2i(gen(ld, GEN_BUS))) = 1; %% DISPATCHABLE loads 0190 end 0191 else %% use areas defined in bus data as zones 0192 load_zone = bus(:, BUS_AREA); 0193 end 0194 end 0195 0196 %% check load_zone to make sure it's consistent with size of load vector 0197 if max(load_zone) > length(load) 0198 error('scale_load: load vector must have a value for each load zone specified'); 0199 end 0200 0201 %%----- compute scale factors for each zone ----- 0202 scale = load; 0203 Pdd = zeros(nb, 1); %% dispatchable P at each bus 0204 if opt.scale(1) == 'Q' %% 'QUANTITY' 0205 %% find load capacity from dispatchable loads 0206 if ~isempty(gen) 0207 Pdd = -Cld * gen(:, PMIN); 0208 end 0209 0210 %% compute scale factors 0211 for k = 1:length(load) 0212 idx = find( load_zone == k ); 0213 fixed = sum(bus(idx, PD)); 0214 dispatchable = sum(Pdd(idx)); 0215 total = fixed + dispatchable; 0216 if opt.which(1) == 'B' %% 'BOTH' 0217 if total ~= 0 0218 scale(k) = load(k) / total; 0219 elseif load(k) == total 0220 scale(k) = 1; 0221 else 0222 error('scale_load: impossible to make zone %d load equal %g by scaling non-existent loads', k, load(k)); 0223 end 0224 elseif opt.which(1) == 'F' %% 'FIXED' 0225 if fixed ~= 0 0226 scale(k) = (load(k) - dispatchable) / fixed; 0227 elseif load(k) == dispatchable 0228 scale(k) = 1; 0229 else 0230 error('scale_load: impossible to make zone %d load equal %g by scaling non-existent fixed load', k, load(k)); 0231 end 0232 elseif opt.which(1) == 'D' %% 'DISPATCHABLE' 0233 if dispatchable ~= 0 0234 scale(k) = (load(k) - fixed) / dispatchable; 0235 elseif load(k) == fixed 0236 scale(k) = 1; 0237 else 0238 error('scale_load: impossible to make zone %d load equal %g by scaling non-existent dispatchable load', k, load(k)); 0239 end 0240 end 0241 end 0242 end 0243 0244 %%----- do the scaling ----- 0245 %% fixed loads 0246 if opt.which(1) ~= 'D' %% includes 'FIXED', not 'DISPATCHABLE' only 0247 for k = 1:length(scale) 0248 idx = find( load_zone == k ); 0249 bus(idx, PD) = bus(idx, PD) * scale(k); 0250 if strcmp(opt.pq, 'PQ') 0251 bus(idx, QD) = bus(idx, QD) * scale(k); 0252 end 0253 end 0254 end 0255 0256 %% dispatchable loads 0257 if opt.which(1) ~= 'F' %% includes 'DISPATCHABLE', not 'FIXED' only 0258 for k = 1:length(scale) 0259 idx = find( load_zone == k ); 0260 [junk, i, junk2] = intersect(e2i(gen(ld, GEN_BUS)), idx); 0261 ig = ld(i); 0262 0263 gen(ig, [PG PMIN]) = gen(ig, [PG PMIN]) * scale(k); 0264 if ~isempty(gencost) 0265 gencost(ig, :) = modcost(gencost(ig, :), scale(k), 'SCALE_F'); 0266 gencost(ig, :) = modcost(gencost(ig, :), scale(k), 'SCALE_X'); 0267 end 0268 if strcmp(opt.pq, 'PQ') 0269 gen(ig, [QG QMIN QMAX]) = gen(ig, [QG QMIN QMAX]) * scale(k); 0270 if ~isempty(gencost) 0271 [pcost, qcost] = pqcost(gencost, ng); 0272 if ~isempty(qcost) 0273 qcost(ig, :) = modcost(qcost(ig, :), scale(k), 'SCALE_F'); 0274 qcost(ig, :) = modcost(qcost(ig, :), scale(k), 'SCALE_X'); 0275 gencost = [pcost; qcost]; 0276 end 0277 end 0278 end 0279 end 0280 end