局部放电三维图谱绘制:MATLAB源码与原始数据实战 简介这份MATLAB局部放电三维图谱绘制项目面向电气工程、高电压技术方向的学生与研究人员以及从事电力设备状态评估的工程师。它针对局部放电信号难以直观呈现频率、强度与时间多维关系的问题提供从原始数据到可视化图谱的完整实践路径。压缩包共2个文件包含1个m脚本与1个csv数据文件整体约27.75MB其中csv存放特高频尖端放电实测信号m文件为三维谱图绘制源码可直接运行复现。目前已有5760人学习下载说明其在相关教学与科研场景中具备一定参考价值。读者可借此掌握MATLAB数据读取、矩阵处理与三维图形生成的关键技巧理解特高频检测在局部放电分析中的作用并将源码作为模板迁移到其他信号可视化任务中适合作为课程设计、实验报告或故障诊断研究的入门素材。1. 局部放电三维图谱绘制从原始数据到可视化这套 MATLAB 源码能直接跑如果你手头有一批局部放电检测的原始采样数据却卡在“怎么把它变成能放进报告里的三维图谱”这一步这套 MATLAB 源码加原始数据的组合就是为你准备的。它解决的不是算法理论问题而是工程落地里最磨人的那一段数据怎么读、相位怎么对齐、三维坐标怎么映射、图谱怎么渲染出可用的视觉效果。适合两类人一类是刚接触局部放电检测、需要快速出图的研究生或初级工程师另一类是想在现有分析流程里嵌入标准化绘图模块的开发者。整套代码基于 MATLAB 实现不依赖额外工具箱拿到数据就能跑改几个参数就能适配自己的采样率与工频周期。2. 项目结构与技术选型为什么用 MATLAB 而不是 Python2.1 目录组织与文件职责拿到压缩包后先别急着点运行。花两分钟把目录结构看清楚后面改代码会省很多事。这套资源的组织方式很典型按“数据—脚本—输出”三层分开pd_plot/ ├── data/ │ ├── pd_raw_01.mat % 原始采样数据含时间戳与幅值 │ ├── pd_raw_02.mat │ └── pd_raw_03.mat ├── src/ │ ├── main_plot3d.m % 主入口一键出图 │ ├── load_pd_data.m % 数据读取与预处理 │ ├── phase_align.m % 相位对齐与周期折叠 │ ├── build_3d_matrix.m % 三维矩阵构建 │ └── render_surface.m % 曲面渲染与配色 ├── config/ │ └── params.m % 采样率、工频、幅值范围等参数 └── output/ └── figures/ % 生成的图谱保存位置data里放的是.mat格式的原始数据每个文件对应一次检测记录。src下按处理流程拆成五个函数main_plot3d.m负责串联。config/params.m是唯一需要你手动改的地方采样率和工频这两个参数如果填错后面所有图都是歪的。output/figures是自动创建的不用提前建。注意如果你的数据是 CSV 或 TXT 格式不要直接改后缀名。load_pd_data.m里用的是load函数读取.mat换成文本格式需要改读取逻辑后面会讲怎么改。2.2 技术选型MATLAB 在这个场景下的真实优势很多人第一反应是“为什么不用 PythonMatplotlib 也能画三维图”。这个项目选 MATLAB 不是随便定的有三个很实际的原因。第一局部放电数据的采样率通常在 10 MS/s 到 100 MS/s 之间一次记录动辄几百万个点。MATLAB 的矩阵运算在这类稠密数值计算上比 Python 的 NumPy 更省心尤其是accumarray和histcounts3这类函数做相位折叠和三维分箱时几乎是一行搞定。第二MATLAB 的surf和patch渲染引擎对工程人员更友好配色、光照、视角调整不需要额外装包colormap和camlight直接调用。第三也是最现实的一点很多电力检测单位的报告模板就是 MATLAB 出的图你换成 Python 出的图格式和风格对不上返工成本更高。当然MATLAB 的缺点也明显不开源、部署麻烦。但如果你只是做数据分析出图不是做产品级软件这个代价可以接受。常见做法是用 MATLAB 做算法验证和出图确认流程没问题后再把核心逻辑移植到 Python 或 C 做集成。2.3 数据流一个脉冲从采样到图谱的完整链路理解数据流比看懂单个函数更重要。这套代码的处理链路是这样的原始采样数据是一维的时间序列每个点包含时间戳和幅值。第一步load_pd_data.m把.mat文件读进来提取出time和amplitude两个向量同时做去直流和简单滤波。第二步phase_align.m根据工频周期把时间轴转换成相位轴通常一个工频周期对应 0 到 360 度然后按周期折叠把多个周期的数据叠加到同一个相位区间。第三步build_3d_matrix.m把相位、幅值、周期序号三个维度做分箱统计生成一个三维矩阵每个格子的值是该相位-幅值区间内的脉冲计数。第四步render_surface.m用surf或bar3把这个三维矩阵画出来配上颜色映射和坐标轴标签。整个链路里最容易出问题的是第二步的相位对齐。如果工频估计不准折叠后的图谱会出现“重影”脉冲分布散开看起来像噪声。params.m里的f0参数就是干这个的默认 50 Hz如果你的检测环境是 60 Hz 电网必须改成 60。3. 运行环境与数据准备从零到第一张图3.1 MATLAB 版本与工具箱依赖这套代码对 MATLAB 版本的要求不苛刻R2018a 及以上都能跑。核心函数surf、histcounts3、accumarray都是基础功能不需要额外工具箱。唯一需要注意的是histcounts3在 R2017b 才引入如果你用的是更早的版本需要把build_3d_matrix.m里的分箱逻辑换成hist3加循环或者手动用discretize实现。检查版本的方法很简单在命令行输入ver(matlab)如果返回的版本号低于 9.4对应 R2018a建议升级。不升级也能跑但部分函数需要替换。我一般会在main_plot3d.m开头加一个版本检查避免在旧版本上跑出莫名其妙的结果% 版本检查低于 R2018a 给出警告 if verLessThan(matlab, 9.4) warning(当前 MATLAB 版本低于 R2018a部分函数可能不兼容建议升级。); end这段代码放在主脚本最前面不影响正常执行只是提醒。如果你确定自己的版本没问题可以删掉。3.2 原始数据格式说明与替换方法data目录下的.mat文件里存的是什么打开一个看看% 查看数据结构 raw load(data/pd_raw_01.mat); disp(fieldnames(raw));通常会看到time和amplitude两个变量。time是采样时间戳向量单位秒amplitude是对应的幅值向量单位伏特或毫伏取决于你的采集设备。如果你的数据字段名不一样比如叫t和v需要在load_pd_data.m里改映射function [t, amp] load_pd_data(filepath) % 读取 .mat 文件并提取时间与幅值 raw load(filepath); % 兼容不同字段名优先找 time/amplitude找不到则尝试 t/v if isfield(raw, time) isfield(raw, amplitude) t raw.time; amp raw.amplitude; elseif isfield(raw, t) isfield(raw, v) t raw.t; amp raw.v; else error(未识别的数据字段请检查 .mat 文件变量名。); end % 去直流分量 amp amp - mean(amp); % 简单低通滤波截止频率由 params 传入 amp lowpass(amp, 1e6, 1/(t(2)-t(1))); end这段函数的逻辑很直白先尝试标准字段名找不到就回退到常见简写。去直流是必须的否则图谱会整体偏移。低通滤波的截止频率我设了 1 MHz实际用的时候根据你的信号带宽调整params.m里有对应参数。如果你的数据是 CSV 格式把load换成readmatrix或csvread然后按列提取。常见做法是% CSV 读取示例 data readmatrix(data/pd_raw_01.csv); t data(:, 1); amp data(:, 2);改完读取逻辑后后面的流程完全不用动。3.3 参数配置采样率、工频、幅值范围config/params.m是整个项目里你唯一必须手动改的文件。打开它会看到类似这样的结构function p params() % 采样率单位 Hz根据你的采集设备填写 p.fs 20e6; % 20 MS/s % 工频频率单位 Hz50 或 60 p.f0 50; % 幅值显示范围单位与数据一致 p.amp_range [-0.5, 0.5]; % 相位分箱数决定图谱的横向分辨率 p.n_phase 360; % 幅值分箱数决定纵向分辨率 p.n_amp 128; % 周期数上限避免数据量过大导致内存溢出 p.max_cycles 200; endfs填错的话相位对齐会完全乱掉。比如你的实际采样率是 10 MS/s填了 20 MS/s算出来的工频周期长度会差一倍图谱上的脉冲会挤在一起或者散开。f0填错同理。amp_range影响的是显示范围不影响计算但如果你的信号幅值超出这个范围图谱上会出现截断。n_phase和n_amp决定分辨率数值越大图越细但计算量也越大。max_cycles是保护机制防止一次加载太多周期导致内存不够。提示第一次跑的时候建议先把max_cycles设小一点比如 50确认流程通了再加大。我见过有人直接设 10000结果 MATLAB 卡死血泪经验。4. 核心模块拆解相位对齐与三维矩阵构建4.1 相位对齐把时间轴折叠成 0-360 度相位对齐是整套代码里最核心的一步也是最容易翻车的地方。原理不复杂局部放电脉冲通常发生在工频电压的特定相位区间所以我们需要把长时间采样的数据按工频周期折叠看看脉冲在哪些相位上集中出现。phase_align.m的实现逻辑如下function [phase, cycle_idx] phase_align(t, amp, p) % 根据工频周期计算每个采样点的相位和周期序号 % t: 时间向量amp: 幅值向量p: 参数结构体 % 计算每个采样点对应的工频周期序号 cycle_idx floor(t * p.f0); % 计算相位范围 0 到 360 度 phase mod(t * p.f0 * 360, 360); % 只保留幅值超过阈值的点减少后续计算量 threshold 0.1 * max(abs(amp)); valid abs(amp) threshold; phase phase(valid); cycle_idx cycle_idx(valid); amp amp(valid); % 限制周期数防止内存溢出 max_cycle min(cycle_idx) p.max_cycles; keep cycle_idx max_cycle; phase phase(keep); cycle_idx cycle_idx(keep); end逐段解释。cycle_idx floor(t * p.f0)算出每个采样点属于第几个工频周期比如 t0.02s、f050Hz 时cycle_idx1表示第二个周期。phase mod(t * p.f0 * 360, 360)把时间映射到 0-360 度mod 保证结果不会超过 360。阈值过滤那一步很关键局部放电脉冲只占整个采样序列的很小一部分大部分点是背景噪声如果不过滤三维矩阵会非常稀疏画出来的图几乎看不到东西。阈值我设的是最大幅值的 10%你可以根据信噪比调整。max_cycles的限制是为了防止数据量过大。假设采样率 20 MS/s工频 50 Hz一个周期有 400k 个点200 个周期就是 8000 万个点。虽然过滤后剩下的脉冲点不多但中间计算过程会占用大量内存。我一般会先跑 50 个周期看看效果确认没问题再加大。4.2 三维矩阵构建相位-幅值-周期计数有了相位和周期序号下一步是把它们映射到一个三维矩阵里。build_3d_matrix.m做的是分箱统计function M build_3d_matrix(phase, amp, cycle_idx, p) % 构建三维计数矩阵相位 x 幅值 x 周期 % 输出 M 的维度为 [n_phase, n_amp, n_cycle] % 相位分箱边界 phase_edges linspace(0, 360, p.n_phase 1); % 幅值分箱边界 amp_edges linspace(p.amp_range(1), p.amp_range(2), p.n_amp 1); % 计算每个点所属的箱序号 phase_bin discretize(phase, phase_edges); amp_bin discretize(amp, amp_edges); % 去除超出范围的无效点 valid ~isnan(phase_bin) ~isnan(amp_bin); phase_bin phase_bin(valid); amp_bin amp_bin(valid); cycle_idx cycle_idx(valid); % 将周期序号归一化到 1 到 n_cycle n_cycle max(cycle_idx) - min(cycle_idx) 1; cycle_bin cycle_idx - min(cycle_idx) 1; % 用 accumarray 做三维计数 M accumarray([phase_bin, amp_bin, cycle_bin], 1, ... [p.n_phase, p.n_amp, n_cycle]); enddiscretize把连续的相位和幅值映射到离散的箱序号。accumarray是 MATLAB 里做分组统计的利器这里用它统计每个三维格子里的脉冲数量。输出矩阵M的三个维度分别是相位、幅值、周期。如果你只想看相位-幅值分布可以对第三个维度求和M2d sum(M, 3)这样得到的就是传统的 PRPD 图谱。n_phase和n_amp的选择有讲究。相位方向 360 个箱对应 1 度分辨率通常够用幅值方向 128 个箱如果你的信号动态范围大可以加到 256。箱数越多图越细腻但每个箱里的计数会变少可能出现大量空格子。常见做法是先用默认值跑一遍看看图谱的稀疏程度再决定要不要调整。4.3 曲面渲染surf 与 bar3 的选择render_surface.m负责把三维矩阵画出来。MATLAB 里画三维图谱有两种主流方式surf画曲面bar3画柱状图。这套代码默认用surf因为曲面图在展示脉冲密度分布时更连续视觉效果更平滑。function render_surface(M, p) % 绘制三维局部放电图谱 % M: 三维计数矩阵p: 参数结构体 % 对计数取对数压缩动态范围避免高密度区域过曝 M_log log1p(M); % 创建相位和幅值坐标轴 phase_axis linspace(0, 360, p.n_phase); amp_axis linspace(p.amp_range(1), p.amp_range(2), p.n_amp); % 对周期维度求和得到相位-幅值二维分布 M2d squeeze(sum(M_log, 3)); % 绘制曲面 figure(Color, w); surf(phase_axis, amp_axis, M2d, EdgeColor, none); colormap(jet); colorbar; % 坐标轴与标签 xlabel(相位 (度)); ylabel(幅值 (V)); zlabel(脉冲计数 (log)); title(局部放电三维图谱); % 视角与光照 view(-45, 30); camlight(headlight); lighting(gouraud); % 保存图片 saveas(gcf, fullfile(output, figures, pd_3d_surface.png)); endlog1p(M)是对计数做对数变换原因是局部放电脉冲的密度分布极不均匀某些相位区间计数极高直接画曲面会导致其他区域被压平。取对数后动态范围压缩细节更清晰。squeeze(sum(M_log, 3))把三维矩阵沿周期维度求和变成二维相位-幅值矩阵。如果你想看周期维度的变化可以不做求和直接用slice函数画切片图。view(-45, 30)设置视角camlight和lighting调整光照这些参数不影响数据但影响出图效果。我一般会多试几个视角选一个脉冲分布最清楚的。保存路径是output/figures文件名固定重复运行会覆盖。注意如果你的 MATLAB 没有log1p函数R2016b 之前用log(1 M)替代效果一样。5. 避坑与常见问题跑不通时先看这几条5.1 图谱出现“重影”或脉冲散开现象画出来的三维图谱上脉冲分布不是集中在特定相位区间而是散成一片或者出现两个对称的“影子”。原因相位对齐时工频估计不准。最常见的情况是params.m里的f0填了 50但实际电网频率在 49.8 到 50.2 之间波动长时间采样后累积误差导致周期折叠错位。解决先估算实际工频。用amp数据做 FFT找 50 Hz 附近的峰值% 估算实际工频 L length(amp); Y fft(amp); P2 abs(Y / L); P1 P2(1:L/21); f p.fs * (0:L/2) / L; [~, idx] max(P1(f 45 f 55)); f_actual f(find(f 45, 1) idx - 1); fprintf(估算工频%.2f Hz\n, f_actual);把f_actual填回params.m的f0重跑。如果电网频率波动大可以考虑分段处理每段单独估频。5.2 内存溢出或运行极慢现象MATLAB 卡死或者报 “Out of memory” 错误。原因max_cycles设得太大或者采样率很高导致单周期点数过多。20 MS/s 采样率下一个 50 Hz 周期有 400k 个点200 个周期就是 8000 万个点即使过滤后剩下的脉冲点不多中间计算过程也会占用大量内存。解决先把max_cycles降到 50跑通后再逐步加大。如果确实需要处理大量周期可以分批处理每批算完后把结果累加到总矩阵里。另外load_pd_data.m里的低通滤波会生成一个和原始数据等长的向量如果内存紧张可以改成对过滤后的脉冲点做滤波而不是对全量数据。5.3 图谱上几乎看不到脉冲现象三维曲面几乎是平的只有零星几个凸起。原因阈值设得太高把大部分脉冲过滤掉了。phase_align.m里的threshold 0.1 * max(abs(amp))是一个经验值如果你的信号信噪比低或者脉冲幅值普遍偏小这个阈值会误杀。解决把阈值改成0.05 * max(abs(amp))或者更低先看看能不能出图。如果还是不行检查amp_range是否覆盖了你的信号幅值范围。比如你的脉冲幅值在 0.01 到 0.1 之间但amp_range设的是[-0.5, 0.5]那所有脉冲都会挤在中间几个箱里看起来像一条线。5.4 保存的图片是空白或格式不对现象output/figures里的 PNG 文件打开是空白或者尺寸不对。原因saveas在某些 MATLAB 版本上对surf图的渲染有问题尤其是开启了lighting之后。另外如果output/figures目录不存在saveas会报错但不会自动创建。解决在main_plot3d.m开头加目录创建逻辑if ~exist(output/figures, dir) mkdir(output/figures); end保存图片时改用print函数兼容性更好print(gcf, fullfile(output, figures, pd_3d_surface.png), -dpng, -r300);-r300指定 300 DPI适合放进报告。5.5 换了自己的数据后字段名不匹配现象报错 “未识别的数据字段” 或 “变量不存在”。原因不同采集设备导出的.mat文件变量名不一样有的叫data有的叫signal有的甚至存成结构体。解决先用whos或fieldnames看看文件里到底有什么raw load(your_data.mat); disp(fieldnames(raw));然后根据实际字段名改load_pd_data.m里的映射逻辑。如果是结构体嵌套比如raw.data.time用raw.data.time提取。6. 二次开发从出图到集成几个实用的改造方向这套代码的定位是“快速出图”但实际项目里往往需要把它嵌到更大的流程里。我一般会从三个方向改造批量处理、参数自动化、输出格式适配。批量处理是最常见的需求。原始代码一次只处理一个文件改成批量只需要在main_plot3d.m外面套一层循环% 批量处理 data 目录下所有 .mat 文件 files dir(data/*.mat); for k 1:length(files) filepath fullfile(files(k).folder, files(k).name); fprintf(处理%s\n, files(k).name); % 调用主流程输出文件名带上原始文件名前缀 main_plot3d(filepath, sprintf(fig_%s, files(k).name(1:end-4))); end这里需要把main_plot3d.m改成接受输入参数的形式而不是硬编码文件路径。改造后每个数据文件生成一张图文件名带前缀方便追溯。参数自动化是第二个方向。手动改params.m在数据量大的时候很痛苦。可以把参数改成从文件名或配置文件读取。比如文件名里带采样率信息pd_20M_50Hz_01.mat用正则解析% 从文件名解析采样率和工频 tokens regexp(filename, (\d)M_(\d)Hz, tokens); if ~isempty(tokens) p.fs str2double(tokens{1}{1}) * 1e6; p.f0 str2double(tokens{1}{2}); end这样换数据的时候不用改代码只要文件名规范就行。输出格式适配是第三个方向。MATLAB 默认出的图是 PNG 或 FIG但很多报告模板要求 EPS 或 PDF 矢量图。把print函数的格式参数改一下就行格式参数适用场景PNG-dpng网页、Word 插入EPS-depscLaTeX、学术论文PDF-dpdf报告、打印FIGsavefig后续 MATLAB 中再编辑我一般会同时输出 PNG 和 EPSPNG 用于快速预览EPS 用于最终排版。还有一个容易被忽略的点三维图谱的视角和配色。默认的jet配色在打印成黑白时区分度很差如果报告需要黑白打印换成gray或hot更稳妥。视角方面view(-45, 30)是一个通用角度但如果你的脉冲集中在特定相位区间可能需要调整方位角让那个区间正对镜头。我通常会生成三张不同视角的图选最清楚的那张。从那以后我每次换新数据都强制先跑一遍params.m检查确认采样率和工频填对了再往下走。这个习惯帮我省了很多返工时间。希望帮到你。本文还有配套的精品资源点击获取