2016-02-23 145 views
1

我正在使用Arduino Mega 2560板实验室中的一个小型项目。我想对三角波的正斜率部分(上升)的信号(电压)进行平均,以尝试去除尽可能多的噪声。我的频率是20Hz,我正在使用115200比特/秒的数据速率(最快由Arduino推荐将数据传输到计算机)。如何使用Python对信号进行平均去除噪声

原始信号看起来像这样:

Raw Signal

Raw Signal Zoom

Raw Signal Zoom Plus

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

我是一名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() 

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

Averaged Signal

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

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

+0

这可能会更好codereview.stackexchange.com –

+0

谢谢,我刚刚开始在那里的一个线程,但如果有人想在这里帮助,你是欢迎。 – LaGuille

+0

我将不胜感激,如果你可以看看这个:https://stackoverflow.com/questions/44458859/python-finding-pattern-in-a-lot –

回答

3
简单

可能是使用平滑函数,诸如移动窗平均。使用熊猫的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() 

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(rawdata[0:500],'r-') 
plt.plot(smooth_data[0:500],'b-') 
plt.show() 

Low-Pass Filter

的巴特沃斯滤波器的方法是从OceanPython.org,BTW。

+0

嗨,爱德华,我将不胜感激,如果你可以看看这个:https:// stackoverflow。COM /问题/ 44458859/Python的调查图案中,一个积 –