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