简介:面向配电网故障定位研究者和有一定Matlab基础的读者,该源码包利用粗糙集理论处理故障信息的不确定性与不完备性,帮助快速判别故障可能发生的区域。压缩包共4个文件、约5KB,包含Matlab主程序(.m)、两个文本数据文件(.txt)及一个Matlab自动备份文件(.asv),规模精简,便于直接运行和查看。已有519人学习下载,适用于电力系统课程设计、故障诊断方向入门与原理验证。代码覆盖数据预处理、属性选择、等价类划分、规则生成到故障定位等完整流程,读者可在Matlab中运行并观察不同故障场景的响应,结合粗糙集模型理解规则构建逻辑,或在此基础上调整特征与阈值,进一步适配不同配电网拓扑和运行工况。整个流程直观清晰,便于二次开发。
1. 粗糙集在配电网故障定位里到底解决什么问题
配电网故障定位的核心难点不是缺数据,而是数据太多太杂。馈线出故障后,FTU、故障指示器上报的过流、电压跌落、开关变位信号混在一起,还经常带缺失和误报。传统逻辑判据要手工梳理每一条规则,遇到分布式电源接入、多分支拓扑就不好使。
粗糙集(Rough Set)的价值在于它能直接吃这些离散化后的运行状态表,自动删掉冗余属性、抽取最小决策规则,不依赖先验概率和隶属度。做配电网故障定位,用粗糙集最靠谱的切入点是离线建规则库、在线做匹配定位。
下面按这条路径讲清楚建模、约简、推理和踩坑,给要动手用MATLAB复现的人一条完整路线。
2. 把故障定位问题建模成决策表:字段、量化和数据准备
2.1 决策表的结构:条件属性与决策属性怎么定
粗糙集算法不认波形,只认表格。它处理的是一张二维决策表,每一行是一次故障事件,每一列是一个属性。条件属性是故障发生时可观测到的特征量,决策属性是你想定位的区段编号。这里最忌讳的是把原始录波直接塞进去,必须先把故障现象整理成结构化状态量。
以一条典型的10kV中性点不接地馈线为例,我会把馈线按分段开关分成4到6个区段,每个分段开关对应一个FTU。条件属性初步定成这样:
- S1、S2、S3:各分段开关是否检测到过流,取值0或1
- U:母线电压是否越限,取值0或1
- I0:零序电流是否越限,取值0或1
- 故障指示器动作标记:取值0或1
决策属性就是区段编号F,从1到N。不要试图把所有电气量都装进表里。粗糙集的特点是能挑出有用信息,但硬塞几十个高度相关的属性,会让约简过程变长,还可能选出过拟合的规则。我一般先保留上述6到8个属性,跑一轮约简看哪个属性被删掉,再决定要不要补充。
这里有个容易忽略的点:决策属性必须互斥且完备。一个故障必须只能落在一个区段,不能出现“区段2和区段3交界处”这种模糊标签。如果两个区段共享一个FTU测点,建议把测点归到上游区段,或者干脆合并区段,否则规则会冲突。常见做法是先画单线图,手工把每个区段的边界和对应的FTU测点列出来,再定属性。
2.2 故障特征量化:电压、电流、开关状态的离散化
粗糙集基础理论里,条件属性可以是连续值,但实际算法都要求离散化。离散化质量直接决定约简结果的好坏。连续量比如电流、电压,需要转成有限的档位;开关状态本身已经是0/1,不用动。
我在做10kV配电网短路电流仿真时,会对线路不同位置设置金属性短路和经过渡电阻短路,记录各测点的故障电流有效值。然后电流按标幺值分档:小于0.1记为0,0.1到0.5记为1,大于0.5记为2。电压大于0.9记为0,0.7到0.9记为1,小于0.7记为2。这里0.1和0.5不是固定值,要结合负荷电流和短路容量来定。如果线路负荷重,正常电流就比较高,再用0.1当阈值会把正常工况误判成过流。
更稳妥的办法是用等频离散化:把每个属性从小到大排序,按分位数切成等样本数的几段。这样断点会自适应落在样本稀疏的地方,不会因为个别极端值影响分档。Matlab里的discretize加上quantile就能实现,代码在下一节。要注意等频离散化只适用于连续属性,像开关状态这种本来就二值的属性不能参与。
零序电流要单独处理。经消弧线圈接地系统里,单相接地时零序电流方向和幅值跟中性点不接地系统差异很大,不能简单地跟相电流混在一个属性里。我一般给零序电流只设“越限/不越限”一档,不区分幅值,因为故障定位主要靠故障点上下游的零序方向差异,而不是大小。
2.3 构建样本集的Matlab代码:从故障仿真到决策表
下面这段代码演示怎么把仿真数据整理成粗糙集能用的决策表。建议把仿真产生的原始曲线先导出成CSV,再在MATLAB里按测点聚合,不要手工录入。
% 构造决策表 decision_table % 条件属性列:S1过流、S2过流、S3过流、S4过流、母线低电压U % 决策属性列:fault_zone,取值1~4 % 示例数据,实际由10kV配电网短路电流仿真批量生成 % 每行代表一次故障样本,前4列是开关过流状态,第5列是低电压标记,第6列是故障区段 raw = [ 1 1 0 0 1 2; % S1,S2过流,低电压 -> 区段2 1 0 0 0 1 1; % 仅S1过流,低电压 -> 区段1 0 1 0 0 1 3; % 仅S2过流,低电压 -> 区段3 1 1 1 0 0 3; % S1,S2,S3过流,电压正常 -> 区段3 0 0 0 0 1 0; % 无过流,低电压 -> 母线侧区段 ]; % 分离条件属性与决策属性 X = raw(:, 1:end-1); Y = raw(:, end); % 检查不一致样本:条件相同但决策不同 [C, ia, ic] = unique(X, 'rows'); if length(ia) ~= size(X, 1) disp('存在条件相同但决策不同的样本,需要先处理'); % 打印冲突对 for i = 1:size(X,1) for j = i+1:size(X,1) if isequal(X(i,:), X(j,:)) && Y(i) ~= Y(j) fprintf('冲突样本: %d 和 %d, 决策分别为 %d 和 %d\n', i, j, Y(i), Y(j)); end end end end % 保存为mat文件,后续约简使用 save('decision_table.mat', 'X', 'Y');这段代码的逻辑是先把仿真结果排成矩阵,前几列是条件属性,最后一列是决策属性,然后用unique(X,'rows')检查有没有条件组合重复出现。ia返回每个唯一组合第一次出现的行号,如果length(ia)小于总行数,说明有重复条件。此时还要看重复行对应的Y是否相同:相同说明是冗余样本,可以删掉多出来的行;不同说明数据有冲突,必须先解决,不然约简出来的规则会自相矛盾。
注意示例里第3行和第4行都是区段3,但条件不同,这不是冲突,是不同故障工况。真正要查的是“条件完全相同、决策不同”的行。实际仿真时数据有几百行,不可能一行行看,就用这段代码自动检查。save默认保存成v7格式,兼容性好,不需要加-v7.3。
2.4 样本覆盖度:为什么每个区段都要有多工况样本
这一步很多人会忽略。粗糙集规则的强度取决于样本覆盖,如果某个区段只投一种故障样本,约简出来的规则就只对那一种工况有效。我在仿真里对每个区段会设置至少三组过渡电阻(0、20欧姆、100欧姆)、两组负荷水平、两种故障类型(单相接地和两相短路),这样每个区段都有几十条样本。
为什么要这么细?因为配电网故障定位规则本质上是“哪几个开关动作了,故障就在哪个区段”。但单相接地时,过流特征不明显,全靠零序方向,所以仅仅用开关过流状态会丢失信息。多工况样本能逼着约简算法把零序方向、电压等信息保留下来。
如果你手头没有仿真模型,可以用历史故障录波加上人工标注来补样本,但要注意样本时间跨度要覆盖不同季节负荷,否则离散化断点会偏移。我见过不少项目拿一个月的录波建库,夏天负荷一上来,规则全失效,这一点在第5章还要细说。
3. 属性约简与规则提取:核心算法的Matlab实现
3.1 区分矩阵与属性重要度:约简不是随便删列
决策表建好后,条件属性可能有冗余。比如S1过流和S2过流高度相关,一个动作另一个基本也动作,两个都保留不会增加区分能力,只会让规则变复杂。约简要找到最小的属性子集,使得它能像完整属性集一样区分所有不同决策的样本。
区分矩阵(discernibility matrix)是理解粗糙集约简的钥匙。对任意两个决策不同的样本i和j,找出所有能区分它们的属性,把这些属性记为一个集合;所有这样的集合放在一起就是区分矩阵。一个属性子集如果跟每个区分项都有交集,它就能区分所有样本对,就叫一个约简。核(core)是出现在所有区分项里的属性,这些属性删掉任何一个都会让区分能力下降。
求最小约简是NP难问题,属性多时不能暴力搜索。配电网场景属性个数通常不超过15个,我一般用贪心算法,从核属性开始,每次加入当前覆盖区分项最多的属性,直到整个子集能区分所有样本对。这样得到的不是理论最优,但工程上足够用,而且速度快。如果你想要更接近最优,可以加一个随机扰动反复跑几次,取属性个数最少的。
另一种思路是属性重要度:逐个试探删掉某个属性后,决策表里不一致样本数增加了多少。增加越多说明这个属性越重要。这个指标比区分矩阵更直观,可以配合贪心使用。我会先用区分矩阵求核和贪心约简,再用属性重要度做一次交叉验证。两个结果差异特别大时,多半是数据里有噪声样本,先回头修数据。
3.2 求约简与核的代码:区分矩阵法
这里给出可直接复制的函数。它接受条件属性矩阵X和决策属性列Y,返回核属性下标和贪心约简下标。
function [core_set, reduct] = rough_set_reduct(X, Y) % 粗糙集属性约简:区分矩阵法(贪心) % X: 决策表条件属性离散值,n x m % Y: 决策属性,n x 1 % 返回 core_set: 核属性下标, reduct: 贪心约简下标 [n, m] = size(X); % 构建区分项:只记录属性下标,不存全矩阵 discern = {}; for i = 1:n-1 for j = i+1:n if Y(i) ~= Y(j) % 找出i,j取值不同的属性 diff_attrs = find(X(i,:) ~= X(j,:)); if ~isempty(diff_attrs) discern{end+1} = diff_attrs; end end end end % 求核:出现在所有区分项里的属性 if isempty(discern) core_set = []; reduct = []; return; end candidate = discern{1}; for k = 2:length(discern) candidate = intersect(candidate, discern{k}); end core_set = candidate; % 贪心从核开始扩展 selected = core_set; remaining = setdiff(1:m, selected); while ~is_discernible(X, Y, selected) && ~isempty(remaining) best_attr = remaining(1); best_gain = -1; for a = remaining gain = covered_pairs(X, Y, [selected, a]); if gain > best_gain best_gain = gain; best_attr = a; end end selected = [selected, best_attr]; remaining = setdiff(remaining, selected); end reduct = selected; end function flag = is_discernible(X, Y, attrs) % 检查用attrs能否区分所有不同决策样本 flag = true; n = size(X,1); for i = 1:n-1 for j = i+1:n if Y(i) ~= Y(j) if isequal(X(i,attrs), X(j,attrs)) flag = false; return; end end end end end function cnt = covered_pairs(X, Y, attrs) % 统计用attrs能区分的不同决策样本对数量 cnt = 0; n = size(X,1); for i = 1:n-1 for j = i+1:n if Y(i) ~= Y(j) && ~isequal(X(i,attrs), X(j,attrs)) cnt = cnt + 1; end end end end这段代码是常用的实现。外层双重循环构建区分项时,只保留那些决策不同的样本对,因为决策相同的样本对不需要区分。find(X(i,:)~=X(j,:))返回的是两个样本取值不同的列下标,这个下标组合就是区分项。如果某一对不同决策样本在所有属性上取值都相同,那它们本身就是冲突样本,diff_attrs为空,不会加入区分项,但这样的冲突会在后续规则提取时暴露出来,应该回到第2章修数据。
求核时intersect逐个取交集,最后得出的属性就是所有区分项共有的属性。如果区分项很多,这个循环可能较慢,但配电网场景一般m小于20,运行时间可以忽略。贪心扩展的终止条件是is_discernible返回真,意思是当前selected已经能区分所有决策不同的样本对。covered_pairs统计加入某个属性后能增加多少可区分样本对,选增益最大的。
参数说明:当样本量n比较大、属性m也比较多时,双重循环的复杂度是O(n^2*m),可能成为瓶颈。我一般先把样本按区段分层抽样,每个区段取最多50条,控制n在200左右,既保留多样性又让计算在几秒内完成。如果实在要跑上千条样本,可以先把重复的条件组合合并并记录计数,但那样代码会复杂很多,工程上没必要。
3.3 从约简表提取决策规则:置信度与覆盖度
约简之后,把原决策表投影到约简列上,会出现很多重复行。把这些重复行合并,并对每个唯一条件组合统计决策分布,就是规则提取。
置信度的定义是:条件组合下,出现次数最多的决策类别占比。占比越高,规则越可信。覆盖度的定义是:该条件组合匹配的样本数占该决策类别总样本数的比例。覆盖度低说明规则太特殊,只适用于极少数样本。提取规则时通常要求置信度不低于0.8,覆盖度不低于0.2,否则丢弃或标记为弱规则。
% 用约简后的表提取规则 reduct_X = X(:, reduct); % 找到所有唯一的条件组合 [rule_cond, ~, ic] = unique(reduct_X, 'rows'); n_rules = size(rule_cond, 1); rule_table = cell(n_rules, 4); for r = 1:n_rules idx = find(ic == r); % 该组合下各类别计数 zones = Y(idx); % zones必须是正整数,若区段从0开始先+1 [gzone, gcount] = histcounts(zones, 'BinMethod', 'integers'); % 找出频数最大的区段 [max_cnt, pos] = max(gcount); winner_zone = gzone(pos); conf = max_cnt / length(idx); % 置信度 % 覆盖度:该规则匹配到的样本数 / 全区段winner_zone的样本数 cover = length(idx) / sum(Y == winner_zone); rule_table{r,1} = rule_cond(r,:); rule_table{r,2} = winner_zone; rule_table{r,3} = round(conf, 2); rule_table{r,4} = round(cover, 2); end % 打印置信度不低于0.8的规则 for r = 1:n_rules if rule_table{r,3} >= 0.8 fprintf('规则%d: 条件=%s -> 区段%d, 置信度=%.2f, 覆盖度=%.2f\n', ... r, mat2str(rule_table{r,1}), rule_table{r,2}, rule_table{r,3}, rule_table{r,4}); end end这段代码的逻辑很直接。unique(reduct_X,'rows')把约简后的条件组合去重,ic给每个样本分配一个规则序号。对每个规则序号,用histcounts统计Y的频数分布。注意histcounts的整数分箱需要Y是正整数,所以如果区段编号从0开始,代码里要先Y = Y + 1。max_cnt对应的区段就是规则的结论,置信度是max_cnt/length(idx)。
覆盖度的计算容易踩坑:不应该除以该规则匹配的总样本数,而应该除以该结论区段在整个训练集里的样本数。比如规则匹配了50个样本,其中48个属于区段3,而区段3总共有200个样本,那么覆盖度是48/200=24%,说明这条规则只覆盖了区段3的一部分样本。如果覆盖度只有5%,说明区段3还有别的重要工况没有形成规则,需要回到仿真阶段补样本。
规则提取完成后,把rule_table保存成.mat文件,在线定位时直接load。规则表就是知识库,不要在每次定位时重新跑约简,那既慢又可能因为在线带标签数据不完整而产出错误规则。
3.4 为什么不用现成工具箱而自己写函数
Matlab自带的分类学习器、决策树等工具,表面上看也能做规则提取,但它们和粗糙集的核心差异在于是否做属性约简。决策树会按信息增益逐层分裂,输出的是if-else树,而粗糙集约简是整体考虑属性子集的区分能力,两者选出的特征集经常不同。配电网故障定位场景下,我倾向用粗糙集是因为规则可以直接对应“哪些开关动作组合指向哪个区段”,解释性强,也方便运维人员审核。
自己写函数的另一个好处是可控。工具箱里的约简算法往往封装得太高,出了问题不好查。区分矩阵方法从头写也就一百行,逻辑清楚,调试方便。当然你也可以参考已有的开源实现,但一定要自己跑一遍测试样例,确认核和约简结果正确。
4. 故障定位推理:用规则表匹配在线故障特征
4.1 规则匹配与故障区段判定逻辑
离线规则库建好后,在线定位的核心是把FTU上报的状态组合跟规则条件做匹配。粗糙集本身是符号推理,不要求数值计算,所以匹配本质上是逻辑一致性问题。
精确匹配很简单:在线向量与某条规则的条件完全一致,直接采用该规则的结论。但现场数据经常出现漏报、误报。比如区段2故障时S2的FTU因为遥信回路抖动没有上报过流,在线向量少了一个1,精确匹配就会落空。这时需要近似匹配。我用加权海明距离:对在线向量和每条规则条件逐位比较,相同为0、不同为1,再按属性权重求和。距离最小的规则胜出。
属性权重的设定不是拍脑袋。约简结果里保留的属性是区分故障区段的关键,权重给1;被约简掉的属性权重给0.5,表示即使取值不同也可以容忍。这样做的道理是:被约简掉的属性本来就可以省略,它的取值变化不影响决策,所以匹配时不必太严格。
判定逻辑上,不要只看单条规则输出。我会让匹配函数返回距离最小的前三条规则,把它们各自对应的区段做一次投票;如果三条规则里两条投同一个区段,就输出那个区段,否则再按置信度加权。这能压掉单条规则误匹配带来的抖动。
4.2 在线匹配的Matlab函数与阈值设置
下面这个fault_locator_online函数是实际部署时的核心。它输入一条在线特征向量,返回匹配区段和置信度。
function [zone, conf, matched] = fault_locator_online(sample, rule_table, weight) % 在线故障定位:规则表匹配 % sample: 1 x m 离散化后的在线故障特征行向量 % rule_table: 离线提取的规则表cell,列1条件行向量,列2区段,列3置信度,列4覆盖度 % weight: 1 x m 属性权重,默认全1 % 返回匹配区段、置信度、匹配标志 if nargin < 3 || isempty(weight) weight = ones(size(sample)); end best_dist = inf; best_zone = []; best_conf = 0; best_cover = 0; for r = 1:size(rule_table,1) cond = rule_table{r,1}; % 加权海明距离 dist = sum(weight .* (sample ~= cond)); % 距离小优先;距离相同选置信度高 if dist < best_dist || (dist == best_dist && rule_table{r,3} > best_conf) best_dist = dist; best_zone = rule_table{r,2}; best_conf = rule_table{r,3}; best_cover = rule_table{r,4}; end end % 阈值判断:距离过大说明规则库没覆盖这种情况 max_dist_threshold = sum(weight) * 0.4; if best_dist <= max_dist_threshold zone = best_zone; conf = best_conf; matched = true; else zone = []; conf = 0; matched = false; end end这个函数用顺序扫描的方式遍历规则库,逐条计算加权海明距离。距离最小的规则先记下,如果距离相同,选置信度高的大。这里没有用向量化,规则库通常几百条,在线故障采样频率不高,顺序扫描的耗时在毫秒级,够用。如果是保护装置嵌入式部署,需要把规则表转成查表数组,避免用cell;但一般监控后台用Matlab没问题。
max_dist_threshold设成sum(weight)*0.4,意思是允许大约40%的加权属性位不匹配。这个值来自现场经验:FTU遥信误动率通常在5%到15%,再留一点裕度就取40%。如果现场装置经常漏报,可以把0.4改成0.5;如果误报多,改成0.3。注意阈值太大会把无关规则也匹配进来,太小会频繁返回matched=false,需要根据验证集调。
匹配不中时,函数返回空区段,业务侧应该走“未匹配”通道,比如调取附近区段的录波人工研判,而不是硬给一个结果。这是容易踩的坑:粗糙集规则库无法覆盖所有故障形态,强行匹配会误导抢修。
4.3 在线特征向量的生成:从FTU报文到离散码
在线匹配的前提是有一条跟训练时一样格式的离散向量。现场FTU通常上报故障电流、故障电压、开关变位、保护动作等遥信遥测,需要先做一层转换。
% 从FTU原始报文构造0/1离散特征 % ftu_data: 结构体,包含过流标记、电压标幺值、零序电流标记 function sample = build_sample(ftu_data) % 假设有3个开关的过流状态 sample(1) = ftu_data.s1_overcurrent; % 0/1 sample(2) = ftu_data.s2_overcurrent; sample(3) = ftu_data.s3_overcurrent; % 母线电压标幺值 -> 两档离散 if ftu_data.bus_voltage_pu > 0.9 sample(4) = 0; elseif ftu_data.bus_voltage_pu > 0.7 sample(4) = 1; else sample(4) = 2; end % 零序电流越限标志 sample(5) = ftu_data.zero_seq_overcurrent; end这里要特别强调:离散化断点必须跟训练时完全一致。训练时用的电压阈值是0.9和0.7,在线也一样。如果训练用等频离散化得到的断点是[0.85, 1.02],在线也必须用同一组断点,不能重新算。所以离线阶段要把断点参数存下来,跟规则表一起打包部署。
另一个常见问题是属性顺序。sample(1)对应决策表第1列,sample(2)对应第2列,必须固定。一旦改过决策表结构,比如新增了零序方向属性,却忘了更新在线转换函数,匹配就会错位。我通常会在规则表文件里保存一份attr_names元数据,在线匹配前检查长度和名称,能提前暴露这类低级错误。
4.4 多区段概率输出与候选区段排序
严格来说,粗糙集规则给出的是符号结论,不是概率。但工程上经常需要知道“还有哪些区段可疑”,方便巡检人员按优先级排查。做法是把匹配距离小于阈值的所有规则都找出来,按“距离越近、置信度越高、覆盖度越高”排序,输出一个候选区段列表。
% 返回所有可达标的候选规则,按得分排序 function cand = fault_locator_candidates(sample, rule_table, weight) scores = zeros(size(rule_table,1), 1); zones = zeros(size(rule_table,1), 1); for r = 1:size(rule_table,1) cond = rule_table{r,1}; dist = sum(weight .* (sample ~= cond)); if dist <= sum(weight)*0.4 % 得分 = 置信度 + 覆盖度*0.5 - 距离归一化*0.2 scores(r) = rule_table{r,3} + 0.5*rule_table{r,4} - 0.2*dist/sum(weight); zones(r) = rule_table{r,2}; end end [~, ord] = sort(scores, 'descend'); cand = [zones(ord(1:min(3,end))), scores(ord(1:min(3,end)))]; end得分公式是我自己常用的,不是粗糙集理论的一部分。为什么要加覆盖度?因为两条规则置信度一样,覆盖度高的说明它对应了该区段更普遍的故障形态,排在前面更合理。距离归一化项只是为了让距离差异也能影响排序。这个候选列表会输出给调度端,抢修队伍按第一个区段优先赶往现场,同时安排第二条路径待命。如果候选列表里前三个区段有跨越很远的两个位置,说明规则匹配效果不好,应该回去查数据。
5. 配电网故障定位的常见坑与排查:从数据到规则的五条踩坑记录
5.1 决策表不一致导致规则冲突
现象:约简前用unique检查发现不一致,规则表里出现同一条条件规则对应两个不同区段,在线匹配时结果反复跳变。
原因:故障样本里混入了过渡电阻差异很大的情况。比如区段2发生单相接地,过渡电阻是5欧姆,波形跟区段3的金属性短路在某些属性上很像,离散化之后变成同一档位,导致条件相同决策不同。
解决:先看冲突样本比例。低于10%可以直接去掉少数类或者用多数投票;高于10%说明离散化粒度太粗,增加一档细分。另外检查是不是漏掉了关键属性,比如零序电流方向、故障时刻相角,把这些属性补进决策表。
5.2 离散化断点选得不合适,约简结果不稳定
现象:同样的故障样本,改一个断点值,约简出来的属性集合就不同,规则数量也变。
原因:粗糙集对离散化很敏感,断点选在样本密集区时,微小扰动会改变大量样本的分档。
解决:不要手动拍断点,用等频离散化,每个属性分成3到5档,让每档样本数尽量接近。或者先做一轮归一化,再按分位数切分。可以用discretize(X, quantile(X, [0, 1/3, 2/3, 1])),这样断点至少稳定。注意这只能用于连续属性,开关状态保持0/1。
5.3 规则覆盖度太低,在线匹配不到
现象:规则库很大,但每条规则的覆盖度都只有一两个样本,在线来的新故障匹配不到。
原因:训练样本太少,每个区段只对应一种故障类型,但实际故障类型有金属性短路、经电阻短路、弧光接地等。
解决:仿真时对每个区段至少设置3种过渡电阻、2种负荷水平、2种故障类型(单相、两相、三相等),把样本量扩到上百条。还可以对规则做合并,把相同结论且条件属性取值相邻的规则用通配符替代,减少规则数。
5.4 仿真数据与现场数据分布差异大
现象:仿真阶段准确率90%,拿到现场数据之后掉到60%。
原因:仿真模型没考虑馈线分支负荷、配电变压器励磁涌流、CT饱和,导致在线特征分布跟训练集偏移。
解决:如果有现场录波数据,直接混进决策表重新约简。没有的话,把仿真模型里负荷改成随机波动,短路位置逐米扫描,而不是只设几个典型位置。在线侧还要做一样的离散化,如果现场量测精度低,适当放宽断点间隔。
5.5 Matlab代码在不同版本间行为不一致
现象:同一段约简代码在某个版本跑得好好的,换台电脑报错或结果不同。
原因:histcounts的分箱方式、unique的行排序规则在不同版本有细节差异;部分工具箱函数接口也变过。
解决:代码里避免依赖工具箱特定函数,核心算法自己写循环;如果用了discretize,确认目标版本支持。保存数据时用save,不用-v7.3除非数据太大,否则换版本容易读不了。把核心函数封装成独立.m文件,不依赖App,换环境损失最小。
6. 把模型用起来:验证、参数调整与离线-在线闭环
6.1 用留出法验证定位准确率
粗糙集规则库建好不是终点,要用验证集证明它能定位。常见做法是留出法:把决策表按7:3分成训练和验证,训练集约简提取规则,验证集跑在线匹配,统计每个区段的定位准确率。
准确率要按区段分开看,不能只看总准确率。比如区段3靠近末端,样本少,错误率高,原因很可能是末端短路电流特征不明显。这时候要么补充该区段的样本,要么单独增加一个判别属性,比如末端电压幅值。
6.2 关键参数调整:离散化粒度与匹配阈值
两个参数最影响结果,一是离散化档位数,二是匹配距离阈值。档位数从2调到5,规则数量和定位准确率会有一个峰值,太大容易过拟合,太小信息丢失。匹配阈值从0.3调到0.5,覆盖率高但误报也会高。一般做法是网格搜索,用验证集画一条准确率随阈值变化的曲线,选择拐点处的阈值。
网格搜索不能把验证集当测试集。如果有一批现场数据,最好把仿真数据当训练,现场数据当测试,这样才能反映真实部署效果。
6.3 从离线训练到在线更新的闭环
粗糙集的规则库可以离线训练,但配电网拓扑会变,新增了分布式电源或者改造了分段开关后,旧规则就失效。我的习惯是保留在线新样本,每积累到一定数量就新旧样本合并重新约简。不需要频繁跑,一个月一次就够。
操作时把新样本的决策属性标好,追加到decision_table.mat里,重新调rough_set_reduct和规则提取函数,更新规则表。追加前先做一致性检查,防止新数据污染旧规则。好的知识库应该越用越准,粗糙集在这一点上有天然优势:属性约简会剔除新数据带来的冗余属性。
最后说一个习惯:无论仿真多漂亮,上线前我都会用一台独立的机器跑一遍从decision_table.mat到fault_locator_online的全流程,模拟一次真实故障注入。这样能发现断点不一致、规则表路径写死这类低级问题。粗糙集不是黑匣子,规则能读出来,定位结果也解释得清楚。希望这些经验能帮你在配电网故障定位上少走弯路,把规则库真正用起来。
本文还有配套的精品资源,点击获取