Newton-Raphson Power Flow Analysis for the IEEE 14-Bus System in MATLAB

This article details the implementation of the Newton-Raphson method for power flow analysis applied to the standard IEEE 14-bus test system using MATLAB. The Newton-Raphson algorithm is an iterative technique widely used in power systems for determining the voltage magnitudes and phase angles at each bus under specified load and generation conditions.

Algorithm Architecture

The core of the power flow solver is encapsulated within a main function that orchestrates data handling, Y-bus matrix construction, iterative calculations, and convergence checks. The function takes as input bus and branch specifications along with the system's base MVA.


function [voltageMagnitudes, voltageAnglesRad, calculatedActivePower, calculatedReactivePower] = runPowerFlowNR(busSpecs, branchSpecs, baseMVA)
    % Executes the Newton-Raphson power flow algorithm.
    % Inputs:
    %   busSpecs: N x 12 matrix with bus data (e.g., [bus_num, type, Pd, Qd, Gs, Bs, area, Vm, Va, basekV, zone, Vmax, Vmin])
    %   branchSpecs: M x 14 matrix with branch data (e.g., [fbus, tbus, r, x, b, rateA, rateB, rateC, ratio, angle, status, angmin, angmax])
    %   baseMVA: System base apparent power in MVA (e.g., 100)
    
    % Initialize system structure
    gridModel = struct(...
        'bus', busSpecs, ...
        'branches', branchSpecs, ...
        'yAdmittanceMatrix', [], ...
        'numBuses', size(busSpecs,1), ...
        'numBranches', size(branchSpecs,1)...
    );
    
    % Initial guesses for state variables
    voltageMagnitudes = ones(gridModel.numBuses, 1);     % Initialize voltage magnitudes to 1.0 p.u.
    voltageAnglesRad = zeros(gridModel.numBuses, 1);    % Initialize voltage angles to 0 radians
    
    % Algorithm parameters
    convergenceThreshold = 1e-6; % Convergence tolerance for power mismatches
    maxIterations = 50;          % Maximum number of iterations
    
    % Construct the bus admittance matrix (Ybus)
    gridModel.yAdmittanceMatrix = buildYbusMatrix(gridModel.branches, gridModel.numBuses, baseMVA);
    
    % Main iterative loop
    for currentIter = 1:maxIterations
        % Calculate active and reactive power at each bus
        [activePowerCalculated, reactivePowerCalculated] = computeBusPowers(voltageMagnitudes, voltageAnglesRad, gridModel.yAdmittanceMatrix);
        
        % Compute power mismatches
        % busSpecs columns 8 and 9 represent P_load and Q_load, if busSpecs(:,8) is Pgen - Pload and busSpecs(:,9) is Qgen - Qload
        % then we just use it directly. Assuming busSpecs(:,8) is P_net_inj, busSpecs(:,9) is Q_net_inj.
        activePowerMismatch = (busSpecs(:,8) - activePowerCalculated) ./ baseMVA;
        reactivePowerMismatch = (busSpecs(:,9) - reactivePowerCalculated) ./ baseMVA;
        
        % Check for convergence
        if max(abs([activePowerMismatch; reactivePowerMismatch])) < convergenceThreshold
            break; % Algorithm converged
        end
        
        % Formulate the Jacobian matrix
        jacobianMatrix = assembleJacobian(voltageMagnitudes, voltageAnglesRad, gridModel.yAdmittanceMatrix, gridModel.numBuses);
        
        % Solve for state variable corrections
        % Note: PV buses require modification to the Jacobian and mismatch vector
        % This example assumes PQ buses for all except slack, and treats all as PQ for simplicity.
        % A full implementation would remove rows/columns corresponding to PV/slack buses.
        stateVariableCorrections = jacobianMatrix \ [-activePowerMismatch; -reactivePowerMismatch];
        
        % Update voltage magnitudes and angles
        voltageAnglesRad = voltageAnglesRad + stateVariableCorrections(1:gridModel.numBuses);
        voltageMagnitudes = voltageMagnitudes + stateVariableCorrections(gridModel.numBuses+1:end);
    end
end

Key Funcsional Modules

1. Branch Network Data Structure

The branch data matrix defines the connections and parameters for each line or transformer in the system. For the IEEE 14-bus system, this typically includes 'from' and 'to' bus numbers, resistance, reactance, and half-line charging susceptance.


% Example branch data format (IEEE 14-bus standard)
% Columns (indices for MATLAB):
% [1:From Bus, 2:To Bus, 3:Resistance (p.u.), 4:Reactance (p.u.), 5:Half-Line Charging Susceptance (p.u.),
%  6:Rate A, 7:Rate B, 8:Rate C, 9:Tap Ratio, 10:Phase Shift Angle (degrees), 11:Status, 12:Min Tap, 13:Max Tap]
networkBranchData = [
    1 2 0.01938 0.05917 0.0528 0 0 0 0 0 1 -360 360;  % Line 1-2
    1 5 0.05403 0.22304 0.0492 0 0 0 0 0 1 -360 360;  % Line 1-5
    2 3 0.04699 0.19797 0.0438 0 0 0 0 0 1 -360 360;  % Line 2-3
    % ... Additional branch entries ...
];

2. Bus Admittance Matrix Construction (Y-Bus)

The Y-bus matrix is a fundamental component for power flow calculations, representing the admittances between all buses in the system. For efficiency with larger systems, it is often constructed as a sparse matrix.


function Ybus = buildYbusMatrix(branchData, numSystemBuses, basePowerMVA_unused)
    Ybus = sparse(numSystemBuses, numSystemBuses); % Initialize as sparse matrix
    
    for lineIdx = 1:size(branchData, 1)
        fromBus = branchData(lineIdx, 1); % From bus
        toBus = branchData(lineIdx, 2);   % To bus
        resistance = branchData(lineIdx, 3);
        reactance = branchData(lineIdx, 4);
        halfShuntB = branchData(lineIdx, 5); % Half-line charging susceptance
        
        % Series admittance for the branch
        seriesAdmittance = 1 / (resistance + 1j * reactance);
        
        % Off-diagonal elements (Y_ft and Y_tf)
        % For simple lines, Y_ft = Y_tf = -y_series
        Ybus(fromBus, toBus) = Ybus(fromBus, toBus) - seriesAdmittance;
        Ybus(toBus, fromBus) = Ybus(toBus, fromBus) - seriesAdmittance;
        
        % Diagonal elements (Y_ff and Y_tt)
        % Y_ii = sum(y_series_ij) + y_shunt_i
        Ybus(fromBus, fromBus) = Ybus(fromBus, fromBus) + seriesAdmittance + 1j * halfShuntB / 2;
        Ybus(toBus, toBus) = Ybus(toBus, toBus) + seriesAdmittance + 1j * halfShuntB / 2;
    end
end

3. Jacobian Matrix Assembly

The Jacobian matrix contains the partial derivatives of the power mismatch equations with respect to the state variables (voltage angles and magnitudes). It dictates the update direction for each iteration. For an N-bus system, the Jacobian matrix is typically of size (2N-2)x(2N-2) if a slack bus and PV buses are handled correctly, but for simplicity, we derive the full 2Nx2N Jacobian here, assuming all non-slack buses are PQ type or for a general derivation.


function J = assembleJacobian(V_mag, angle_rad, Y_bus, n_buses)
    G = real(Y_bus); % Conductance matrix
    B = imag(Y_bus); % Susceptance matrix
    
    J = zeros(2 * n_buses, 2 * n_buses); % Initialize Jacobian matrix
    
    % Re-calculate P and Q at each bus for Jacobian construction
    % (This could also be passed from the main loop if P_calc and Q_calc were saved)
    P_calculated = zeros(n_buses, 1);
    Q_calculated = zeros(n_buses, 1);
    for i = 1:n_buses
        for j = 1:n_buses
            theta_difference = angle_rad(i) - angle_rad(j);
            P_calculated(i) = P_calculated(i) + V_mag(i) * V_mag(j) * (G(i,j) * cos(theta_difference) + B(i,j) * sin(theta_difference));
            Q_calculated(i) = Q_calculated(i) + V_mag(i) * V_mag(j) * (G(i,j) * sin(theta_difference) - B(i,j) * cos(theta_difference));
        end
    end

    % Construct sub-matrices of the Jacobian: J_P_delta, J_P_V, J_Q_delta, J_Q_V
    J_P_delta = zeros(n_buses); % dP/dDelta
    J_P_V = zeros(n_buses);     % dP/dV
    J_Q_delta = zeros(n_buses); % dQ/dDelta
    J_Q_V = zeros(n_buses);     % dQ/dV

    for i = 1:n_buses
        for j = 1:n_buses
            if i == j % Diagonal elements
                % J_P_delta (dP_i/dDelta_i)
                J_P_delta(i,i) = -Q_calculated(i) - V_mag(i)^2 * B(i,i);
                % J_P_V (dP_i/dV_i)
                J_P_V(i,i) = (P_calculated(i) / V_mag(i)) + (V_mag(i) * G(i,i));
                % J_Q_delta (dQ_i/dDelta_i)
                J_Q_delta(i,i) = P_calculated(i) - (V_mag(i)^2 * G(i,i));
                % J_Q_V (dQ_i/dV_i)
                J_Q_V(i,i) = (Q_calculated(i) / V_mag(i)) - (V_mag(i) * B(i,i));
            else % Off-diagonal elements
                theta_diff_ij = angle_rad(i) - angle_rad(j);
                
                % J_P_delta (dP_i/dDelta_j)
                J_P_delta(i,j) = V_mag(i) * V_mag(j) * (G(i,j) * sin(theta_diff_ij) - B(i,j) * cos(theta_diff_ij));
                % J_P_V (dP_i/dV_j)
                J_P_V(i,j) = V_mag(i) * (G(i,j) * cos(theta_diff_ij) + B(i,j) * sin(theta_diff_ij));
                % J_Q_delta (dQ_i/dDelta_j)
                J_Q_delta(i,j) = V_mag(i) * V_mag(j) * (-G(i,j) * cos(theta_diff_ij) - B(i,j) * sin(theta_diff_ij));
                % J_Q_V (dQ_i/dV_j)
                J_Q_V(i,j) = V_mag(i) * (G(i,j) * sin(theta_diff_ij) - B(i,j) * cos(theta_diff_ij));
            end
        end
    end
    
    % Assemble the full Jacobian matrix
    J = [J_P_delta J_P_V; J_Q_delta J_Q_V];
end

% Note: The 'computeBusPowers' function calculates P and Q for each bus based on V, delta, and Ybus.
% Its implementation involves summations similar to those for P_calculated and Q_calculated above.
function [P_computed, Q_computed] = computeBusPowers(V_magnitudes, delta_angles, Y_matrix)
    num_buses = length(V_magnitudes);
    P_computed = zeros(num_buses, 1);
    Q_computed = zeros(num_buses, 1);
    
    for i = 1:num_buses
        for j = 1:num_buses
            theta_ij = delta_angles(i) - delta_angles(j);
            Y_ij = Y_matrix(i,j);
            P_computed(i) = P_computed(i) + V_magnitudes(i) * V_magnitudes(j) * (real(Y_ij) * cos(theta_ij) + imag(Y_ij) * sin(theta_ij));
            Q_computed(i) = Q_computed(i) + V_magnitudes(i) * V_magnitudes(j) * (real(Y_ij) * sin(theta_ij) - imag(Y_ij) * cos(theta_ij));
        end
    end
    % The output P_computed and Q_computed are in actual MW/MVAr, not p.u.
    % Mismatches in the main function will handle p.u. conversion.
end

Representative Simulation Outcomes

1. Bus Voltage Profile

A typical outcome for the IEEE 14-bus system simulation illustrates the voltage magnitudes and phase angles across the network:

Bus Voltage Magnitude (p.u.) Phase Angle (°)
1 1.060 0.0
2 1.045 -4.98
3 1.010 -12.72
4 1.019 -10.33
14 1.036 -16.04

2. Convergence Behavior

The convergence of the power mismatch errors (active and reactive) against the number of iterations demonstrates the stability and efficiency of the Newton-Raphson method.


% Plotting the convergence of power mismatches
% To plot, you would typically store the max absolute P_mismatch and Q_mismatch
% from each iteration in vectors (e.g., P_mismatch_history, Q_mismatch_history).
% Assuming 'currentIter' is the final iteration count:
% semilogy(1:currentIter, abs(P_mismatch_history), 'r-o', 1:currentIter, abs(Q_mismatch_history), 'b-s');
% xlabel('Iteration Number');
% ylabel('Absolute Power Mismatch (p.u.)');
% legend('Active Power Mismatch', 'Reactive Power Mismatch');
% title('Newton-Raphson Algorithm Convergence');

Advanced Features

1. Transformer Tap Ratio Control

Transformer tap changers are crucial for voltage regulation. This function, often embedded within the power flow iteration, adjusts tap settings to maintain voltages with in specified limits at certain buses.


function [updatedBranchData, regulatedVoltages] = adjustTransformerTaps(branchInfo, currentVoltages, angleValues, minVoltageThreshold, maxVoltageThreshold)
    updatedBranchData = branchInfo; % Copy branch data for potential modification
    regulatedVoltages = currentVoltages; % Voltages might be regulated by tap changes in a real iterative process
    
    % Loop through all branches to identify transformers with tap control
    % Assuming branchInfo(:,9) is the tap ratio, branchInfo(:,12) is min_tap, branchInfo(:,13) is max_tap
    for k = 1:size(updatedBranchData, 1)
        % Heuristic: Check if tap ratio column 9 is not zero and tap limits (col 12,13) are defined
        % (i.e., not the dummy -360/360 used for lines without tap control)
        if updatedBranchData(k, 9) ~= 0 || updatedBranchData(k, 12) ~= -360 
            
            % For a transformer, the tap ratio typically affects the voltage at the 'to' bus.
            % Let's assume branchInfo(k,2) is the bus whose voltage is to be regulated.
            regulatedBusIndex = updatedBranchData(k,2); 
            currentBusVoltage = regulatedVoltages(regulatedBusIndex);
            
            tapRatio = updatedBranchData(k, 9);
            minTap = updatedBranchData(k, 12); % Corrected index if using the provided format
            maxTap = updatedBranchData(k, 13); % Corrected index if using the provided format

            % Adjust tap based on voltage deviation. This is a simplified, direct adjustment.
            % A practical control would be part of an outer loop or specialized algorithm.
            if currentBusVoltage < minVoltageThreshold
                tapRatio = tapRatio + 0.005; % Increase tap to boost voltage
            elseif currentBusVoltage > maxVoltageThreshold
                tapRatio = tapRatio - 0.005; % Decrease tap to lower voltage
            end
            
            % Enforce tap limits
            updatedBranchData(k, 9) = max(min(tapRatio, maxTap), minTap);
        end
    end
end

2. Reactive Power Limit Enforcement

Generator reactive power output must operate within specified minimum and maximum limits. This function enforces these limits and flags any violations, potentially converting a PV bus to a PQ bus if limits are hit.


function [adjustedQgenOutputs, limitViolationDetected] = applyQgenLimits(generatorReactivePower, minQ_limits, maxQ_limits)
    adjustedQgenOutputs = generatorReactivePower;
    limitViolationDetected = false;
    
    for genIdx = 1:length(adjustedQgenOutputs)
        if adjustedQgenOutputs(genIdx) > maxQ_limits(genIdx)
            adjustedQgenOutputs(genIdx) = maxQ_limits(genIdx);
            limitViolationDetected = true;
        elseif adjustedQgenOutputs(genIdx) < minQ_limits(genIdx)
            adjustedQgenOutputs(genIdx) = minQ_limits(genIdx);
            limitViolationDetected = true;
        end
    end
end

Tags: MATLAB Newton-Raphson Power Flow IEEE 14-Bus System Electrical Grid Analysis

Posted on Tue, 04 Aug 2026 16:28:34 +0000 by NogDog