- 2025-01-01
-
回复了主题帖:
【2024 DigiKey 创意大赛】+基于Teensy4.1环境温湿度和气压监测
底板有开源吗
- 2024-12-31
-
加入了学习《基于 Arduino?Nano RP2040 Connect?开发板的机器学习系列示例应用》,观看 基于 ArduinoNano RP2040 Connect开发板的机器学习系列示例应用
-
回复了主题帖:
【Follow me第二季第4期】基于 Edge Impulse 的语音识别
干得好
-
回复了主题帖:
【得捷电子Follow Me第二季第4期】Nano RP2040 Connect 的机器学习实...
你真棒
-
回复了主题帖:
【Follow me第二季第4期】Arduino Nano RP2040 Connect之GPIO与PWM控制
酱油
-
发表了主题帖:
【Follow me第二季第4期】Arduino connect nano 物联网综合应用
本帖最后由 L物恩纶 于 2024-12-31 21:33 编辑
【Follow me第二季第4期】Arduino connect nano 物联网综合应用
本项目基于Arduino connect nano的项目任务,涉及音频处理、传感器数据展示及机器学习应用等领域。包括利用PDM麦克风采集音频数据,计算RMS值控制LED亮灭。通过回调函数采集数据,主循环计算RMS并平滑处理。移动平均技术能减少噪声、提升稳定性,依据平滑后的RMS值分级控制LED。 利用板载的LSM6DS3传感器采集数据,在OLED屏实时显示加速度和角速度,还以柱状图展示加速度大小。PDM麦克风采集音频数据,经格式转换、进行FFT变换和幅值计算,最后在OLED屏以柱状图实时显示频谱。基于STMicroelectronics扩展板的LSM6DSOX传感器,初始化配置后,加载振动监测程序到MLC,实时监测并将振动状态分类。
任务一、点灯+麦克风测试
任务1使用 PDM(Pulse Density Modulation)麦克风 采集音频数据,并通过计算音频信号的 RMS(均方根)值 来控制板载 LED 的亮灭。实时采集音频信号,计算其 RMS 值,并对 RMS 值进行平滑处理,以减少噪声对 LED 控制的影响。
1. 音频采集:
当 PDM 麦克风有新的音频数据时,回调函数 onPDMdata 会被触发。该函数从 PDM 麦克风读取数据到缓冲区 sampleBuffer,并更新已读取的样本数量 samplesRead。
2. 音频处理:
在主循环中,程序检查是否有新的音频数据。如果有,调用 calculateRMS 函数计算音频信号的 RMS 值。RMS 值反映了音频信号的强度,通过计算样本的平方和的平均值,再取平方根得到。为了减少噪声的影响,调用 calculateMovingAverage 函数对 RMS 值进行平滑处理。该函数使用移动平均算法,对最近的若干个 RMS 值进行平均,返回平滑后的 RMS 值。平滑处理的核心原理是通过对数据进行平均或加权平均,减少噪声和瞬时波动的影响,从而得到更加稳定和可靠的结果。
(1)移动平均的基本原理
移动平均是一种常用的平滑技术,它通过对最近若干个数据点进行平均,来减少噪声和瞬时波动的影响。移动平均的基本思想是:
- 维护一个固定大小的窗口(即缓冲区),用于存储最近的数据点。
- 每次有新的数据点时,将其加入窗口,并移除最旧的数据点。
- 计算窗口中所有数据点的平均值,作为当前平滑后的值。
(2)平滑处理的效果
- 减少噪声:通过移动平均,瞬时噪声对 RMS 值的影响被显著减小,因为噪声通常表现为短时波动,而移动平均会将其与多个数据点进行平均,从而平滑掉这些波动。
- 提高稳定性:平滑后的 RMS 值更加稳定,能够更好地反映音频信号的整体强度,减少因瞬时噪声导致的 LED 误触发。
- 响应速度与平滑效果的权衡:窗口大小决定了平滑效果和响应速度的平衡。窗口越大,平滑效果越好,但响应速度会变慢;窗口越小,响应速度越快,但平滑效果会减弱。
3. LED 控制:
根据平滑后的 RMS 值,调用 controlLEDs 函数控制 LED 的亮灭状态。RMS 值越大,表示音频信号越强,LED 的亮灭状态会根据设定的阈值进行分级控制。例如,RMS 值较小时点亮红色 LED,中等时点亮绿色 LED,较大时点亮蓝色 LED,极大时点亮所有 LED。
// 初始化 RMS 缓冲区
void initRMSBuffer()
{
for (int i = 0; i < windowSize; i++)
{
rmsBuffer[i] = 0.0;
}
}
// 计算移动平均
float calculateMovingAverage(float newRMS)
{
rmsBuffer[rmsIndex] = newRMS; // 将新 RMS 值存入缓冲区
rmsIndex = (rmsIndex + 1) % windowSize; // 更新索引
float sum = 0.0;
for (int i = 0; i < windowSize; i++)
{
sum += rmsBuffer[i]; // 计算缓冲区中所有 RMS 值的总和
}
return sum / windowSize; // 返回移动平均值
}
void onPDMdata()
{
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer, bytesAvailable);
samplesRead = bytesAvailable / 2;
}
float calculateRMS(short *buffer, int length)
{
long sum = 0;
for (int i = 0; i < length; i++)
{
sum += (long)buffer[i] * buffer[i];
}
float mean = (float)sum / length;
return sqrt(mean);
}
void loop()
{
if (samplesRead)
{
float rms = calculateRMS(sampleBuffer, samplesRead);
float smoothedRMS = calculateMovingAverage(rms); // 计算移动平均
controlLEDs(smoothedRMS); // 使用平滑后的 RMS 值控制 LED
Serial.println(smoothedRMS);
samplesRead = 0;
}
static unsigned long lastTime = 0;
if (millis() - lastTime >= 1000)
{
lastTime = millis();
Serial.println("Hello DigiKey & EEWorld!");
}
}
任务二、加速度传感器数据展示
这个项目是一个基于 Arduino 平台的 IMU(惯性测量单元) 数据采集与可视化系统。项目使用 LSM6DS3 传感器(包含加速度计和陀螺仪)来采集设备的加速度和角速度数据,并通过 OLED 显示屏 实时显示这些数据。
将采集到的加速度和角速度数据通过 OLED 显示屏实时显示,并以柱状图的形式直观展示加速度的大小。
- 柱状图绘制:通过 drawBarGraph 函数将加速度数据映射到 OLED 屏幕的高度范围,并以柱状图的形式显示。柱状图的高度与加速度的大小成正比,直观反映了设备在各个方向上的加速度变化。
void loop()
{
// 获取加速度数据
float accelX = 0.0; // 读取 X 轴加速度
float accelY = 0.0;
float accelZ = 0.0;
if (IMU.accelerationAvailable())
{
IMU.readAcceleration(accelX, accelY, accelZ);
Serial.print(accelX * CONVERT_G_TO_MS2,4);
Serial.print('\t'); Serial.print(accelY * CONVERT_G_TO_MS2,4);
Serial.print('\t'); Serial.println(accelZ * CONVERT_G_TO_MS2,4);
}
float x, y, z;
if (IMU.gyroscopeAvailable())
{
IMU.readGyroscope(x, y, z); Serial.print(x, 2); Serial.print('\t'); Serial.print(y, 2);
Serial.print('\t'); Serial.println(z, 2);
}
// 显示加速度数据
display.clearDisplay();
// 在 OLED 显示实时加速度数据
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Accel X: ");
display.println(accelX, 2);
display.print("Accel Y: ");
display.println(accelY, 2);
display.print("Accel Z: ");
display.println(accelZ, 2);
// 绘制柱状图
drawBarGraph(accelX, accelY, accelZ);
display.display();
delay(100); // 延迟100毫秒更新
}
void drawBarGraph(float x, float y, float z)
{
// 映射加速度值到 OLED 高度范围
int barHeightX = map(abs(x * 50), 0, 100, 0, SCREEN_HEIGHT); // 放大倍数调整灵敏度
int barHeightY = map(abs(y * 50), 0, 100, 0, SCREEN_HEIGHT);
int barHeightZ = map(abs(z * 50), 0, 100, 0, SCREEN_HEIGHT);
// 限制范围,避免超出屏幕
barHeightX = constrain(barHeightX, 0, SCREEN_HEIGHT);
barHeightY = constrain(barHeightY, 0, SCREEN_HEIGHT);
barHeightZ = constrain(barHeightZ, 0, SCREEN_HEIGHT);
// 绘制 X 轴柱状图
display.fillRect(10, SCREEN_HEIGHT - barHeightX, 20, barHeightX, SSD1306_WHITE);
// 绘制 Y 轴柱状图
display.fillRect(50, SCREEN_HEIGHT - barHeightY, 20, barHeightY, SSD1306_WHITE);
// 绘制 Z 轴柱状图
display.fillRect(90, SCREEN_HEIGHT - barHeightZ, 20, barHeightZ, SSD1306_WHITE);
}
任务三、声音FFT频谱分析与显示
本任务是一个基于 Arduino 平台的音频频谱分析系统,使用 PDM(Pulse Density Modulation)麦克风 采集音频数据,并通过 FFT(快速傅里叶变换) 对音频信号进行频谱分析。
(1)音频数据采集:通过 PDM 麦克风采集音频数据,并将其存储在缓冲区中。
- PDM 数据读取:在主循环中,检查 PDM 麦克风是否有新的音频数据可用。如果有,读取音频数据到缓冲区 pdmBuffer 中。
- 数据转换:将 PDM 数据转换为 FFT 输入格式,存储在 vReal 数组中,并将虚数部分 vImag 数组置零。
(2)FFT 频谱分析:对采集到的音频数据进行 FFT 变换,计算音频信号的频谱。
- 加窗处理:对音频数据进行加窗处理(使用汉明窗),以减少频谱泄漏。
- FFT 计算:对加窗后的音频数据进行 FFT 变换,计算频谱。
- 幅值计算:将 FFT 结果转换为幅值,存储在 vReal 数组中。
3. 频谱可视化:将计算得到的频谱通过 OLED 显示屏 实时显示,以柱状图的形式展示不同频率成分的幅值。
- OLED 显示:在 OLED 显示屏上绘制频谱图,将不同频率成分的幅值映射为柱状图的高度,并显示在屏幕上。
- 刷新显示:每 10 毫秒更新一次 OLED 显示屏,确保频谱图的实时性。
void loop() {
// 读取麦克风数据
int amplesRead = PDM.available();
if (amplesRead > 0) {
PDM.read(pdmBuffer, SAMPLES);
// 将 PDM 数据转换为 FFT 输入
for (int i = 0; i < SAMPLES; i++) {
vReal[i] = pdmBuffer[i] ; // 转换为浮点数
vImag[i] = 0.0; // 虚数部分置零
}
// 执行 FFT
FFT.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); // 汉明窗
FFT.compute(FFT_FORWARD); // 计算 FFT
FFT.complexToMagnitude(); // 计算幅值
// 映射到 OLED 显示
displayFFTOnOLED();
// showSignal2();
delay(10); // 控制刷新率
}
}
// 绘制频谱图
void displayFFTOnOLED() {
display.clearDisplay();
// 显示频谱
for (int i = 0; i < SAMPLES / 2; i++) { // 只显示正频部分
// 映射幅值到 OLED 高度
int barHeight = map(vReal[i], 0, 10000, 0, SCREEN_HEIGHT*3/4);
// barHeight = constrain(barHeight, 0, SCREEN_HEIGHT); // 限制高度范围
display.drawLine(i, SCREEN_HEIGHT, i, SCREEN_HEIGHT - barHeight, SSD1306_WHITE);
}
display.display();
}
void showSignal2() {
int y;
display.clearDisplay();
for (int n = 0; n < 128; n++) {
// y = vReal[n]*10;
y = map(vReal[n],-2000, 2000, 5, 60);
// display.drawPixel(n, oldy[n], BLACK);
display.drawPixel(n, y, WHITE);
oldy[n] = y;
}
display.display();
}
任务四、震动强度机器学习
本任务基于 STMicroelectronics X-NUCLEO-IKS01A3 扩展板的 LSM6DSOX 传感器的机器学习核心(MLC)应用示例。LSM6DSOX 传感器内置了一个机器学习核心(MLC),能够在不依赖外部处理器的情况下,执行简单的机器学习算法。MLC 可以用于实时监测传感器数据,并根据预定义的规则进行分类或决策。
1. 传感器初始化与配置:初始化 LSM6DSOX 传感器,并配置其加速度计和陀螺仪。
2. 机器学习核心(MLC)应用:将预定义的机器学习程序加载到 LSM6DSOX 的 MLC 中,用于振动监测。
项目中加载了一个预定义的机器学习程序(lsm6dsox_vibration_monitoring),该程序专门用于振动监测。程序通过分析加速度计和陀螺仪的数据,判断设备的振动状态。
- 程序验证:逐行加载程序,并检查是否加载成功。如果加载失败,程序将停止运行,并通过 LED 闪烁提示错误。
-通过 MLC 实时监测设备的振动状态,并将振动状态分类为“无振动”、“低振动”和“高振动”。
void loop() {
if (mems_event) {
mems_event=0;
LSM6DSOX_MLC_Status_t status;
AccGyr.Get_MLC_Status(&status);
if (status.is_mlc1) {
uint8_t mlc_out[8];
AccGyr.Get_MLC_Output(mlc_out);
printMLCStatus(mlc_out[0]);
}
}
}
void INT1Event_cb() {
mems_event = 1;
}
void printMLCStatus(uint8_t status) {
switch(status) {
case 0:
SerialPort.println("no vibration");
display.clearDisplay();
display.setCursor(10,25);
display.print("no vibration");
display.display();
break;
case 1:
SerialPort.println("low vibration");
display.clearDisplay();
display.setCursor(10,25);
display.print("low vibration");
display.display();
break;
case 2:
SerialPort.println("high vibration");
display.clearDisplay();
display.setCursor(10,25);
display.print("high vibration");
display.display();
break;
}
}
总结:
这次活动围绕Arduino connect nano展开,在音频处理、传感器应用及机器学习等方面各有探索,展现了多样化的功能与技术应用: 音频处理与控制:“点灯+麦克风测试”项目利用PDM麦克风采集音频,通过计算RMS值控制LED;实现音频采集、FFT频谱分析与可视化展示,提供音频频谱信息。借助LSM6DS3传感器采集加速度和角速度数据,并以直观的柱状图在OLED屏呈现;运用LSM6DSOX传感器的MLC进行振动监测与分类,体现传感器在数据采集和分析上的不同应用方式。 各项目结合Arduino等平台,综合运用多种技术实现特定功能,为相关领域的技术应用和开发提供了实践范例,展示硬件技术在不同场景下的可行性和创新性。