
搞综合管廊安全评估的同行一定对LEC法不陌生。项目刚启动那阵我直接拿传统LEC法给管廊基坑风险打分现场七八个专家围着表格争论同一个风险源打出完全相反的分值取个平均硬算出来的D值看上去精确到小数实际上把所有判断里的不确定性都吞掉了。后来我把三角模糊数和云模型引进来用matlab重写了整套评估流程从打分表到风险云图一步到位才算把这件事做顺。这篇文章就把完整的模型思路、代码实现和踩过的坑整理出来给做地下工程、市政管廊安全评估的朋友做个参考。1. 为什么综合管廊施工风险评估要换一套模型1.1 综合管廊施工风险到底特殊在哪综合管廊和普通房建工程不一样它是把电力、通信、燃气、热力、给排水这些市政管线集中到一个地下隧道空间里。施工阶段开挖深度大、作业面狭窄、多工种交叉再加上燃气舱、电力舱这类特殊功能舱室存在风险链条比普通项目长得多。我做过的一个项目里管廊基坑深度超过12米紧贴着既有市政道路一侧还有运行中的高压燃气管。施工期间一旦发生基坑坍塌或者机械误伤管线事故影响范围就远超现场本身可能波及整条道路的交通和周边居民的供电供气。这种情况下风险评估如果只靠拍脑袋定个“高风险”了事根本没法支撑后续的安全管控决策必须有一套能量化、可追溯、能对应到具体工序的评价方法。1.2 传统LEC法的两个硬伤LEC法的计算公式很简单D L × E × CL是事故发生可能性E是人员暴露频率C是后果严重程度。上世纪八十年代引入国内后因为简单实用一直是安全评价的主流工具。但用多了就会发现两个硬伤。第一个硬伤是打分标准的边界切得太硬。LEC法把可能性分成“很不可能、可能、相当可能”等档位每个档位对应一个固定分数。可实际上“可能性较大”和“可能性很大”之间根本没有清晰的分界线让两个经验不同的专家给同一个场景打分一个给3分一个给6分背后的判断差异其实是模糊的强行落到精确值就把模糊性丢了。第二个硬伤是分值相乘的“一次定生死”。D值落在70以上就是显著风险69以下就是一般风险临界点两边一个天一个地。可施工现场的风险是动态波动的今天支护没跟上就可能逼近临界值明天加强监测又降回去了。传统LEC法给不出这种波动范围只能给一个静态的数字决策者看着这个数字很难判断自己距离下一个风险等级还有多少安全裕度。1.3 三角模糊数如何把“很危险”变成可计算的语言三角模糊数解决的就是打分时的模糊性它的表示形式是(a, b, c)a是判断的下限b是最可能值c是上限。专家打分的时候不需要纠结到底给3还是给4直接说“这个风险的可能性在2到4之间最可能是3”就把主观判断的不确定性完整表达出来了。判断起来也更自然人脑本来就更擅长给范围而不是精确点值。比如我问你“明天出门带伞的概率”你很容易说“大概七八成”但要精确到73.5%就很难。三角模糊数符合人的表达习惯又保留了足够的信息量去做后续计算。从数学上说三角模糊数的隶属度函数是分段线性的区间中间数值隶属度最高两端逐渐降到0形式足够简单后续做解模糊、模糊聚类、云变换都比较顺。这也是我最终选它而不是更高阶的梯形模糊数或者高斯模糊数的原因——够用且不容易把模型复杂化到没法跟现场的人解释。2. 模型落地的完整设计思路从指标体系到云参数2.1 风险评估指标体系怎么搭才不跑偏管廊施工风险因素多指标体系如果不加约束会越搭越臃肿。我的做法是采用“风险类型 × 施工阶段”的矩阵式思路先把风险类型定住再对照各施工阶段去筛选有效指标这样专家打分行对各施工阶段去筛选有效指标这样专家打分时能直接对应到具体作业场景不至于泛泛而谈。参考我实际项目里用得比较顺的一套指标主要风险因素如下表序号风险因素主要关联施工阶段1基坑坍塌基坑开挖、支护施工2高处坠落主体结构施工、附属设施安装3地下管线破坏基坑开挖、机械作业4机械伤害吊装运输、预制拼装5触电伤害机电安装、临时用电6中毒窒息舱内作业、防水施工7火灾爆炸燃气舱施工、焊接作业指标数量控制在10个以内比较合适超过15个打分时间成本就会明显上升专家在后半程容易疲劳打分数据质量反而下降。我一般建议优先保留后果严重度高的指标比如燃气舱作业、深基坑开挖这些这类风险即使发生概率低一旦出事故就是大事必须评进高风险区。重点提一句指标之间要避免语义重叠。比如“机械伤害”和“物体打击”放在一起专家打分时很难区分边界我遇到过好几个专家在类似指标上给出截然相反的分值。处理办法是合并相近指标或者给每个指标补充明确的操作定义和典型事故场景定义写清楚打分噪音会小很多。2.2 三角模糊LEC的语言变量与赋值表确定了指标下一步就是把L、E、C三个要素转换成三角模糊数。传统LEC法每个要素有标准赋值表我在这套量表的基础上做了一层模糊化让专家在打分时选择一个区间而不是孤零零的点。这里给出我常用的三角模糊LEC赋值框架基于传统LEC法档位做的扩展要素语言描述传统值三角模糊区间L可能性很不可能0.2(0.1, 0.2, 0.5)L可能性可能1(0.5, 1, 2)L可能性相当可能3(2, 3, 4)L可能性完全可能6(4, 6, 8)E暴露频率偶尔暴露1(0.5, 1, 2)E暴露频率经常暴露3(2, 3, 4)E暴露频率持续暴露6(4, 6, 10)C后果严重度一般事故7(3, 7, 10)C后果严重度重大事故15(10, 15, 20)C后果严重度特别重大事故100(80, 100, 100)这套赋值表在实际操作里让专家先选档位再给一个上下浮动区间。比如某专家认为基坑坍塌的可能性属于“相当可能”但开挖深度大、地质条件差他愿意给到(3, 4, 6)而不是表里默认的(2, 3, 4)这种弹性正是模糊化带来的好处。打分表建议做成Excel模板下发给专家每位专家一列每个指标三行格式完全统一。第一轮打分完成后我会把匿名汇总结果发回给所有专家做一轮简单的德尔菲式反馈——看到别人的区间跟自己差异较大时专家往往会主动修正自己的判断这是控制打分发散度的最廉价手段。2.3 云模型在这里解决的是什么问题云模型是李德毅院士提出的一套定性定量转换工具三个参数各有明确含义期望Ex表示概念最典型的取值熵En表示概念覆盖范围的模糊程度超熵He表示熵本身的稳定程度也就是“概念的厚度”。说人话就是Ex是风险评分最有可能落在的位置En反映评分范围大小He反映评分范围本身稳不稳定。如果多位专家对同一个风险共识度高En和He都比较小云看起来就是一条细窄的带如果专家分歧很大云的形状就会又宽又厚这本身就是很重要的决策信息——分歧大的评估项需要在现场管理上多花精力去核实。云模型接入这套评估体系解决的核心问题是给LEC打分结果的每个D值都配上了一个“不确定度包络”。传统评估只给一个risk数字配合云模型之后我可以输出这个数字的置信带宽和专家共识程度决策者看到的不再是孤零零一个点而是一个风险分布。2.4 整条流水线的逻辑链这套三角模糊LEC云模型的核心流程可以整理成一条清晰的流水线先把专家打分转换成三角模糊数每个专家对某个指标在L、E、C三维度各给出一个模糊区间然后对每个维度做三角模糊数解模糊把每个专家的判断浓缩成一个代表性数值接着把所有专家在该维度的代表性数值视为一组样本用统计方法估计出云参数最后通过云代数运算把L、E、C三朵云合成D值的云再与标准风险等级云做隶属度比较判定最终风险等级。整条链路里最关键的决策点是“解模糊的时机”。我是先解模糊再统计云参数而不是先聚合模糊数再做云计算这样每个云参数都保留了专家个体判断的分布信息改起来也更灵活。有人会问直接解模糊不是又把模糊性丢了吗注意这里丢的是“单个专家打分时的模糊区间”保留下来的是“所有专家之间的意见分布”后者才是更值得关注的不确定性来源也是云模型能刻画的部分。3. matlab代码实现从打分表到云图的完整流程3.1 代码框架与主脚本设计我设计的代码框架包含一个主脚本和五个核心函数分层清晰方便替换模型参数。整个框架分四块专家数据输入、云参数估计、云运算、风险等级判定与可视化。主脚本只需要控制数据流向每个环节都是独立函数调参不需要动主逻辑。%% 三角模糊LEC云模型风险评估主脚本 % 功能读取专家三角模糊打分估计云参数计算风险D值云判定等级并绘图 % 依赖函数tfn_defuzzify.m, estimate_cloud_params.m, forward_cloud.m, risk_level.m clear; clc; close all; rng(42); % 固定随机种子保证结果可复现 % 风险因素名称 riskNames {基坑坍塌; 高处坠落; 地下管线破坏; 机械伤害; ... 触电伤害; 中毒窒息; 火灾爆炸}; % 专家打分数据cell数组每个cell对应一个风险因素 % 每个矩阵行 专家编号列 [L_a L_b L_c, E_a E_b E_c, C_a C_b C_c] scoresAll cell(length(riskNames), 1); % 这里以“基坑坍塌”为例展示5位专家的三角模糊打分 scoresAll{1} [ 2 3 4 3 6 10 7 15 25; 2 3 3 3 6 6 7 15 15; 1 2 3 2 3 6 10 15 20; 3 4 5 3 6 10 7 10 15; 2 3 4 4 6 8 15 15 40; ]; % 其余风险因素的生产数据按同样格式填入这里先初始化为示例矩阵 defaultScore [ 1 2 3 2 3 6 3 7 10; 1 2 3 1 2 3 3 7 7; 1 1 2 2 3 6 3 7 10; 1 2 2 2 3 3 7 7 10; 2 3 4 3 6 6 7 7 15; ]; for k 2:length(riskNames) scoresAll{k} defaultScore; end注意matlab的随机数种子固定为42不代表这是“官方标准”只是让每次运行结果一致方便编写文档时截图演示。真正做项目时我会跑多次蒙特卡洛观察云参数在不同随机种子下的稳定性。3.2 三角模糊数与云模型核心函数核心函数五个其中三角模糊数解模糊我用的期望值法公式是(a 4b c) / 6中间值权重是上下界的两倍符合LEC打分时专家通常对“最可能值”更有把握的直觉。function x tfn_defuzzify(a, b, c) % 三角模糊数期望值法解模糊 % 输入a-下限b-最可能值c-上限 % 输出解模糊后的确定性代表值 x (a 4*b c) / 6; end云参数估计函数里Ex用样本均值En用一阶绝对中心矩估算He再根据样本方差和En的平方做非负修正。这段逻辑对应的是半经验估计法操作上比最大似然估计更稳不会因为样本量小就产生奇奇怪怪的参数值。function [Ex, En, He] estimate_cloud_params(x) % 根据样本数据估计云模型三参数 % 输入x - 样本数据向量 % 输出Ex-期望En-熵He-超熵 Ex mean(x); % 一阶绝对中心矩估算熵 En mean(abs(x - Ex)) * sqrt(pi / 2); % 用样本方差减En的平方估算超熵避免负值 s2 var(x); He sqrt(max(0, s2 - En^2)); end正向云发生器是云模型可视化的核心它做的事情是先给每个云滴加一个熵的随机扰动再以扰动后的方差生成正态分布云滴计算确定度。代码里直接用了randn不依赖统计工具箱。function [x, y] forward_cloud(Ex, En, He, n) % 正向正态云发生器 % 输入Ex-期望En-熵He-超熵n-云滴数量 % 输出x-云滴位置坐标y-云滴确定度 Enn En He .* randn(1, n); x Ex Enn .* randn(1, n); y exp(-(x - Ex).^2 ./ (2 .* Enn.^2)); end这三个函数加起来不到40行但已经覆盖了模糊解算和云生成的完整链路。风险等级判定函数我会在3.3节跟可视化一起讲。3.3 风险等级判定与可视化输出主流程中对每个风险因素要经历聚合专家打分、逐维度解模糊、估计云参数、云代数运算、风险等级判定五个步骤。聚合时我直接对打分矩阵的每一列取平均得到综合三角模糊数这样专家权重均匀简单直观避免过度设计。%% 主循环逐风险因素计算云参数与风险等级 % 标准风险等级云参数[Ex, En, He] stdLevels [ 10 5 1; % 低风险 D: 0-20 45 8 1; % 一般风险 D: 20-70 115 20 2; % 显著风险 D: 70-160 240 30 3; % 高风险 D: 160-320 400 50 5; % 极高风险 D: 320 ]; levelNames {低风险; 一般风险; 显著风险; 高风险; 极高风险}; numRisk length(riskNames); D_clouds zeros(numRisk, 3); D_levels strings(numRisk, 1); L_clouds zeros(numRisk, 3); E_clouds zeros(numRisk, 3); C_clouds zeros(numRisk, 3); for k 1:numRisk scores scoresAll{k}; numExpert size(scores, 1); % 各维度逐专家解模糊 L_vals zeros(numExpert, 1); E_vals zeros(numExpert, 1); C_vals zeros(numExpert, 1); for i 1:numExpert L_vals(i) tfn_defuzzify(scores(i,1), scores(i,2), scores(i,3)); E_vals(i) tfn_defuzzify(scores(i,4), scores(i,5), scores(i,6)); C_vals(i) tfn_defuzzify(scores(i,7), scores(i,8), scores(i,9)); end % 估计三维度云参数 [L_clouds(k,1), L_clouds(k,2), L_clouds(k,3)] estimate_cloud_params(L_vals); [E_clouds(k,1), E_clouds(k,2), E_clouds(k,3)] estimate_cloud_params(E_vals); [C_clouds(k,1), C_clouds(k,2), C_clouds(k,3)] estimate_cloud_params(C_vals); % 云代数运算D L * E * C一阶误差传播近似 ExL L_clouds(k,1); EnL L_clouds(k,2); HeL L_clouds(k,3); ExE E_clouds(k,1); EnE E_clouds(k,2); HeE E_clouds(k,3); ExC C_clouds(k,1); EnC C_clouds(k,2); HeC C_clouds(k,3); ExD ExL * ExE * ExC; EnD abs(ExD) * sqrt((EnL/ExL)^2 (EnE/ExE)^2 (EnC/ExC)^2); HeD abs(ExD) * sqrt((HeL/ExL)^2 (HeE/ExE)^2 (HeC/ExC)^2); D_clouds(k, :) [ExD, EnD, HeD]; % 风险等级判定 D_levels(k) risk_level(D_clouds(k,:), stdLevels, levelNames); end风险等级判定的核心思路是算综合确定度。对每个标准等级云计算评估D值云期望落在该等级云期望曲线上的确定度取确定度最大的那个等级作为判定结果。function level risk_level(D_cloud, stdLevels, levelNames) % 通过期望隶属度判定风险等级 % 输入D_cloud-待判定的云参数向量stdLevels-标准等级云参数矩阵levelNames-等级名称cell numLevel size(stdLevels, 1); membership zeros(numLevel, 1); for i 1:numLevel Ex_s stdLevels(i, 1); En_s stdLevels(i, 2); membership(i) exp(-(D_cloud(1) - Ex_s)^2 / (2 * En_s^2)); end [~, idx] max(membership); level levelNames{idx}; end最后可视化输出三部分每朵风险云的云滴图、全部风险因素的D值对比条形图、风险评估汇总表。云滴图用scatter加透明度比plot更直观因为大量云滴重叠在一起时透明度能体现出密度分布差异。%% 可视化风险云图 等级对比条形图 figure(Position, [100 100 1200 900]); for k 1:numRisk subplot(3, 3, k); [xd, yd] forward_cloud(D_clouds(k,1), D_clouds(k,2), D_clouds(k,3), 3000); scatter(xd, yd, 6, filled, MarkerFaceAlpha, 0.25); hold on; % 叠加期望曲线 x_curve 0:1:D_clouds(k,1) 4*D_clouds(k,2); y_curve exp(-(x_curve - D_clouds(k,1)).^2 / (2 * D_clouds(k,2)^2)); plot(x_curve, y_curve, r-, LineWidth, 1.5); xlabel(风险D值); ylabel(确定度); grid on; title(sprintf(%s | %s, riskNames{k}, D_levels(k))); end % 风险评估汇总条形图 figure(Position, [100 100 1000 500]); ExD_all D_clouds(:,1); EnD_all D_clouds(:,2); bar(ExD_all, FaceColor, [0.3 0.6 0.9]); hold on; errorbar(1:numRisk, ExD_all, EnD_all, k., LineWidth, 1.2); set(gca, XTickLabel, riskNames); xtickangle(30); ylabel(风险D值期望); title(综合管廊施工风险评估结果含不确定性); grid on;运行这段代码你会发现“基坑坍塌”的D值云可能由于C维度方差大云团明显比“物体打击”更厚更宽。这个厚度差异本身就是风险预警信号——说明专家组对基坑坍塌后果严重度的认识很不一致管理上需要先统一认识再谈风险管控措施。3.4 模拟数据验证与参数敏感性用模拟数据跑通代码后一定要做一步参数敏感性验证。我常用的方式是固定Ex集群不变把En和He分别放大1.5倍和缩小一半观察风险等级判定是否翻转。比如某指标D值云参数是(95, 20, 4)En放大到30之后期望隶属度在“显著风险”和“一般风险”之间的差值可能缩小到不足5%。这种情形说明风险正好处在等级边界附近评估结果对专家认知波动非常敏感。我会把这个指标标记为“边界风险”并要求现场加大监测频率而不是为了让评估结果好看一点就去调整打分数据。有一种反面做法是干脆不导入He让云退化成带厚度的普通正态曲线。我用早期版本的时候试过风险等级判定确实更“干脆”但代价是抹掉了专家分歧度这个宝贵信息。从决策角度看专家分歧很大本身就是风险尤其管廊里涉及燃气舱、高压电力舱这类高风险源分歧大就意味着管控预案需要覆盖更广的场景。4. 实操中踩过的坑与排查技巧4.1 云滴过聚或过散En和He到底怎么来第一次跑通代码时我遇到了一个很尴尬的问题云滴图看着像一条细线完全没有云朵的厚度感。检查之后发现是En设得太小。当时为了演示方便我拍脑袋给En设了0.5结果云滴全挤在一个点上。后来我改成用样本数据估计En和He问题就解决了。重点在于En不要从模糊区间里拉一个感觉值而是通过一阶绝对中心矩从专家打分的离散度里去估计He则通过样本方差与En平方的差值来反推。这样估计出来的云参数能真实反映专家分歧不会犯“把不确定的东西输入确定值”的错。如果你跑出来云滴整体形状没问题但局部太稀疏说明云滴数不够。3000个云滴是个基础量输出精细图的时候我会放到8000个以上matlab运行也没压力。4.2 专家打分离散度太高一致性检查与异常值处理有一回评估“火灾爆炸”风险8个专家里有1个专家在L维度给出(8, 10, 10)其他专家基本都在(2, 4, 6)附近。均值一算En被拉得很大风险等级直接从“显著”跳到“极高”整个结果都被这个异常值带跑了。遇到这种情况要做的第一件事不是改数据而是做专家一致性检查。简单的办法是计算专家打分两两之间的距离设定一个相似度阈值把明显偏离的专家打分标记出来。那个给高分的专家很可能掌握着你没注意到的重要信息比如他知道施工班组曾在燃气舱附近违规动火。我处理的时候会找这位专家单独复核确认理由属实就保留他的高分并提高权重确认是误判就让他重新打。不建议直接删除异常专家因为真实项目里异常值往往对应着新的风险认知直接删掉等于主动丢掉信息。流程上应该永远是“先沟通确认再决定如何处理”。4.3 风险等级边界卡住不要硬切数据要算相似度D值正好落在两个等级交界处的情况非常常见。比如某个指标D值期望是157标准分级里“显著风险”上限是160再往上就是“高风险”。传统做法会判定为“显著风险”但这么处理的风险在于忽略了不确定性区间——如果En算出来是25那么实际D值有一半概率超过160风险提升到高等级是完全可能的。我的做法是把判定结果改成输出“主风险等级 次风险等级”的形式。主等级由期望隶属度最大决定次等级由隶属度第二大的等级给出。如果两个隶属度差值小于10%评估结论会标注“处于等级边界建议按较高等级管理”。这样做现场处理时有明确抓手不会卡在数值边界上吵来吵去。这个问题的根源在标准等级的云参数设置。每一档标准云不应该是一个点而是一个带我用(0-20)低风险、(20-70)一般风险这类区间时会取区间中点作为Ex区间半宽的两倍左右作为En这样标准等级之间天然有交叠评估结果不会因为一个临界点产生突变。4.4 一个容易被忽略的细节He出现零值用最开始的版本跑数据时我遇到过He算出精确零的情况查下来是样本方差比一阶绝对中心矩估算出的En平方还小。这说明专家打分高度一致不确定度本身也极低理论上说得通但从云模型计算的角度He为零会让正向云发生器里的Enn变成固定值云滴厚度完全消失。处理办法是给超熵设一个下限比如默认0.5防止云退化成普通正态分布。设置之后要留意如果某个指标He一直压在底线上说明该风险评估的共识度极高可以适当降低云图展示的透明度免得决策者误以为还有很大不确定性。5. 最后再分享一点实际操作层面的体会做完两个完整的综合管廊项目后我最大的体会是模型再好专家打分环节的质量才是决定评估效果的因素。三角模糊LEC云模型的优势不是“算得准”而是“算得明白”——准不准取决于输入能不能解释清楚不确定性才是模型本身的能力。实际操作中我建议打分表下发前先开半小时的评分培训会用一两个示例场景现场带着专家走一遍打分流程让大家明确“区间不是越宽越好”这个原则。有专家习惯性给(1, 5, 10)这种宽区间看起来是表达模糊性实质上是没有认真判断这种数据对模型输出的En贡献极大会把整体风险不确定性拉高到失真水平。代码本身后续还有很多扩展方向。比如把云模型换成二维、把LEC维度和云相似度算法升级或者对同一段管廊按不同施工阶段分别评估后做动态风险曲线这些我都陆续在试。如果你也在做类似的安全风险评估建议先用我这套模拟数据跑通流程再替换成你项目的真实打分表整个迁移过程会非常顺。