⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fm_spf.m

📁 这是一个很适合研究和学习用的电力系统仿真软件
💻 M
字号:
function fm_spf
% FM_SPF solve standard power flow by means of the NR method
%       and fast decoupled power flow (XB and BX variations)
%       with either a single or distributed slack bus model.
%
% FM_SPF
%
%see the properties of the Settings structure for options.
%
%Author:    Federico Milano
%Date:      11-Nov-2002
%Update:    09-Jul-2003
%Version:   1.0.1
%
%E-mail:    fmilano@thunderbox.uwaterloo.ca
%Web-site:  http://thunderbox.uwaterloo.ca/~fmilano
%
% Copyright (C) 2002-2006 Federico Milano

fm_var
fm_disp
fm_disp('Newton-Raphson Method for Power Flow Computation')
if Settings.show
  fm_disp(['Data file "',Path.data,File.data,'"'])
end
nodyn = 0;

% these computations are needed only the first time the power flow is run
if ~Settings.init
  % bus type initialization
  fm_ncomp
  if ~Settings.ok, return, end
  % report components parameters to system bases
  if Settings.conv, fm_base, end
  % create the admittance matrix
  fm_y
  % create the FM_CALL FUNCTION
  if Settings.show, fm_disp('Writing file "fm_call" ...',1), end
  fm_wcall;
  Settings.refbus = SW.bus(1); % reference bus (for phase angle)
  fm_dynlf; % indicization of components used in power flow computations
end

% memory allocation for equations and Jacobians
if (DAE.n~=0)
  DAE.f = ones(DAE.n,1);  % differential equations
  DAE.x = ones(DAE.n,1);  % state variables
  fm_xfirst;
  DAE.Fx = sparse(DAE.n,DAE.n);   % df/dx
  DAE.Fy = sparse(DAE.n,2*Bus.n); % df/dy
  DAE.Gx = sparse(2*Bus.n,DAE.n); % dg/dx
else  % no dynamic elements
  nodyn = 1;
  DAE.n = 1;
  DAE.f = 0;
  DAE.x = 0;
  DAE.Fx = 1;
  DAE.Fy = sparse(1,2*Bus.n);
  DAE.Gx = sparse(2*Bus.n,1);
end

% check PF solver method
FDPF = Settings.pfsolver;
if FDPF > 1
  if Mn.n, mn = sum(~Mn.con(:,8));  else, mn = 0; end
  if Pl.n, pl = sum(~Pl.con(:,11)); else, pl = 0; end
  ncload = mn + pl + Lines.n + (~nodyn);
  if ncload | Settings.distrsw,
    FDPF = 1; % force using standard NR method
  else
    fm_b
    no_sw = 1:Bus.n;
    no_sw(SW.bus) = [];
    no_g = 1:Bus.n;
    no_g([SW.bus; PV.bus]) = [];
    Bp = Line.Bp(no_sw,no_sw);
    Bpp = Line.Bpp(no_g,no_g);
    [Lp, Up, Pp] = lu(Bp);
    [Lpp, Upp, Ppp] = lu(Bpp);
  end
end

switch FDPF
 case 1, fm_disp('PF solver: Newton-Raphson method')
 case 2, fm_disp('PF solver: XB fast decoupled power flow method')
 case 3, fm_disp('PF solver: BX fast decoupled power flow method')
end

if Settings.distrsw
  DAE.Fk = sparse(DAE.n,1);
  DAE.Gk = sparse(2*Bus.n,1);
  Jrow = sparse(1,DAE.n+SW.bus,1,1,DAE.n+2*Bus.n+1);
  DAE.kg = 0;
  if ~swgamma(SW,'sum')
    fm_disp('Slack buses have zero power loss participation factor.')
    fm_disp('Single slack bus model will be used')
    Setting.distrsw = 0;
  end
  if totp(SW) == 0
    SW = setpg(totp(PQ)-totp(PV),1);
    fm_disp('Slack buses have zero generated power.')
    fm_disp('P_slack = sum(P_load)-sum(P_gen) will be used.')
    fm_disp('Only PQ loads and PV generators are used.')
    fm_disp('If there are convergence problems, use the single slack bus model.')
  end
  Gkcall(SW);
  Gkcall(PV);
end

switch Settings.distrsw
 case 1
  fm_disp('Distributed slack bus model')
 case 0
  fm_disp('Single slack bus model')
end

if FDPF > 1, fm_call('fdpf'), end

iter_max = Settings.lfmit;
if iter_max < 2, iter_max = 2; end
iteration = 0;
tol = Settings.lftol;
err_max = tol+1;
err_vec = [];
alfatry = 1;
alfa = 1;
safety = 0.9;
pgrow = -0.2;
pshrnk = -0.25;
try
  errcon = (5/safety)^(1/pgrow);
catch
  errcon = 1.89e-4;
end

% Graphical settings
fm_status('pf','init',iter_max,{'r'},{'-'},{Theme.color11})
fm_connectivity(0,'islands')

%  Newton-Raphson routine
t0 = clock;

while (err_max > tol) & (iteration <= iter_max) & (alfa > 1e-5)

  if Fig.main
    if ~get(Fig.main,'UserData'), break, end
  end

  if FDPF == 1   % Standard NR technique

    refreshJac;

    % component calls
    if Settings.distrsw
      fm_call('kgpf');
      glambda(SW,1,DAE.kg);
      DAE.g(Bus.n+SW.bus) = 0;

      Gbus = Bus.n+[SW.bus;PV.bus];
      DAE.Jlfv(Gbus,:) = 0;
      DAE.Jlfv(:,Gbus) = 0;
      DAE.Jlfv(:,SW.bus) = 0;
      DAE.Jlfv(Gbus,Gbus) = speye(PV.n+SW.n);
      DAE.Fy(:,SW.bus) = 0;
      DAE.Gx(SW.bus,:) = 0;
      if nodyn, DAE.Fx = 1; end
      inc = -[[DAE.Fx, DAE.Fy; DAE.Gx, DAE.Jlfv],[DAE.Fk;DAE.Gk];Jrow]\ ...
            [DAE.f; DAE.g; 0];
      DAE.x = DAE.x + inc(1:DAE.n);
      DAE.a = DAE.a + inc(1+DAE.n:Bus.n+DAE.n);
      DAE.V = DAE.V + inc(1+DAE.n+Bus.n:DAE.n+2*Bus.n);
      DAE.kg = DAE.kg + inc(end);

    elseif Settings.robust

      xold = DAE.x;
      aold = DAE.a;
      Vold = DAE.V;

      while 1

        refreshJac;
        fm_call('l');
        refreshGen(nodyn);
        k1 = -alfa*[DAE.Fx, DAE.Fy; DAE.Gx, DAE.Jlfv]\[DAE.f; DAE.g];

        DAE.x = xold + 0.5*k1(1:DAE.n);
        DAE.a = aold + 0.5*k1(1+DAE.n:Bus.n+DAE.n);
        DAE.V = Vold + 0.5*k1(1+DAE.n+Bus.n:DAE.n+2*Bus.n);
        refreshJac;
        fm_call('l');
        refreshGen(nodyn);
        k2 = -alfa*[DAE.Fx, DAE.Fy; DAE.Gx, DAE.Jlfv]\[DAE.f; DAE.g];

        DAE.x = xold + 0.5*k2(1:DAE.n);
        DAE.a = aold + 0.5*k2(1+DAE.n:Bus.n+DAE.n);
        DAE.V = Vold + 0.5*k2(1+DAE.n+Bus.n:DAE.n+2*Bus.n);
        refreshJac;
        fm_call('l');
        refreshGen(nodyn);
        k3 = -alfa*[DAE.Fx, DAE.Fy; DAE.Gx, DAE.Jlfv]\[DAE.f; DAE.g];

        DAE.x = xold + k3(1:DAE.n);
        DAE.a = aold + k3(1+DAE.n:Bus.n+DAE.n);
        DAE.V = Vold + k3(1+DAE.n+Bus.n:DAE.n+2*Bus.n);
        refreshJac;
        fm_call('l');
        refreshGen(nodyn);
        k4 = -alfa*[DAE.Fx, DAE.Fy; DAE.Gx, DAE.Jlfv]\[DAE.f; DAE.g];

        % compute RK4 increment of variables
        inc = (k1+2*(k2+k3)+k4)/6;

        % to estimate RK error, use the RK2:Dy and RK4:Dy.
        yerr = max(abs(abs(k2)-abs(inc)));
        if yerr > 0.01
          alfa = max(0.985*alfa,0.9);
        else
          alfa = min(1.015*alfa,1.1);
        end

        DAE.x = xold + inc(1:DAE.n);
        DAE.a = aold + inc(1+DAE.n:Bus.n+DAE.n);
        DAE.V = Vold + inc(1+DAE.n+Bus.n:DAE.n+2*Bus.n);
        break

      end
      %disp(['alpha = ',num2str(alfa)])

    else % standard Newton-Raphson method

      % complete Jacobian matrix
      fm_call('l');
      refreshGen(nodyn)
      inc = -[DAE.Fx, DAE.Fy; DAE.Gx, DAE.Jlfv]\[DAE.f; DAE.g];
      DAE.x = DAE.x + inc(1:DAE.n);
      DAE.a = DAE.a + inc(1+DAE.n:Bus.n+DAE.n);
      DAE.V = DAE.V + inc(1+DAE.n+Bus.n:DAE.n+2*Bus.n);

    end

  else % Fast Decoupled Power Flow

    % P-theta
    da = -(Up\(Lp\(Pp*DAE.gp(no_sw))));
    DAE.a(no_sw) = DAE.a(no_sw) + da;
    Vc = DAE.V.*exp(j*DAE.a);
    fm_call('fdpf')
    normP = norm(DAE.gp,inf);
    normQ = norm(DAE.gq,inf);
    if normP < tol & normQ < tol, break, end

    % Q-V
    dV = -(Upp\(Lpp\(Ppp*DAE.gq(no_g))));
    DAE.V(no_g) = DAE.V(no_g)+dV;
    Vc = DAE.V.*exp(j*DAE.a);
    fm_call('fdpf')
    normP = norm(DAE.gp,inf);
    normQ = norm(DAE.gq,inf);
    if normP < tol & normQ < tol, break, end

    inc = [normP; normQ];

    % recompute Bpp if some PV bus has been switched to PQ bus
    if Settings.pv2pq & strmatch('Switch',History.text{end})
      fm_disp('Recomputing Bpp matrix for FDPF')
      no_g = 1:Bus.n;
      no_g([SW.bus; PV.bus]) = [];
      Bpp = Line.Bpp(no_g,no_g);
      [Lpp, Upp, Ppp] = lu(Bpp);
    end
  end

  iteration = iteration + 1;
  err_max = max(abs(inc));
  err_vec(iteration) = err_max;
  
  fm_status('pf','update',[iteration, err_max],iteration)

  if Settings.show
    if err_max == Inf, err_max = 1e3; end
    fm_disp(['Iteration = ', num2str(iteration), ...
             '     Maximum Convergency Error = ', ...
             num2str(err_max)],1)
  end

  % stop if the error increases too much 
  if iteration > 4
    if err_vec(iteration) > 1000*err_vec(1)
      fm_disp('The error is increasing too much.')
      fm_disp('Convergence is likely not reachable.')
      break
    end
  end

end

Settings.lftime = etime(clock,t0);
Settings.iter = iteration;
if iteration > iter_max
  fm_disp(['Reached Maximum number of iteration for NR Routine without ' ...
           'Convergence'],2)
end

% Total power injections and consumptions at network buses

% Pl and Ql computation (shunts only)
DAE.gp = zeros(Bus.n,1);
DAE.gq = zeros(Bus.n,1);
fm_call('pq');
Bus.Pl = DAE.gp;
Bus.Ql = DAE.gq;
% take away PQ generator powers
rmpqgen(PQ)

%Pg and Qg computation
if Line.n, fm_lf(1), end
DAE.gp = zeros(Bus.n,1);
DAE.gq = zeros(Bus.n,1);
fm_call('1');
Bus.Pg = DAE.gp + DAE.glfp;
Bus.Qg = DAE.gq + DAE.glfq;
SW = setpg(SW,'all',Bus.Pg(SW.bus));
% add PQ generator powers
addpqgen(PQ)

% memory allocation for dynamic variables & state variables indicization
if nodyn == 1; DAE.x = []; DAE.f = []; DAE.n = 0; end
DAE.npf = DAE.n;
fm_dynidx;
if (DAE.n~=0)
  DAE.f = [DAE.f; ones(DAE.n-DAE.npf,1)];  % differential equations
  DAE.x = [DAE.x; ones(DAE.n-DAE.npf,1)];  % state variables
  DAE.Fx = sparse(DAE.n,DAE.n); % state Jacobian df/dx
  DAE.Fy = sparse(DAE.n,2*Bus.n); % state Jacobian df/dy
  DAE.Gx = sparse(2*Bus.n,DAE.n); % algebraic Jacobian dg/dx
end

%  build cell arrays of variable names
fm_idx(1)
if (Settings.vs == 1), fm_idx(2), end

% initializations of state variables and components
if Settings.static
  fm_disp('* * * Dynamic components are not initialized * * *')
end
Settings.init = 1;
fm_synit
fm_excin
fm_call('0');
% start up of induction machines
if Mot.n > 0, fm_mot(5), end
% refresh PQ powers
% PQ = pqactual(PQ,'all');

% power flow result visualization
fm_disp(['Power Flow completed in ',num2str(Settings.lftime),' s'])
if Settings.showlf == 1 | Fig.stat
  fm_stat;
else
  if Settings.beep, beep, end
end

% initialization of all equations & Jacobians
refreshJac
fm_call('i');

% build structure "Snapshot"
if isempty(Settings.t0) & Fig.main
  hdl = findobj(Fig.main,'Tag','EditText3');
  Settings.t0 = str2num(get(hdl,'String'));
end

if ~Settings.locksnap & Bus.n <= 5000 & DAE.n < 5000
  Snapshot = struct( ...
      'name','Power Flow Results', ...
      'time',Settings.t0, ...
      'V',DAE.V, ...
      'ang',DAE.a, ...
      'x',DAE.x,...
      'Y',Line.Y, ...
      'Pg',Bus.Pg, ...
      'Qg',Bus.Qg, ...
      'Pl',Bus.Pl, ...
      'Ql',Bus.Ql, ...
      'vfd',Syn.vf, ...
      'pmech',Syn.pm, ...
      'Jlf',DAE.Jlf, ...
      'Jlfv',DAE.Jlfv, ...
      'Fx',DAE.Fx, ...
      'Fy',DAE.Fy, ...
      'Gx',DAE.Gx, ...
      'Ploss',sum(DAE.glfp), ...
      'Qloss',sum(DAE.glfq), ...
      'it',1);
else
  if Bus.n > 5000
    fm_disp(['Snapshots are disabled for networks with more than 5000 ' ...
             'buses.'])
  end
  if DAE.n > 5000
    fm_disp(['Snapshots are disabled for networks with more than 5000 ' ...
             'state variables.'])
  end  
end

fm_status('pf','close')

LIB.selbus = min(LIB.selbus,Bus.n);
if Fig.lib,
  set(findobj(Fig.lib,'Tag','Listbox1'), ...
      'String',Varname.bus, ...
      'Value',LIB.selbus);
end


% -----------------------------------------------
function refreshJac

global DAE Bus

DAE.gp = sparse(Bus.n,1);
DAE.gq = sparse(Bus.n,1);
DAE.J11 = sparse(Bus.n,Bus.n);
DAE.J21 = sparse(Bus.n,Bus.n);
DAE.J12 = sparse(Bus.n,Bus.n);
DAE.J22 = sparse(Bus.n,Bus.n);

% -----------------------------------------------
function refreshGen(nodyn)

global DAE Bus SW PV

DAE.Fy(:,SW.bus) = 0;
DAE.Gx(SW.bus,:) = 0;
DAE.Fy(:,Bus.n+SW.bus) = 0;
DAE.Gx(Bus.n+SW.bus,:) = 0;
DAE.Fy(:,Bus.n+PV.bus) = 0;
DAE.Gx(Bus.n+PV.bus,:) = 0;
if nodyn, DAE.Fx = 1; end
 
% check for islanded buses
if ~isempty(Bus.island)
  k = Bus.island;
  DAE.Jlfv(k,:) = 0;
  DAE.Jlfv(:,k) = 0;
  DAE.Jlfv(:,k+Bus.n) = 0;
  DAE.Jlfv(k+Bus.n,:) = 0;
  DAE.Jlfv(k,k) = speye(length(k));
  DAE.Jlfv(k+Bus.n,k+Bus.n) = speye(length(k));
  DAE.g(k) = 0;
  DAE.g(k+Bus.n) = 0;
  DAE.V(k) = 1e-6;
  DAE.a(k) = 0;
end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -