Visual Basic .NET中List元素快速计算:正弦波峰值查找优化
正弦电压波峰值(最大值/最小值)及索引的高效查找方案
原代码的性能瓶颈分析
- 索引查找错误+低效:
list_values_voltage.IndexOf(list_values_voltage.Item(k*Range))会遍历整个列表找匹配值,若存在重复电压值,会返回第一个匹配项的索引,导致切片范围完全错误;且每次IndexOf都是O(n)操作,循环累积后时间复杂度飙升至O(n²)。 - 切片逻辑错误:
GetRange的长度参数用k*Range + Range会导致每次切片长度翻倍(第一次取Range个元素,第二次取2Range...),完全违背按固定周期分段的需求。 - 不必要的内存开销:每次
GetRange都会创建新的List实例,频繁的内存分配和GC回收会大幅拖慢运行速度。
优化方案(基于已知周期的最优实现)
既然已知正弦波的输出频率,我们可以直接按固定周期区间遍历原列表,在每个区间内直接查找最大值、最小值及其索引,全程无需创建子列表,时间复杂度降至O(n):
Public Sub Leakage_Current_Result_Verification(list_current As List(Of Double), list_voltage As List(Of Double)) ' 复用传入的列表,避免不必要的赋值 Dim sample_rate As Double = 1000 Dim periodTime As Double = 1 / AmetekNew.Output_Frequency Dim range As Integer = Convert.ToInt32(periodTime * sample_rate) Dim totalPeriods As Integer = list_voltage.Count \ range ' 整数除法,避免浮点运算误差 ' 结果存储列表 Dim list_voltage_peaks_max As New List(Of Double) Dim list_voltage_peaks_min As New List(Of Double) Dim list_voltage_peak_max_indexes As New List(Of Integer) Dim list_voltage_peak_min_indexes As New List(Of Integer) Dim list_current_at_peaks As New List(Of Double) Dim list_current_fault_values As New List(Of Double) Dim list_fault_indexes As New List(Of Integer) For periodIdx As Integer = 0 To totalPeriods - 1 Dim startIdx As Integer = periodIdx * range Dim endIdx As Integer = startIdx + range - 1 ' 闭区间,避免越界 ' 处理最后一段可能不足一个周期的情况 If endIdx >= list_voltage.Count Then endIdx = list_voltage.Count - 1 End If ' 遍历当前周期区间,找最大、最小值及对应索引 Dim currentMax As Double = Double.MinValue Dim currentMin As Double = Double.MaxValue Dim maxIdx As Integer = startIdx Dim minIdx As Integer = startIdx For i As Integer = startIdx To endIdx ' 更新最大值 If list_voltage(i) > currentMax Then currentMax = list_voltage(i) maxIdx = i End If ' 更新最小值 If list_voltage(i) < currentMin Then currentMin = list_voltage(i) minIdx = i End If ' 同时检查电流故障(>1mA) If list_current(i) > 0.001 Then ' 1mA = 0.001A list_current_fault_values.Add(list_current(i)) list_fault_indexes.Add(i) End If Next ' 存储当前周期的峰值数据 list_voltage_peaks_max.Add(currentMax) list_voltage_peaks_min.Add(currentMin) list_voltage_peak_max_indexes.Add(maxIdx) list_voltage_peak_min_indexes.Add(minIdx) ' 存储最大值对应的电流值 list_current_at_peaks.Add(list_current(maxIdx)) Next End Sub
优化点说明
- 直接区间遍历:跳过所有子列表创建和索引查找操作,直接在原列表的周期区间内遍历,时间复杂度从O(n²)降到O(n)。
- 避免内存浪费:全程复用原列表,无额外List实例创建,减少GC压力。
- 逻辑修正:用整数除法计算周期数,避免浮点运算误差;处理最后一段不足一个周期的边界情况。
- 合并操作:将电流故障检查合并到峰值查找的遍历中,避免二次遍历列表。
通用峰值检测方案(适用于周期未知/波动的场景)
如果正弦波存在频率漂移或周期未知,可采用差分法检测峰值(当前值大于左右相邻值即为局部最大值,小于则为局部最小值),同样是O(n)时间复杂度:
' 示例:查找所有局部最大值的索引 Dim peakIndexes As New List(Of Integer) For i As Integer = 1 To list_voltage.Count - 2 If list_voltage(i) > list_voltage(i-1) AndAlso list_voltage(i) > list_voltage(i+1) Then peakIndexes.Add(i) End If Next
注:该方法会检测所有局部峰值,若正弦波无噪声,每个周期只会有一个最大值和一个最小值;若存在噪声,可增加滑动窗口滤波后再检测。
内容的提问来源于stack exchange,提问作者meddlrainerwiggsler
相关产品推荐
相关产品推荐

