从 Arduino Uno 读取的 ADXL335 电压尖峰
Spikes in ADXL335 voltage read from Arduino Uno
背景: 我已将 ADXL335 加速度计连接到 Arduino Uno 上的引脚 A0、A1、A2。测量时Arduino通过usb与笔记本电脑连接,加速度计直接由Arduino上的3.3V引脚供电。
目的是从加速器读取电压并使用 Python 绘制相应的时间和频谱。整个过程非常简单,我实际上能够做到这一点。我记录的信号快照如下所示。从加速度计到 read/write 的 Arduino 代码和从 Arduino 读取并构建绘图的 Python 代码在底部提供以供参考。
我面临的问题是 Arduino 读取的实际值(我认为)。
问题: 在 read/write 过程中,Arduino 似乎接收到了一些噪音。为了证明这一点,我 运行 在传感器静止时进行了两次单独的数据采集。下面提供了快照。
7 年前,我在研究生院使用过类似的系统,使用的是 National Instruments DAC 和 LabView。那时我确实遇到了一些噪音,但这类似于约 60 Hz 的电噪音。这个比较奇特,不知道怎么处理。
结束语:有人可以帮我理解我看到的是什么噪音吗?也许知道这叫做什么会帮助我详细研究它并尝试解决它。任何 pointers/references 也会有所帮助。
未来范围:我相信稳定的静止信号作为第一步将极大地帮助减轻电压偏移(频率频谱中的直流分量),即使一个简单的平均值。另外,我需要学习如何提高uno的采样率。
使用的程序:
Arduino 代码从加速度计read/write
#define xPin A0
#define yPin A1
#define zPin A2
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop()
{
// put your main code here, to run repeatedly:
float xVal = analogRead(xPin);
float yVal = analogRead(yPin);
float zVal = analogRead(zPin);
long time = micros(); //current time
delay(1);
//Serial.print("x=");
Serial.print(time);
Serial.print("\t");
Serial.print(xVal);
Serial.print("\t");
Serial.print(yVal);
Serial.print("\t");
Serial.println(zVal);
delay(1);
}
Python 从 Arduino 读取并构建绘图的代码
#Thanks for the tutorial, Curio Res
#https://www.youtube.com/watch?v=fIlklRIuXoY
from serial.tools import list_ports
import serial
import time
import csv
#find the port corresponding to the Arduino
ports = list_ports.comports()
for port in ports: print(port)
#setup the file for saving voltage data from the accel/Arduino
f=open("data.csv","w",newline='')
f.truncate()
serialCom = serial.Serial('COM9',115200) #ENSURE the correct COM#
#Reset the arduino
serialCom.setDTR(False)
time.sleep(1)
serialCom.flushInput()
serialCom.setDTR(True)
#read from the Arduino
kmax=2000 #number of data points to record
#kmax* sampling rate in millisec delay = total time of data recorded
for k in range(kmax):
try:
#read a line of data
s_bytes = serialCom.readline()
#Decode binary
decoded_bytes = s_bytes.decode("utf-8").strip('\r\n')
#print(decoded_bytes)
#parse lines
if k==0:
values = [x for x in decoded_bytes.split(",")]
else:
values = [float(x) for x in decoded_bytes.split()]
print(values)
writer = csv.writer(f,delimiter=",")
writer.writerow(values)
except:
print("ERROR. Line was not recorded.")
f.close() #close csv file
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#import data using padas
data = pd.read_csv("data.csv",skiprows=1)
data.columns = ["time", "accel-x", "accel-y", "accel-z"] #using three channels
# data.columns = ["time", "accel-x"] #using one channel
# print(data)
#retrieve data columns
D=data.to_numpy();
time=(D[:,0])/1000000 #Arduino prints time in micro-second
x_accel=D[:,1]
y_accel=D[:,2]
z_accel=D[:,3]
signal=(x_accel**2)**0.5 #sum y and z for rms in the future
# first method of removing dc component.
i=1
dc_component=[]
for i in range(1,10):
dc_component.append(signal[i])
signal=x_accel-np.average(dc_component)
#setup doesn't provide data with uniform time-interval
#create an array of all successive time steps to see the spread later
i=1
delta_t=[]
#find the average time step in the array 'time'
for i in range(1,len(time)):
delta_t.append(time[i]-time[i-1])
dt=np.average(delta_t) #average time step
fs=1/dt #sampling frequency
N=len(time) #number of samples
f_step=fs/N #req interval
freq=np.linspace(0,(N-1)*f_step,N) #construct the frequency array
# time=np.linspace(0,(N-1)*dt,N) #Test time array
# y=1*np.sin(2*np.pi*1*time) #Test sine signal
x=np.fft.fft(signal) #perform a fast fourier transform
x_mag = np.abs(x)/N #obtain the magnitude of the transform
freq_plot=freq[0:int(N/2+1)]
x_mag_plot=2*x_mag[0:int(N/2+1)] #enter, Nyquist
x_mag_plot[0]=x_mag_plot[0]/2 #DC component does not need to be multiplied by 2
# plot
fig,[ax1,ax2] = plt.subplots(figsize=(7.5,5),nrows=2,ncols=1,constrained_layout=True)
ax1.plot(time,signal)
ax1.set_title('Time History')
ax1.set_xlabel('time(s)')
ax1.set_ylabel('Voltage(V)')
# plt.xlim([min(time),max(time)])
ax2.plot(freq_plot,x_mag_plot)
ax2.set_title('Frequency Spectrum')
ax2.set_xlabel('Frequency(Hz)')
ax2.set_ylabel('Amplitude')
plt.show()
这是尖峰噪声。
您应该使用中值滤波器来清理信号。它是一个数字非线性滤波器,您可以在您的软件中实现它。
请注意:我不知道您使用的是哪个采样频率,但采样频率越高,收集到的噪声就越多。因此,将采样频率限制为 2 x 信号带宽(香农定理)
背景: 我已将 ADXL335 加速度计连接到 Arduino Uno 上的引脚 A0、A1、A2。测量时Arduino通过usb与笔记本电脑连接,加速度计直接由Arduino上的3.3V引脚供电。 目的是从加速器读取电压并使用 Python 绘制相应的时间和频谱。整个过程非常简单,我实际上能够做到这一点。我记录的信号快照如下所示。从加速度计到 read/write 的 Arduino 代码和从 Arduino 读取并构建绘图的 Python 代码在底部提供以供参考。
我面临的问题是 Arduino 读取的实际值(我认为)。
问题: 在 read/write 过程中,Arduino 似乎接收到了一些噪音。为了证明这一点,我 运行 在传感器静止时进行了两次单独的数据采集。下面提供了快照。 7 年前,我在研究生院使用过类似的系统,使用的是 National Instruments DAC 和 LabView。那时我确实遇到了一些噪音,但这类似于约 60 Hz 的电噪音。这个比较奇特,不知道怎么处理。
结束语:有人可以帮我理解我看到的是什么噪音吗?也许知道这叫做什么会帮助我详细研究它并尝试解决它。任何 pointers/references 也会有所帮助。
未来范围:我相信稳定的静止信号作为第一步将极大地帮助减轻电压偏移(频率频谱中的直流分量),即使一个简单的平均值。另外,我需要学习如何提高uno的采样率。
使用的程序:
Arduino 代码从加速度计read/write
#define xPin A0
#define yPin A1
#define zPin A2
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop()
{
// put your main code here, to run repeatedly:
float xVal = analogRead(xPin);
float yVal = analogRead(yPin);
float zVal = analogRead(zPin);
long time = micros(); //current time
delay(1);
//Serial.print("x=");
Serial.print(time);
Serial.print("\t");
Serial.print(xVal);
Serial.print("\t");
Serial.print(yVal);
Serial.print("\t");
Serial.println(zVal);
delay(1);
}
Python 从 Arduino 读取并构建绘图的代码
#Thanks for the tutorial, Curio Res
#https://www.youtube.com/watch?v=fIlklRIuXoY
from serial.tools import list_ports
import serial
import time
import csv
#find the port corresponding to the Arduino
ports = list_ports.comports()
for port in ports: print(port)
#setup the file for saving voltage data from the accel/Arduino
f=open("data.csv","w",newline='')
f.truncate()
serialCom = serial.Serial('COM9',115200) #ENSURE the correct COM#
#Reset the arduino
serialCom.setDTR(False)
time.sleep(1)
serialCom.flushInput()
serialCom.setDTR(True)
#read from the Arduino
kmax=2000 #number of data points to record
#kmax* sampling rate in millisec delay = total time of data recorded
for k in range(kmax):
try:
#read a line of data
s_bytes = serialCom.readline()
#Decode binary
decoded_bytes = s_bytes.decode("utf-8").strip('\r\n')
#print(decoded_bytes)
#parse lines
if k==0:
values = [x for x in decoded_bytes.split(",")]
else:
values = [float(x) for x in decoded_bytes.split()]
print(values)
writer = csv.writer(f,delimiter=",")
writer.writerow(values)
except:
print("ERROR. Line was not recorded.")
f.close() #close csv file
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#import data using padas
data = pd.read_csv("data.csv",skiprows=1)
data.columns = ["time", "accel-x", "accel-y", "accel-z"] #using three channels
# data.columns = ["time", "accel-x"] #using one channel
# print(data)
#retrieve data columns
D=data.to_numpy();
time=(D[:,0])/1000000 #Arduino prints time in micro-second
x_accel=D[:,1]
y_accel=D[:,2]
z_accel=D[:,3]
signal=(x_accel**2)**0.5 #sum y and z for rms in the future
# first method of removing dc component.
i=1
dc_component=[]
for i in range(1,10):
dc_component.append(signal[i])
signal=x_accel-np.average(dc_component)
#setup doesn't provide data with uniform time-interval
#create an array of all successive time steps to see the spread later
i=1
delta_t=[]
#find the average time step in the array 'time'
for i in range(1,len(time)):
delta_t.append(time[i]-time[i-1])
dt=np.average(delta_t) #average time step
fs=1/dt #sampling frequency
N=len(time) #number of samples
f_step=fs/N #req interval
freq=np.linspace(0,(N-1)*f_step,N) #construct the frequency array
# time=np.linspace(0,(N-1)*dt,N) #Test time array
# y=1*np.sin(2*np.pi*1*time) #Test sine signal
x=np.fft.fft(signal) #perform a fast fourier transform
x_mag = np.abs(x)/N #obtain the magnitude of the transform
freq_plot=freq[0:int(N/2+1)]
x_mag_plot=2*x_mag[0:int(N/2+1)] #enter, Nyquist
x_mag_plot[0]=x_mag_plot[0]/2 #DC component does not need to be multiplied by 2
# plot
fig,[ax1,ax2] = plt.subplots(figsize=(7.5,5),nrows=2,ncols=1,constrained_layout=True)
ax1.plot(time,signal)
ax1.set_title('Time History')
ax1.set_xlabel('time(s)')
ax1.set_ylabel('Voltage(V)')
# plt.xlim([min(time),max(time)])
ax2.plot(freq_plot,x_mag_plot)
ax2.set_title('Frequency Spectrum')
ax2.set_xlabel('Frequency(Hz)')
ax2.set_ylabel('Amplitude')
plt.show()
这是尖峰噪声。 您应该使用中值滤波器来清理信号。它是一个数字非线性滤波器,您可以在您的软件中实现它。
请注意:我不知道您使用的是哪个采样频率,但采样频率越高,收集到的噪声就越多。因此,将采样频率限制为 2 x 信号带宽(香农定理)