【问题标题】:How to average a signal to remove noise with Python如何使用 Python 对信号进行平均以消除噪声
【发布时间】:2016-06-05 22:53:16
【问题描述】:

我正在实验室中使用 Arduino Mega 2560 开发板进行一个小项目。我想对三角波的正斜率部分(上升)的信号(电压)进行平均,以尽量消除噪声。我的频率是 20Hz,我正在使用 115200 位/秒的数据速率(Arduino 推荐的最快数据传输到计算机)。

原始信号如下所示:

我的数据存储在一个文本文件中,每一行对应一个数据点。由于我确实有数千个数据点,我希望一些平均可以使我的信号看起来更平滑,并在这种情况下形成一条接近完美的直线。但是,其他实验条件可能会导致信号沿三角波的正斜率部分具有特征,例如负峰,我绝对需要能够在平均信号上看到此特征。

我是一名 Python 初学者,所以我可能没有理想的方法来做到这一点,而且我的代码对你们大多数人来说可能看起来很糟糕,但我仍然希望得到你关于如何改进我的信号处理代码的提示/想法通过平均信号实现更好的噪声去除。

#!/usr/bin/python
import matplotlib.pyplot as plt
import math

# *** OPEN AND PLOT THE RAW DATA ***
data_filename = "My_File_Name"
filepath = "My_File_Path" + data_filename + ".txt"

# Open the Raw Data
with open(filepath, "r") as f:
    rawdata = f.readlines()

# Remove the \n     
rawdata = map(lambda s: s.strip(), rawdata)

# Plot the Raw Data
plt.plot(rawdata, 'r-')
plt.ylabel('Lightpower (V)')
plt.show()

# *** FIND THE LOCAL MAXIMUM AND MINIMUM
# Number of data points for each range 
datarange = 15 # This number can be changed for better processing
max_i_range = int(math.floor(len(rawdata)/datarange))-3

#Declare an empty lists for the max and min
min_list = []
max_list = []

min_list_index = []
max_list_index = []

i=0

for i in range(0, max_i_range):
    delimiter0 = i * datarange
    delimiter1 = (i+1) * datarange
    delimiter2 = (i+2) * datarange
    delimiter3 = (i+3) * datarange

    sumrange1 = sum(float(rawdata[i]) for i in range(delimiter0, delimiter1 + 1))
    averagerange1 = sumrange1 / len(rawdata[delimiter0:delimiter1])
    sumrange2 = sum(float(rawdata[i]) for i in range(delimiter1, delimiter2 + 1))
    averagerange2 = sumrange2 / len(rawdata[delimiter1:delimiter2])
    sumrange3 = sum(float(rawdata[i]) for i in range(delimiter2, delimiter3 + 1))
    averagerange3 = sumrange3 / len(rawdata[delimiter2:delimiter3])

    # Find if there is a minimum in range 2
    if ((averagerange1 > averagerange2) and (averagerange2 < averagerange3)):
        min_list.append(min(rawdata[delimiter1:delimiter2])) # Find the value of all the minimum 

        #Find the index of the minimum
        min_index = delimiter1 + [k for k, j in enumerate(rawdata[delimiter1:delimiter2]) if j == min(rawdata[delimiter1:delimiter2])][0] # [0] To use the first index out of the possible values
        min_list_index.append(min_index)


    # Find if there is a maximum in range 2
    if ((averagerange1 < averagerange2) and (averagerange2 > averagerange3)):
        max_list.append(max(rawdata[delimiter1:delimiter2])) # Find the value of all the maximum

        #Find the index of the maximum
        max_index = delimiter1 + [k for k, j in enumerate(rawdata[delimiter1:delimiter2]) if j == max(rawdata[delimiter1:delimiter2])][0] # [0] To use the first index out of the possible values
        max_list_index.append(max_index)



# *** PROCESS EACH RISE PATTERN ***

# One rise pattern goes from a min to a max
numb_of_rise_pattern = 50 # This number can be increased or lowered. This will average 50 rise patterns

max_min_diff_total = 0

for i in range(0, numb_of_rise_pattern):
    max_min_diff_total = max_min_diff_total + (max_list_index[i]-min_list_index[i])

# Find the average number of points for each rise pattern
max_min_diff_avg = abs(max_min_diff_total / numb_of_rise_pattern)

# Find the average values for each of the rise pattern
avg_position_value_list = []


for i in range(0, max_min_diff_avg):

    sum_position_value = 0
    for j in range(0, numb_of_rise_pattern):

        sum_position_value = sum_position_value + float( rawdata[ min_list_index[j] + i ] )
    avg_position_value = sum_position_value / numb_of_rise_pattern

    avg_position_value_list.append(avg_position_value)


#Plot the Processed Signal
plt.plot(avg_position_value_list, 'r-')
plt.title(data_filename)
plt.ylabel('Lightpower (V)')
plt.show()

最后,处理后的信号是这样的:

我希望有一条直线,但我可能错了。我相信我的代码中可能存在很多缺陷,并且肯定会有更好的方法来实现我想要的。如果你们中的任何人想从中获得乐趣,我已经包含了一个包含一些原始数据的文本文件的链接。

http://www108.zippyshare.com/v/2iba0XMD/file.html

【问题讨论】:

    标签: python signals signal-processing average


    【解决方案1】:

    更简单的方法可能是使用平滑函数,例如移动窗口平均值。使用 pandas.Series 中的滚动功能实现这一点非常简单。 (仅显示 501 个点。)调整数值参数(窗口大小)以获得不同的平滑量。

    import pandas as pd
    import matplotlib.pyplot as plt
    
    # Plot the Raw Data
    ts = rawdata[0:500]
    plt.plot(ts, 'r-')
    plt.ylabel('Lightpower (V)')
    
    #    previous version
    #    smooth_data = pd.rolling_mean(rawdata[0:500],5).plot(style='k')
    #    changes to pandas require a change to the code as follows:
    smooth_data = pd.Series(ts).rolling(window=7).mean().plot(style='k')
    plt.show()
    

    Moving Average

    移动平均线基本上是一个低通滤波器。因此,我们还可以使用 SciPy 中的函数实现低通滤波器,如下所示:

    import scipy.signal as signal
    
    # First, design the Buterworth filter
    N  = 3    # Filter order
    Wn = 0.1 # Cutoff frequency
    B, A = signal.butter(N, Wn, output='ba')
    smooth_data = signal.filtfilt(B,A, rawdata[0:500])
    plt.plot(ts,'r-')
    plt.plot(smooth_data[0:500],'b-')
    plt.show()
    

    Low-Pass Filter

    巴特沃斯过滤方法来自OceanPython.org,顺便说一句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 2016-12-20
      • 1970-01-01
      • 2011-10-15
      • 1970-01-01
      • 2012-04-27
      • 1970-01-01
      相关资源
      最近更新 更多