当前位置: 首页 > news >正文

Hampel滤波器的完整C#实现示例,适合用于信号处理(如IGBT功率循环测试中的Vf波形或TVJ数据去离群点)

以下是一个Hampel滤波器的完整C#实现示例,适合用于信号处理(如IGBT功率循环测试中的Vf波形或TVJ数据去离群点)。代码包含:

  • 经典实现(带1.4826尺度因子)
  • 边界处理(边缘复制 padding)
  • 可配置窗口大小和阈值(threshold,通常3~5)
  • 返回滤波后信号 + 可选的离群点掩码(bool数组)
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceSignalProcessing{/// <summary>/// Hampel滤波器:用于检测和替换时间序列中的离群点(outliers)/// 基于局部中位数 + MAD(中值绝对偏差)/// </summary>publicstaticclassHampelFilter{/// <summary>/// 对一维信号应用Hampel滤波/// </summary>/// <param name="input">输入信号(double数组)</param>/// <param name="windowHalfWidth">窗口半宽k(总窗口长度=2k+1,必须奇数)</param>/// <param name="threshold">阈值(标准差倍数),常见值3.0~5.0</param>/// <param name="useScaleFactor">是否使用1.4826尺度因子(默认true,使MAD≈σ)</param>/// <param name="outliers">输出:离群点掩码(true表示该点被替换)</param>/// <returns>滤波后的信号(与输入长度相同)</returns>publicstaticdouble[]Filter(double[]input,intwindowHalfWidth=5,doublethreshold=5.0,booluseScaleFactor=true,outbool[]outliers){if(input==null||input.Length==0)thrownewArgumentException("输入信号不能为空");intn=input.Length;intwindowSize=2*windowHalfWidth+1;doublescale=useScaleFactor?1.4826:1.0;double[]output=newdouble[n];outliers=newbool[n];Array.Copy(input,output,n);// 默认输出=输入for(inti=0;i<n;i++){// 提取当前窗口List<double>window=newList<double>();for(intj=-windowHalfWidth;j<=windowHalfWidth;j++){intidx=i+j;// 边界处理:复制边缘值(replication padding)if(idx<0)idx=0;if(idx>=n)idx=n-1;window.Add(input[idx]);}doublemedian=Median(window);doublemad=Mad(window,median);if(mad<1e-10)// 防止mad=0导致除零{continue;}doubledeviation=Math.Abs(input[i]-median);doublelimit=threshold*scale*mad;if(deviation>limit){output[i]=median;// 替换为中位数outliers[i]=true;}else{outliers[i]=false;}}returnoutput;}/// <summary>/// 计算数组的中位数/// </summary>privatestaticdoubleMedian(IEnumerable<double>values){varsorted=values.OrderBy(x=>x).ToList();intcount=sorted.Count;if(count%2==1)returnsorted[count/2];return(sorted[count/2-1]+sorted[count/2])/2.0;}/// <summary>/// 计算MAD(中值绝对偏差)/// </summary>privatestaticdoubleMad(IEnumerable<double>values,doublemedian){vardeviations=values.Select(x=>Math.Abs(x-median)).ToList();returnMedian(deviations);}// ---------------- 测试 / 示例用法 ----------------publicstaticvoidExample(){// 模拟带尖峰噪声的信号double[]signal=newdouble[100];Randomrand=newRandom();for(inti=0;i<signal.Length;i++){signal[i]=Math.Sin(i*0.1)+0.1*(rand.NextDouble()-0.5);}// 人为加入几个离群点signal[20]=5.0;signal[50]=-4.0;signal[80]=6.0;bool[]isOutlier;double[]filtered=Filter(signal,windowHalfWidth:5,threshold:4.0,outisOutlier);Console.WriteLine("原始信号(部分): "+string.Join(", ",signal.Take(10)));Console.WriteLine("滤波后信号(部分): "+string.Join(", ",filtered.Take(10)));// 打印离群点位置for(inti=0;i<isOutlier.Length;i++){if(isOutlier[i])Console.WriteLine($"离群点 at index{i}: 原值={signal[i]:F3}→ 替换为{filtered[i]:F3}");}}}// 使用示例:HampelFilter.Example();}

关键参数说明

参数推荐值说明
windowHalfWidth (k)3 ~ 10窗口半宽,总窗口=2k+1,越大越平滑但延迟增加
threshold3.0(经典) / 5.0(保守)多少倍“标准差”视为离群(你的代码用5)
useScaleFactortrue是否乘1.4826(使MAD≈正态σ),推荐开启

与你原有代码的对比 / 改进点

你的原始实现:

double[]signal=newdouble[tvjCount+2*k];Array.Copy(tvj.ToArray(),1,signal,0,k);// 前向复制第2~k+1个点Array.Copy(tvj.ToArray(),0,signal,k,tvjCount);Array.Copy(tvj.ToArray(),tvjCount-k-1,signal,k+tvjCount,k);double[]hampelSignal=this.HampelFilter(signal,k,5);tvj=newList<double>(hampelSignal);// 注意输出比输入短2k

改进建议:

  • 输出长度与输入一致(更符合大多数使用场景)
  • 边界用复制边缘值(replication),避免引入不自然的跳变
  • 可选输出离群点位置,便于调试/日志
  • 增加对mad≈0的保护(防止全平坦信号除零)

性能提示

  • 对于几千点信号,当前实现足够快(O(n × w log w),w=窗口大小)
  • 如果信号非常长(>10万点),可考虑:
    • 使用排序后的滑动窗口中位数(更复杂)
    • 或借助第三方库(如Math.NET Numerics + 自定义MAD)

如果需要更高效版本、结合你的TVJ代码的集成示例、或求导/其他变体,随时告诉我!

http://www.jsqmd.com/news/615029/

相关文章:

  • 亚马逊停止旧款 Kindle 支持,用户与市场面临新变局
  • 2025届学术党必备的五大AI论文神器实测分析
  • XCOM RAN推出面向物理AI的端到端私有5G解决方案
  • Steam Achievement Manager:全方位游戏成就管理工具深度解析
  • iOS 15-16 iCloud激活锁绕过:applera1n图形化工具完整使用指南
  • PFC(Power Factor Correction,功率因数校正)
  • PHP条形码生成轻量级实现:从行业痛点到跨场景适配的完整解决方案
  • 第十五节:启动序列——从 claude 命令到 REPL 就绪
  • Bilibili-Evolved革新性动画性能优化指南:全方位提升B站观看体验
  • 多线程设计:join() 理解
  • 2025届最火的六大AI论文神器解析与推荐
  • 2026届学术党必备的五大AI辅助论文工具推荐
  • 光网络:弥合AI算力与消费之间的鸿沟
  • 一文搞懂 Cookie、Session 和 Token 的区别
  • 多格式文档批量字数统计与导出 Excel 备忘
  • Linux 下双击程序没反应?一条报错定位 root 启动问题
  • c++ grpc拦截器 c++如何实现grpc的客户端和服务端interceptor
  • Piggy_Packages V2026.1 帮助文档(四)WRF区域模式降尺度
  • 蓝桥杯——算法入门
  • 罗德与施瓦茨ZNB8功能概述
  • 3个突破性技巧:Figma设计数据结构化如何解决开发协作痛点
  • 空间智能技术赋能交通基础设施数字化提升方案
  • EF Core 10向量搜索扩展架构设计图泄露事件(内部PPT第7页已证实):这3个设计决策将重写.NET AI应用开发范式
  • 鸣潮游戏自动化终极指南:如何用ok-ww工具解放你的游戏时间
  • PHP容器化落地国产化替代的最后1公里:从Docker镜像构建、OpenEuler适配到等保2.0合规部署(含12项硬性检测项)
  • P4561 [JXOI2018] 排序问题
  • version attribute在html中必要吗_DOCTYPE替代说明【说明】
  • 知识点解释(1.1)
  • 不记命令也能排障:catpaw chat 实战手册俟
  • 贾子科学体系TMM三层结构定律全解:终结方法霸权,重构科学的“操作系统”