从 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 信号带宽(香农定理)