搞电力系统状态估计,绕不开两个关键词:WLS和PMU。项目标题写得很直白,就是用加权最小二乘(WLS)配合相量测量单元(PMU)去估计电网各节点的电压幅值和相角,然后再拿这个估计结果,和用Newton-Raphson潮流算出来的“标准答案”做对比。
如果你正在学电力系统调度自动化,或者刚开始接触状态估计,这篇文章应该能帮上忙。我尽量把原理、代码、调试经验一次讲透,不管是刚上手的研一学生,还是做了几年配网运维想转高级应用的工程师,都能照着把流程跑通,并且理解每一步为什么要这么做。
1. 项目拆解:状态估计和潮流计算到底是什么关系
1.1 状态估计解决的核心矛盾
电力系统运行中,我们永远不可能完美知道系统当前的状态。SCADA系统采集上来的遥测、遥信数据,天生带噪声,还会有坏数据、数据缺失、时间不同步的问题。你拿到一堆电压、功率、电流读数,但它们互相矛盾,根本没法直接用。
状态估计的作用,就是利用一个带冗余的测量集合,按照电力系统的物理模型(导纳矩阵、功率平衡方程),算出最有可能的一组系统状态,也就是所有节点的电压幅值和相角。这组状态一旦算出来,其他电气量比如支路潮流、注入功率,都可以从这个状态推导出来。所以状态估计是EMS(能量管理系统)的核心引擎,不是锦上添花,是刚需。
1.2 PMU给状态估计带来了什么
传统SCADA量测主要是潮流、注入功率、电压幅值,唯独缺了相角。为什么?因为普通测量装置没有一个统一的时间基准,不同变电站的相角没法放在同一坐标系下比较。
PMU用GPS/北斗的同步脉冲给电压电流波形打时标,测出来的相角是相对于全球统一参考时间的绝对相角。这等于直接把“系统状态”里最难测的那个维度直接测出来了。所以题目里强调“使用PMU估计电压幅值和角度”,本质上是利用PMU的量测优势,让状态估计对系统有更好的可观测性,甚至可以把估计问题从非线性迭代简化成接近线性的求解。
1.3 为什么用Newton-Raphson的状态作为比较基准
Newton-Raphson(简称NR)是解电力系统潮流最经典的方法。给定网络参数、发电机出力和负荷,NR迭代求解满足功率平衡方程的电压解。这个解是在模型完全已知、没有量测噪声的假设下得到的,可以当成一个“参考真值”。
我做这个项目时的思路是:先用NR算一次潮流,得到一组确定性的“真实状态”;然后在这个状态基础上叠加高斯白噪声,模拟PMU量测;再用WLS状态估计去处理这些带噪声的量测;最后比较WLS估计结果和NR真值之间的误差。这样就能非常直观地看到WLS的滤波效果和估计精度。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. WLS状态估计的数学模型与原理
2.1 状态向量与量测方程
一个N节点系统,状态量通常是节点电压相角和幅值。为了数值稳定,常将状态量定义为:
x = [θ2, θ3, ..., θN, V1, V2, ..., VN]^T
这里省略平衡节点的相角θ1,因为它固定为0(或者某个参考角),不进入状态量。V则选全部节点电压幅值,包括平衡节点,因为平衡节点的V虽然通常已知,但在某些量测配置下也当作状态处理也可以。实际上在状态估计里,如果不把平衡节点V当作确定量,可以直接包含进去。为了方便,我把所有V都纳入状态。
量测方程写为:
z = h(x) + ε
其中z是量测向量,h(x)是量测函数,ε是量测误差。假设误差为零均值高斯分布,协方差矩阵为R。那么R的对角元就是各量测的方差。常用做法是取误差标准差为量测满量程的0.5%~2%,电力系统里电流越限、功率越限的情况都是相对值,所以这个取值很自然。
2.2 WLS目标函数与迭代公式
WLS的思路是找到一组状态x,使量测残差的加权平方和最小:
min J(x) = [z - h(x)]^T W [z - h(x)]
其中权重矩阵 W = R^{-1},也就是量测越准,权重越大。为什么不是直接最小二乘而是加权?因为不同精度的表计混在一起时,误差小的量测应该更被信任。用协方差矩阵的逆做权重,这样在统计上才是最优线性无偏估计。
求解这个非线性最小二乘问题,最常用的方法是高斯-牛顿迭代。把h(x)在当前迭代点展开成线性,得到法方程:
(H^T W H) Δx = H^T W [z - h(x)]
其中H是量测雅可比矩阵,H(i,j) = ∂h_i / ∂x_j。每次迭代更新状态:
x_{k+1} = x_k + Δx
迭代到Δx的范数小于阈值。值得注意的是,如果量测全是PMU的电压幅值和相角,那么h(x)对x近似线性,迭代一步就能收敛。如果还加了支路电流、潮流等非线性量测,就需要多迭代几次。
2.3 PMU量测模型具体怎么建立
PMU量测一般包含:
- 节点电压幅值V_i
- 节点电压相角θ_i
- 支路电流幅值I_ij
- 支路电流相角φ_ij
- 甚至还有注入功率,但注入功率通常由计算得到,不直接作为PMU原始量测
在本项目中,我主要用两类量测:
- 全节点电压幅值和相角:这是PMU最直接的输出,量测方程是线性的。
- 关键支路电流幅值:因为电流幅值与节点电压的关系是非线性的,这能让WLS迭代过程更“完整”,也更能体现算法的通用性。
支路电流幅值的量测方程为:
I_ij = | (V_i - V_j) * y_ij + V_i * y_io |
其中 y_ij 是支路导纳,y_io 是对地导纳。雅可比矩阵需要对V和θ求偏导,推导不复杂,但很容易错。我在实现时直接用数值微分求H,虽然慢一点点,但调试起来特别稳。如果你追求性能,再换成解析表达式。
2.4 Newton-Raphson潮流回顾
NR潮流是在给定节点注入功率条件下,求解功率平衡方程:
P_i = V_i Σ V_j (G_ij cosθ_ij + B_ij sinθ_ij)
Q_i = V_i Σ V_j (G_ij sinθ_ij - B_ij cosθ_ij)
把PQ节点的注入功率、PV节点的有功和电压幅值、平衡节点的电压幅值相角作为已知量,形成2N维的非线性方程组。NR法本质上也是用雅可比矩阵做牛顿迭代,求解速度快、收敛性好。这个“解”被我们用作基准真值。在Matlab里,手写一个NR潮流函数大概100多行,也可以用Matpower的runpf一步完成。为了不引入额外的工具箱依赖,我建议自己写一个针对具体系统的NR函数,后面我会给简化代码。
3. Matlab实现与核心代码解析
3.1 测试系统与数据准备
为了演示,我采用一个3节点测试系统,参数如下(标幺值,基准容量100MVA):
| 节点 | 类型 | 参数 |
|---|---|---|
| 1 | 平衡节点 | V=1.0, θ=0 |
| 2 | PQ节点 | P_load=0.4, Q_load=0.2 |
| 3 | PQ节点 | P_load=0.5, Q_load=0.3 |
线路参数:
| 支路 | 电阻R pu | 电抗X pu | 对地电纳B/2 pu |
|---|---|---|---|
| 1-2 | 0.02 | 0.10 | 0.01 |
| 1-3 | 0.03 | 0.12 | 0.015 |
| 2-3 | 0.04 | 0.15 | 0.02 |
这里对地电纳都给一半,方便组装节点导纳矩阵。系统不大,但状态估计的所有关键环节都能体现。
3.2 组装节点导纳矩阵
在Matlab中,我习惯用复导纳矩阵Y直接运算。代码如下:
matlab复制function Y = makeYbus(branch)
% branch: [from, to, R, X, B/2]
% return Y bus matrix
nb = 3;
Y = zeros(nb, nb);
for k = 1:size(branch,1)
from = branch(k,1);
to = branch(k,2);
z = branch(k,3) + 1j*branch(k,4);
y = 1/z;
b = branch(k,5); % 对地电纳一半
Y(from, from) = Y(from, from) + y + 1j*b;
Y(to, to) = Y(to, to) + y + 1j*b;
Y(from, to) = Y(from, to) - y;
Y(to, from) = Y(from, to);
end
end
这个函数把线路的对地电容归算到两端节点。千万注意B/2的单位,很多新手把整条线路的B当成每端对地电纳,导致导纳矩阵错误,状态估计和潮流一起发散。
3.3 用NR潮流生成参考状态
我在项目里把NR潮流写成了一个函数,输入是导纳矩阵、节点负荷和发电机有功、电压控制设定,输出是各节点V和θ。核心迭代代码大概是这样:
matlab复制function [V, theta, iter] = NR_PowerFlow(Ybus, S_load, S_gen, V0, theta0, isPQ, Pspec, Vspec)
% 简化示意:isPQ标记PQ节点,Pspec/Vspec表示PV控制
tolerance = 1e-10;
maxIter = 30;
V = V0;
theta = theta0;
for iter = 1:maxIter
% 计算注入功率
Vc = V .* exp(1j*theta);
Iinj = Ybus * Vc;
Sinj = Vc .* conj(Iinj);
P = real(Sinj); Q = imag(Sinj);
% 只对PQ节点计算功率偏差,平衡节点的P,Q不参与
dP = Pspec - P - real(S_load - S_gen);
dQ = Qspec - Q - imag(S_load - S_gen);
dPQ = [dP(isPQ); dQ(isPQ)];
if max(abs(dPQ)) < tolerance
break;
end
% 形成雅可比矩阵(略),求解修正量
dx = J \ dPQ;
deltaTheta = zeros(length(V),1);
deltaV = zeros(length(V),1);
% 更新相角和幅值
end
end
这个代码没有展开完整雅可比矩阵,但思路就是这样。如果你用Matpower,直接 runpf(case9) 返回结果里的 bus.Vm 和 bus.Va 就是NR状态。我在调试时两种方式都试了,自己写NR的好处是对雅可比矩阵的“手感”更清楚,后面写WLS的H矩阵时不慌。
3.4 生成PMU量测
获得NR参考状态后,以这个状态为均值,叠加高斯噪声,模拟PMU量测。
matlab复制sigma_V = 0.005; % 电压幅值量测标准差,标幺值
sigma_theta = 0.002; % 相角量测标准差,弧度约0.11度
sigma_I = 0.01; % 电流幅值量测标准差
V_true = V_NR;
theta_true = theta_NR;
% 生成全节点电压幅值和相角量测
zV = V_true + sigma_V * randn(nb,1);
zTheta = theta_true + sigma_theta * randn(nb,1);
% 生成关键支路电流幅值量测
zI = compute_branch_current(V_true, theta_true, Ybus, branch) ...
+ sigma_I * randn(nbranch,1);
这里量测噪声的取值需要根据实际PMU精度来。当前商用PMU电压幅值精度在0.1%~0.5%左右,相角误差在0.01°~0.1°。我取0.5%和0.002rad,算是一个比较保守、贴近工程实际的设置。
3.5 WLS状态估计主循环
WLS主函数我实现了两种量测组合:一种只用电压幅值和相角,另一种加上支路电流幅值。核心循环如下:
matlab复制function [x_est, iter] = WLS_Estimation(zV, zTheta, zI, Ybus, branch, W, x0)
x = x0; % x = [theta2..thetaN; V1..VN]
for iter = 1:20
[h, H] = compute_h_and_H(x, Ybus, branch);
residual = z - h;
G = H' * W * H;
if rcond(G) < 1e-12
warning('G矩阵病态,检查可观测性');
end
dx = G \ (H' * W * residual);
x = x + dx;
if max(abs(dx)) < 1e-8
break;
end
end
x_est = x;
end
compute_h_and_H 里,h的前三行是电压幅值,接下来三行是电压相角,再往下是支路电流幅值。电压幅值和相角的量测方程是线性的,所以对应H行是常数;而支路电流幅值的H行需要求偏导。我实际调试时踩过一个坑:相角的单位要统一,PMU给的角度可能是角度制,但状态估计里全是弧度制,忘了转换会让迭代直接跳到荒谬值。
3.6 结果比较与误差统计
估计完成后,我把WLS得到的V和θ与NR真值做误差对比。代码如下:
matlab复制error_V = abs(V_est - V_NR);
error_theta = abs(theta_est - theta_NR);
fprintf('电压幅值最大误差: %.6f pu\n', max(error_V));
fprintf('电压相角最大误差: %.6f rad\n', max(error_theta));
fprintf('电压幅值RMSE: %.6f pu\n', sqrt(mean(error_V.^2)));
实测下来的典型结果是:WLS估计的电压幅值误差远小于原始PMU量测误差,相角误差也明显被平滑了。这是因为状态估计里有多余量测,最小二乘把随机噪声平均掉了,体现出WLS的滤波价值。
4. 实操中遇到的问题与排查技巧
4.1 导纳矩阵虚部符号不对,潮流直接发散
这是我排在最前面的坑。电力系统潮流计算里,导纳矩阵的对角线元素是节点自导纳,等于所有连接支路导纳之和加上对地电纳;非对角元素是互导纳,恒为负。如果对地电纳符号搞反了,非对角元素变成正的,NR迭代第一步就会发散。
排查方法很简单:先算一个2节点系统的导纳矩阵,手算一遍和程序输出对比。虽然老套,但比自己对着屏幕干瞪眼强。
4.2 WLS迭代矩阵奇异,可观测性不足
我在做更小系统测试时,曾试图只用两条支路电流量测去估三个节点的电压相角,结果G矩阵奇异。这是因为相角量测量不足,系统不可观测。PMU的优势就在这:直接提供相角量测,比传统SCADA可观测性强很多。
但如果你的PMU不是每个节点都装,就需要注意量测配置是否满足全网可观测性。一个经验法则是:每个分区至少有一个PMU提供参考相角,否则WLS法方程奇异。遇到这个报错,先检查rcond,如果太小,要么增加PMU,要么用伪逆求解,但伪逆在工程上会给一个从数学上讲通却没有物理意义的结果。
4.3 PMU相角参考和潮流计算参考不一致
NR潮流里,平衡节点的相角固定为0,其他节点相角都是相对于平衡节点的功角。PMU量测的相角是相对于全球统一时间参考的绝对相角。如果直接把PMU的绝对相角当作相对量测塞进WLS,而状态量的参考仍然是节点1为0,就会出现系统性的相位偏移,误差曲线是一条水平直线。
解决办法是先把PMU相角统一减去参考节点的PMU相角,变成相对功角,再做估计。或者在WLS状态量里保留一个参考相角状态,通过量测确定。我建议后者,因为可以应对PMU参考通道切换的情况,但实现稍复杂。项目为了简洁,采用了第一种方法:用参考节点的PMU相角做基准。
4.4 权重矩阵设置太随意导致估计值被“带偏”
权重矩阵W是量测协方差矩阵的逆。如果实际量测误差是1%,但你把标准差设置成0.01%,那么这个量测在WLS里会被当成“金标准”,如果它本身恰好有较小的坏数据,估计结果就会被严重拉偏。这个问题在工程中很常见,尤其是PMU数据偶尔有异常或通信延迟时。
我的做法是:不直接用理论标准差,而是先跑一段离线数据,统计每个PMU通道的误差标准差,再生成权重矩阵。这样至少能避免“拍脑袋定权重”。另外,WLS对坏数据不鲁棒,一个简单防御是加一次残差检验:估计完后计算标准化残差,超过阈值的量测剔除或降权,再重新估计一次。
4.5 支路电流量测的方向和极性
PMU安装在线路一侧时,电流相量的方向是定义的参考方向。如果你的两套PMU分别装在线路两端,它们的量测极性可能相反。在计算h(x)时,支路电流方向必须和导纳矩阵定义的方向一致,否则残差会接近实际电流的两倍,WLS算法会拼命调状态去“平衡”这个矛盾,结果状态严重失真。
解决方案是:在形成量测向量时,根据PMU所在位置统一电流的方向,每一路电流量测都要明确是从哪个节点流向哪个节点,并在代码中对应h(x)计算。
5. 结果可视化与扩展建议
5.1 电压幅值和相角估计结果图
把NR真值、PMU原始量测、WLS估计值画在同一张图上,可以非常直观地看到WLS对噪声的平滑效果。我习惯用errorbar图:
matlab复制figure;
subplot(2,1,1);
bar([1:nb], V_NR, 'k'); hold on;
errorbar(1:nb, zV, sigma_V*ones(nb,1), 'bo');
plot(1:nb, V_est, 'r*-', 'LineWidth', 1.5);
legend('NR真值','PMU量测','WLS估计');
xlabel('节点'); ylabel('电压幅值 / pu');
subplot(2,1,2);
bar([1:nb], theta_NR, 'k'); hold on;
errorbar(1:nb, zTheta, sigma_theta*ones(nb,1), 'bo');
plot(1:nb, theta_est, 'r*-', 'LineWidth', 1.5);
legend('NR真值','PMU量测','WLS估计');
xlabel('节点'); ylabel('相角 / rad');
这个图是项目汇报的“门面”,也是检查算法有没有bug的第一关。如果估计值和真值差得不多,并且估计值的误差棒比量测误差棒明显更窄,说明WLS起作用了。
5.2 混合量测与动态状态估计
实际工程中不太可能全网都是PMU。多数电网是SCADA为主、PMU逐步布点,因此更实用的状态估计应该同时用SCADA和PMU的混合量测。在WLS框架下,这并不难:把常规潮流量测的雅可比行和PMU量测的雅可比行拼在一起,形成更大的H矩阵和残差向量,再统一迭代。需要注意的还是权重:SCADA和PMU的精度差一个数量级,权重差异必须反映出来,否则算法会被PMU“绑架”。
如果你要做的是动态状态估计,也就是实时追踪状态随时间的变化,WLS可以扩展成卡尔曼滤波的形式。PMU的高采样率(30~60帧/秒)让动态估计算法成为可能。WLS处理的是当前时刻的快照,卡尔曼滤波会利用上一时刻的信息做预测,然后修正,适合扰动后的暂态过程。项目里做的WLS静态估计,是这一切的基础。
5.3 代码性能优化
在Matlab里,WLS的主要瓶颈是每次迭代都要生成H矩阵和求解法方程。如果系统节点很多,比如数千节点,直接形成稠密H会非常吃内存。解决办法是利用H矩阵的稀疏结构。用sparse存储H和G,并用lsqnonneg或者最小二乘迭代求解代替直接求逆。实测中,对几百节点的系统,稀疏化后计算时间从秒级降到毫秒级,对在线应用很重要。
不过对入门学习来说,先用稠密矩阵把流程跑通,再优化,是更合理的路径。一上来就搞稀疏化会分散对核心算法的注意力。
6. 个人体会与最后的小建议
我在做这个项目时,最大的体会是状态估计和潮流计算是一对“孪生兄弟”。潮流计算是给定模型求状态,状态估计是给定量测求状态。理解了两者区别,再去看WLS就会豁然开朗:WLS不过是在潮流方程的基础上,加了一个统计最优的视角。
最后分享一个调试小技巧:在WLS迭代过程中,把每次迭代的目标函数值J(x)打印出来,正常情况应该是单调下降的。如果看到J在震荡或上升,十有八九是雅可比矩阵算错了。这时候不要急着调权重,先逐项检查H矩阵和数值微分结果是否一致。我在项目里用这个办法找回过好多次“莫名其妙”的故障。
代码和数据文件我建议保留成三个独立脚本:data_case.m、nr_pf.m、wls_se.m,这样后面换系统只需要改data_case里的参数,算法完全不用动。这也是一个值得长期坚持的工程习惯。
