我正在使用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()
最后,处理过的信号如下所示:
我期待更直线,但我可能错了。我相信我的代码中可能存在很多缺陷,肯定会有更好的方法来实现我想要的东西。我已经在文本文件中添加了一些链接,其中包含一些原始数据,如果你们中的任何一个想要玩得开心的话。
答案 0 :(得分:6)
更简单的可能是使用平滑功能,例如移动窗口平均值。使用pandas中的rolling_mean函数实现起来非常简单。 (仅显示501个点。)调整数值参数(窗口大小)以获得不同的平滑量。
import pandas as pd
import matplotlib.pyplot as plt
# Plot the Raw Data
plt.plot(rawdata[0:500], 'r-')
plt.ylabel('Lightpower (V)')
smooth_data = pd.rolling_mean(ts,5).plot(style='k')
plt.show()
移动平均线基本上是低通滤波器。因此,我们还可以使用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(rawdata[0:500],'r-')
plt.plot(smooth_data[0:500],'b-')
plt.show()
巴特沃斯滤波器方法来自OceanPython.org,BTW。