Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000
A Power Flow in Matlab © 1999, 2000 Fernando L. Alvarado This section describes the development and extension of a basic power flow program in Matlab. To the extent feasible, complex vector operations are used, even for the calculation of the Jacobian matrix1.
The problem The main problem of interest in power system analysis is the solution of the so-called power flow (or load flow) problem. The assumptions for the basic power flow problem are: •
A passive linear network network of admittances describes the transmission grid. The nodal admittance matrix Y-bus (denoted by Y) characterizes the behavior of the nodal voltages to nodal current injections. The components of Y of Y are complex numbers of the form the network. The dimension of Y of Y is n by n. Y ij = g ij + jbij . There are n nodes in the
•
Every node can have active and reactive generation and active and reactive demand, each represented as a complex number. number. The complete set of generation generation injections for the the network g d is denoted by the vector S , and the demands by the vector S , each a vector of dimension n.
•
Every node (or bus) is classified classified as either a PV or a PQ node. For a PV node, the voltage magnitude and the net power power injection are fixed, while while the generation Q is a variable. variable. For a PQ node, both the active and reactive net power injections are fixed (either positive or negative).
•
One node (usually a PV node) is designated designated as the angle reference for all all voltages. At least one node (usually the same PV node) is designated as a node where the net injection P is not specified but rather determined determined as a variable. Thus, in this node both voltage voltage magnitude and angle are known. The node is called called the slack node. When multiple multiple nodes are designated designated as
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 •
The voltage magnitudes and angles (or real and imaginary parts of the voltages) for all PQ nodes.
•
The voltage angles at all PV nodes.
All other variables (such as Q at PV nodes or P and Q at the slack node) can be determined after the fact from the above equation. There are situations where the explicit rectangular form of the power flow equations is more desirable than the concise complex vectorized version above. For these situations, the following
∆Pi = − Pi + | V i | ∑ | V j | g ij cos(δ i j∈α ˆ ∆Qi = −Qi + | V i | ∑ | V j | g ij sin(δ i j∈α i
i
− δ j ) + ∑ | V j | bij sin(δ i − δ j ) j ∈α − δ j ) − ∑ | V j | bij cos(δ i − δ j ) ˆ j∈α i
i
is the set of power flow equations of interest: where gij and boj are the real and imaginary components of the entries of the nodal admittance ^ matrix, δi is the angle of V i, αi denotes all neighbors or node i excluding i itself, and αi denotes the neighbors of i including i itself. In matrix form, these equations can be expressed as: d
g
*
∆S = S − S + V * ( Y V ) i
i
and from here the Jacobian can be determined from:
Fd I I * Fd V I = V.*G J+ I .*G J d | V| d V K d V K H H d S
*
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000
Building Y-bus (vectorized version) The following vectorized code builds the Y-bus matrix: function Ybus=bldybus(S) % bldybus.m Build the y-bus matrices Ybus=sparse(S.Bus.n,S.Bus.n); YL=[]; if isfield(S.Bus,'G'), YL=S.Bus.G; end if isfield(S.Bus,'B'), YL=YL+i*S.Bus.B; end if ~isempty(YL), Ybus=Ybus+diag(sparse(YL)); end n=S.Bus.n; Y11=(1./S.Branch.Z+(i*S.Branch.B)/2).*S.Branch.Status; Ybus=Ybus+sparse(S.Branch.From,S.Branch.From,Y11,n,n); Y12=(-1./(S.Branch.TAP.*S.Branch.Z)).*S.Branch.Status; Ybus=Ybus+sparse(S.Branch.From,S.Branch.To,Y12,n,n); Y21=(-1./(conj(S.Branch.TAP).*S.Branch.Z)).*S.Branch.Status; Ybus=Ybus+sparse(S.Branch.To,S.Branch.From,Y21,n,n); Y22=(1./((abs(S.Branch.TAP).^2).*S.Branch.Z)+(i*S.Branch.B)/2).*S.Branch.Stat us; Ybus=Ybus+sparse(S.Branch.To,S.Branch.To,Y22,n,n); if isfield(S.Branch,'YI'), Ybus=Ybus+sparse(S.Branch.From,S.Branch.From,S.Branch.YI,n,n); end if isfield(S.Branch,'YJ'), Ybus=Ybus+sparse(S.Branch.To,S.Branch.To,S.Branch.YJ,n,n); end if isfield(S,'Shunt'), Ybus=Ybus+sparse(S.Shunt.I,S.Shunt.I,i*S.Shunt.BINIT,n,n); end;
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 •
The appropriate matrices are constructed using the bldybus.m function, also available as a p-code file.
•
Some data conversion is performed (the solver assumes that net injections are used a nd does not distinguish between the positive power delivered to loads and the negative power delivered by generators).
•
The solver is called. It returns the complex voltages at every bus, and also the mismatch or maximum error.
•
The user is given an indication of completion.
The main routine within this code if pfsolve.m . While we have only provided the p-code for this routine, it is useful to examine a simplified version of this routine:
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 function S=pfsolve(S) % This routine solves the power flow problem using a Newton-Raphson % iteration with full Jacobian update at every iteration. % Originally developed by Professor Christopher DeMarco, 1997 % and expanded by Fernando Alvarado 1998, 1999 % % Compute initial mismatch MAXITER=15; n=S.Bus.n; vbus=S.Bus.Voltages; S.mismatch = Inf; % pick off largest component of relevant mismatch % Newton-Raphson Iteration S.itcnt = 0; while S.mismatch > .0001 4 fullmiss = pfmiss(S); rmiss=[real(fullmiss(S.PVlist));real(fullmiss(S.PQlist)); ... imag(fullmiss(S.PQlist))]; S.mismatch = max(abs(rmiss)); 6 [dsdd, dsdv] = pflowjac(S.Ybus,vbus);
1
2
3 10
7
% %
5
dsdd and dsdv are composed of all (complex) partial derivatives rjac is a selection from these rjac = [ ... real(dsdd(S.PVlist,S.PVlist)) real(dsdd(S.PVlist,S.PQlist)) ... real(dsdv(S.PVlist,S.PQlist)); ... real(dsdd(S.PQlist,S.PVlist)) real(dsdd(S.PQlist,S.PQlist)) ... real(dsdv(S.PQlist,S.PQlist)); ... imag(dsdd(S.PQlist,S.PVlist)) imag(dsdd(S.PQlist,S.PQlist)) ... imag(dsdv(S.PQlist,S.PQlist)) ]; x=[angle(vbus(S.PVlist))*pi/180; angle(vbus(S.PQlist))*pi/180; 8 abs(vbus(S.PQlist))]; dx = -rjac\rmiss; % Here is the actual update del=angle(vbus); vmag=abs(vbus); n1=length(S.PVlist); n2=n1+length(S.PQlist); n3=length(dx); del(S.PVlist)=del(S.PVlist)+dx(1:n1); del(S.PQlist)=del(S.PQlist)+dx((n1+1):n2); 9
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 4. The tolerance for this error is fixed at 0.0001, a suitable value for most applications. Normal termination is based on the mismatch being smaller that this value. 5. Although most computations are done in complex mode, it is still necessary to have available vectors with the polar representation of the voltages. 6. This is where the complex version of the complete Jacobian is computed. 7. This is where the real portion of the Jacobian of interest to us is extracted. 8. This is the main computational step: the solution of the simultaneous sparse linear equations. 9. This is where the correction is added to the previous solution value. 10. The mismatch fullmiss is computed for all buses, but only the portion of interest to us rmiss is extracted. 11. The solution also can terminate by exceeding the maximum allowed number of iterations,.
Extending the power flow The code above simply solves the basic power flow with no limits and finds the voltages and angles at every node. After this is done, there are generally a number of additional computations of interest. Some of these are described next.
Flows and overloads The real objective of solving a power flow is quite often to find the individual line flows in the network, and most particularly, to find whether there are any overloaded lines under the presumed conditions. While developing the code for doing this computation using for and while loops is straightforward. This section illustrates how to write this code in a vectorized manner. The following code determines and displays every flow in every line in the network, identifies any overloads, and displays a list of overloaded lines. function [Sflow,iOvld]=flows(S)
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 Function beta=penalty(S) % Construct the penalty factors [dSdd,dSdv]=pflowjac(S.Ybus,S.Bus.Voltages); Jac=[real(dSdd) real(dSdv); imag(dSdd) imag(dSdv)]; [n1,n2]=size(Jac); Jacr=Jac(2:n1,2:n2); % Assuming the slack bus is bus 1 rhs=-Jac(1,2:n2)'; beta=[1; Jacr'\rhs]; disp('Beta'); disp(full(reshape(beta,n2/2,2)));
The following comments apply to this code: 1. The same Jacobian computation routine as in the power flow is used. In fact, it is possible to save this Jacobian re-computation and just use the last Jacobian from the solution itself. 2. As before, real and imaginary parts of this complex Jacobian are extracted. Unlike the previous case, however, all entries of the Jacobian are used. This assumes that no buses are holding voltage constant. 3. The slack bus row and column are then excluded. In this simple version, the slack bus must be node 1. 4. The right hand side corresponds to the row of the omitted slack bus active power. 5. The solution involves the use of the transposed reduced Jacobian. 6. The reshape function permits a more elegant display of the computed beta inverse penalty factors.
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000
Using the power flow We now illustrate the use of the above code to solve several simple power flow cases. Consider the case illustrated below, from Wood and Wollenberg:
Bus3
Bus2
Bus6
Bus1 Bus5
Bus4 The common format data for this case is (save it as 6bus.cf): Wood and Wollenberg test BUS DATA FOLLOWS 1 BUS1 1 1 2 BUS2 1 1 3 BUS3 1 1 4 BUS4 1 1
case 3 2 2 0
1.0500 1.0500 1.0700 1 0000
0.00 0.00 0.00 0 00
0.00 0.00 0.00 70 00
0.00 0.00 0.00 70 00
100.00 50.00 60.00 00
.00 .00 .00
100.00 100.00 100.00
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 listed in the voltage magnitude field. Execution of the above power flow with this data as input yields the following: » fname='6bus'; » mpflow; mpflow (c)1997 F. Alvarado and C. DeMarco 2 iterations Power flow solved » mis mis = 1.4496e-006 » VV VV = (1,1) 1.0500 (2,1) 1.0478- 0.0682i (3,1) 1.0669- 0.0809i (4,1) 0.9838- 0.0719i (5,1) 0.9756- 0.0892i (6,1) 0.9960- 0.1042i » rect2pol(VV) ans = (1,1) 1.0500 (2,1) 1.0500- 3.7248i (3,1) 1.0700- 4.3340i (4,1) 0.9864- 4.1788i (5,1) 0.9797- 5.2240i (6,1) 1.0014- 5.9705i
The following comments apply: 1. The output from the code is minimal. The final mismatch and the VV output had to be manually extracted after the solution ended. 2. The final mismatch is quite small. 3. The rect2pol function gives the output as complex numbers, but the interpretation is that the real part of the numbers is the magnitude of VV and the imaginary part is the angle in
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 » penalty Beta 1.0000 1.0154 1.0188 1.0289 1.0331 1.0264
-0.1590 -0.1777 -0.1792 -0.1460 -0.1504 -0.1702
The first column entries are the inverses of the penalty factors for the active powers at every node in the network. The second column entries are the corresponding factors for the reactive powers.
The Fast Decoupled power flow Approximations to the Jacobian slow down convergence, but do not change the solution. The Fast Decoupled power flow uses the same mismatch equations, but approximates the Jacobian in several ways: •
Conductances G are neglected.
•
Voltage magnitudes are assumed to be 1pu.
•
Voltage angles are small. Terms containing cosines are replaced by 1, terms containing sines are set to zero.
The result of these approximations is a Jacobian that is decoupled, requires no trigonometric computations, and remains constant from iteration to iteration.
The DC load flow Approximations to the energy balance (or mismatch) equations do alter the solution. However, there are many cases where a fast, non-iterative linear solution is adequate for e stimation purposes. In these cases, the “DC power flow” can be used. The same approximations as for the Fast Decoupled power flow are used, but these approximations are applied to the mismatch
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 must stay at 1pu. Hint: this will occur when the penalty factors for all the Qs are zero, and the penalty factors for all the Ps are unity. 5. Write a script using the above code to determine the maximum increase possible in the demands in the network before an overload occurs. Assume that for every MW of demand increase in the load there is a corresponding MW increase in the supply, which is distributed among the generators in direct proportion to their size. Increase only the P component of every demand, in direct proportion to their size. Report the total system demand value at which the overload occurs.
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000
Appendix A: Supporting routines This appendix lists sufficient versions of the necessary supporting routines, without commentary. The following code computes the mismatch: function nmiss = pfmiss(S) % Form the vector of complex power mismatches. % Usage: nmiss = pfmiss(Y,vb,s_net_inject) % Arguments: complex bus admittance matrix, Y; % vector of complex bus voltage phasors, vb; % vector of complex bus power demand (net), % S.snet; (note that s_net_inject will be % negative at buses demanding power) % Returns: a full complex n-vector of power mismatches. % Power LEAVING the bus is positive % Comments: Note that we return ALL mismatches at EVERY bus. ib=S.Ybus*S.Bus.Voltages; nmiss = S.Bus.Voltages.*conj(ib)-S.snet;
The following code computes the Jacobian: function [dSdd,dSdv] = pflowjac(Y,vb) % Construct the power flow Jacobian matrix in complex form % Usage: [dSdd,dSdv] = pflowjac(Y,vb) % Arguments: complex bus admittance matrix, Y; % vector of complex bus voltage phasors, vb. % Returns: Two full, complex nxn matrices of partial derivatives; % dSdd = partial of complex power w.r.t. delta; % dSdv = partial of complex power w.r.t. voltage magnitude. % Comments: We return ALL the partial derivatives of power absorbed at EVERY % bus with respect to EVERY voltage magnitude and phase angle. % The operation of this routine is transparent if one recognizes that: % S = diag(vb)*conj(ib) = diag(conj(ib))*vb; % hence: % dS/d(delta) = diag(vb)*conj(d(ib)/d(delta))+diag(conj(ib))*d(vb)/d(delta) % dS/d(vmag) = diag(vb)*conj(d(ib)/d(vmag))+diag(conj(ib))*d(vb)/d(vmag)
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 The following code is a utility function scanint.m: function i=scanint(s,beg,last,default), % Function to read an integer from a designated field if nargin<4, default=0; end; i=default; [dummy,ns]=size(s); if ns
The following is the code for scanreal.m: function i=scanreal(s,beg,last,default), % Function to read a real from a designated field if nargin<4, default=0; end; i=default; [dummy,ns]=size(s); if ns
The next portion of code is the code necessary to read a common format file into a structure: function S=readcf(fname) % readcf.m % Read the common format file and create a data dictionary structure if nargin<1, [fname,pname]=uigetfile('*.cf'); fname=[pname fname]; end S.Misc.BaseMVA=100; fcf=fopen(fname,'r'); % Open common format file s=fgetl(fcf);
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 S.Bus.Name{n}=s(6:17); S.newBus(bus)=n; S.Machine.newGen(bus,1)=0; if (Pg~=0) | (Qg~=0) | (s(26)=='3') | (s(26)=='2'), ng=ng+1; S.Machine.newGen(bus,1)=ng; S.Machine.BusRef(ng,1)=bus; % Generation bus number S.Machine.MW(ng,1)=Pg/S.Misc.BaseMVA; % Active Power Generation (actual) S.Machine.MVAR(ng,1)=Qg/S.Misc.BaseMVA; % Reactive Power Generation S.Machine.Status(ng,1)=1; end if (Pd~=0) | (Qd~=0), nL=nL+1; newLoad(bus,1)=nL; S.Load.BusRef(nL,1)=bus; % Load bus number S.Load.MW(nL,1)=Pd/S.Misc.BaseMVA; % Net active power load S.Load.MVAR(nL,1)=Qd/S.Misc.BaseMVA; % Net reactive power load S.Load.Status(nL,1)=1; end; S.Bus.Generation(n,1)=(Pg+j*Qg)/S.Misc.BaseMVA; S.Bus.Load(n,1)=(Pd+j*Qd)/S.Misc.BaseMVA; S.Bus.Voltages(n,1)=scanreal(s,28,33,1)* ... exp(sqrt(-1)*scanreal(s,34,40)*pi/180); S.Bus.area(n,1)=sscanf(s(19:20),'%d'); % Now this is numeric, +1 S.Bus.Zone(n,:)=s(21:23); S.Bus.KV(n,1)=scanreal(s,77,83); if S.Machine.newGen(bus), S.Machine.MinOperatingVolt(ng,1)=scanreal(s,85,90); S.Machine.MaxOperatingVolt(ng,1)=scanreal(s,85,90); S.Machine.MaxQOutput(ng,1)=scanreal(s,91,98)/S.Misc.BaseMVA; S.Machine.MinQOutput(ng,1)=scanreal(s,99,106)/S.Misc.BaseMVA; S.Machine.ControlledBusRef(ng,1)=scanreal(s,124,128); end S.Bus.G(n,1)=scanreal(s,107,114); S.Bus.B(n,1)=scanreal(s,115,122); s=fgetl(fcf); while s(1)=='%', s=fgetl(fcf); end;
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 s=fgetl(fcf); % Next line while s(1)=='%', s=fgetl(fcf); end; % Skip comments end S.Branch.YI=zeros(nn,1); S.Branch.YJ=zeros(nn,1); S.Branch.Status=ones(nn,1); kzero=find(S.Branch.RateValue==0); % No zero ratings permitted S.Branch.RateValue(kzero)=Inf; while ~strcmp(s(1:3),'INT'), s=fgetl(fcf); end s=fgetl(fcf); while s(1)=='%', s=fgetl(fcf); end; nInterch=0; while ~strcmp(s(1:2),'-9'), nInterch=nInterch+1; S.Interch.I(nInterch,1)=scanint(s,1,2); S.Interch.ControlGenRef(nInterch,1)=scanint(s,3,7); S.Interch.SchedNetMW(nInterch,1)=scanreal(s,21,29)/S.Misc.BaseMVA; s=fgetl(fcf); while s(1)=='%', s=fgetl(fcf); end; end fclose(fcf); S.Machine.BusRef=S.newBus(S.Machine.BusRef)'; % Use internal bus numbers S.Load.BusRef=S.newBus(S.Load.BusRef)'; % " ky=find(S.Machine.ControlledBusRef); % " kx=S.Machine.ControlledBusRef(ky); S.Machine.ControlledBusRef(ky)=S.newBus(kx); S.Bus.n=length(S.Bus.Voltages); S.Branch.nn=length(S.Branch.From); S.Bus.area=S.Bus.area+dArea;
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000
Appendix B: Brief description of the common format for solved power flow data interchange
Taken from “Common Data Format for the Exchange of Solved Load Flow Data,” Working Group on a Common Format for the Exchange of Solved Load Flow Data, _IEEE Transactions on Power Apparatus and Systems, Vol. PAS-92, No. 6, November/December 1973, pp. 19161925. Only the “tape” format (with lines of up to 128 characters) is described here. The data is organized into sections with section headers and terminated with numeric flags (usually –9 or –999). Data items are entered in specific columns. Mandatory items are indicated. No blank items are allowed for mandatory items (note: most program will, nevertheless, default some blank items). Floating point items should have explicit decimal point. No implicit decimal points are used. Data type codes: A - Alphanumeric (no special characters) I – Integer F - Floating point * - Mandatory item TAPE First line is the title, it also contains the Base MVA, usually 100 BUS DATA FOLLOWS Co lu mns 1 - 4 Columns 7-17 Columns 19-20 Columns 21-23 Columns 25-26
Bu s n um ber (I ) * Name (A) (left justified) * Load flow area number (I) Don't use zero! * Loss zone number (I) Type (I) * 0 - Unregulated (load, PQ) 1 - Hold MVAR generation within voltage limits, (PQ) 2 - Hold voltage within VAR limits (gen, PV) 3 - Hold voltage and angle (swing V-Theta)
Simulation and Analysis of Power Systems and Power Electronics in MATLAB Montreal, lecture 1, Wednesday September 13, 2000 Columns Columns Columns Columns Columns Columns Columns Column
20-29 30-40 41-50 51-55 57-61 63-67 69-72 74
Branch resistance R, per unit (F) * Branch reactance X, per unit (F) * No zero impedance lines Line charging B, per unit (F) * ( total line charging, +B) Line MVA rating No 1 (I) Left justify! Line MVA rating No 2 (I) Left justify! Line MVA rating No 3 (I) Left justify! Control bus number Side (I) 0 - Controlled bus is one of the terminals 1 - Controlled bus is near the tap side 2 - Controlled bus is near the impedance side (Z bus) Columns 77-82 Transformer final turns ratio (F) Columns 84-90 Transformer (phase shifter) final angle (F) Columns 91-97 Minimum tap or phase shift (F) Columns 98-104 Maximum tap or phase shift (F) Columns 106-111 Step size (F) Columns 113-119 Minimum voltage, MVAR or MW limit (F) Columns 120-126 Maximum voltage, MVAR or MW limit (F)
-999 LOSS ZONES FOLLOWS Columns Columns
1- 3 5-16
Loss zone number (I) Loss zone name (A)
-99 INTERCHANGE DATA FOLLOWS Columns Columns Columns Columns Columns Columns Columns
1- 2 4- 7 9-20 21-28 30-35 38-43 46-75
Area number (I) no zeros! * Interchange slack bus number (I) * Alternate swing bus name (A) Area interchange export, MW (F) (+ = out) * Area interchange tolerance, MW (F) * Area code (abbreviated name) (A) * Area name (A)
-9 TIE LINES FOLLOW Columns Columns Columns Columns Column
–999
1- 4 7-8 11-14 17-18 21
Metered bus number (I) Metered area number (I) Non-metered bus number (I) Non-metered area number (I) Circuit number