获取特定频率的持续时间
Getting duration of a particular frequency
我需要一些帮助来分析 arduino 中的音频输入。这是我的代码(主要来自现有示例):
#include <arduinoFFT.h>
#include <PDM.h>
#include <Arduino_APDS9960.h>
#define SAMPLES 256 //Must be a power of 2
#define SAMPLING_FREQUENCY 16000 //On pin communication limit is 10k. Our microphone is on board
//Buffer for storing input values
short sampleBuffer[SAMPLES];
volatile int samplesRead;
//Timer variables
long t1=0;
long t2=-1;
//Fourier arrays
double vReal[SAMPLES];
double vImag[SAMPLES];
//Call back function
void onPDMdata(void);
//Led feedback
const int ledPin = 22; //red
const int ledPin2 = 23; //green
const int ledPin3 = 24; //blue
//Creating FFT obj
arduinoFFT FFT = arduinoFFT();
void setup()
{
Serial.begin(115200);
while (!Serial)
{
; // wait for serial port to connect.
}
PDM.onReceive(onPDMdata);
PDM.setBufferSize(SAMPLES);
// PDM: single channel (mono) sampling at 16K
if (!PDM.begin(1, SAMPLING_FREQUENCY))
{
Serial.println("Failed to start PDM!");
while (1);
}
if (!APDS.begin())
{
Serial.println("Error initializing APDS9960 sensor!");
}
//Pin setup!
pinMode(ledPin, OUTPUT);
pinMode(ledPin2 , OUTPUT);
pinMode(ledPin3, OUTPUT);
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin2, HIGH);
lightOne();
}
void loop()
{
// put your main code here, to run repeatedly:
//Check if i'm close to something
if (APDS.proximityAvailable())
{
// read the proximity
// - 0 => close
// - 255 => far
// - -1 => error
int proximity = APDS.readProximity();
/*print value to the Serial Monitor
Serial.print("Proximity ");
Serial.print(proximity);
Serial.print("\n");
*/
//If something is really near i'll check for sound
//Apparently can't see black
if(proximity < 200)
{
lightThree();
//If we have something to read
if (samplesRead)
{
for (int i = 0; i < SAMPLES; i++)
{
vReal[i] = sampleBuffer[i];
vImag[i] = 0;
}
//Magic Fourier transformation!
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_BLACKMAN_HARRIS, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
//Pick peak frequency
double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
if (peak >2500 && peak < 2800 && t1==0 )
{
Serial.println(peak);
t1=millis();
//lightTwo();
//delay(250);
//lightOne();
}
if(peak < 2500 && t2<0 && t1>0)
{
t2=millis();
Serial.print("TIME SPAN ");
//long n=t2-t1;
Serial.print(t2-t1);
Serial.print("\n");
t1=0;
t2=-1;
}
//Reset sample counts.
samplesRead = 0;
}
}
else
{
lightOne();
}
}
}
//Call back function, invoked when data is available to be read.
void onPDMdata()
{
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer, bytesAvailable);
samplesRead = bytesAvailable / 2;
}
//Led functions to get feedback
void lightOne()
{
digitalWrite(ledPin, LOW);
digitalWrite(ledPin2, HIGH);
digitalWrite(ledPin3, HIGH);
}
void lightTwo()
{
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, HIGH);
}
void lightThree()
{
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin2, HIGH);
digitalWrite(ledPin3, LOW);
}
所以基本上这个小脚本使用 arduino 来捕获和转换音频检查我是否可以感知特定频率 (2550-2800)。
频率识别工作正常,但我也想知道这种频率峰值持续多长时间。
有人可以解决我的问题吗?我对傅里叶变换有非常基本的了解(我知道我们应该如何使用它以及为什么要使用它),所以即使您不能为我提供解决方案,我也很高兴有一些文档可以帮助我安排解决方案。
短期傅立叶变换部分地从时域转换到频域 - 您的时间分辨率从 16000 下降到 16000/256,但您仍然知道哪些帧有峰值,哪些帧没有。
我不完全确定你的 SAMPLES
和 samplesRead
- 你的 Arduino 有没有可能有 samplesRead>0 但
否则,时机就很简单了。您每毫秒获得 16 个样本,因此您传递给 FFT 的每组 SAMPLES 代表 SAMPLES/16 毫秒。 FFT 以时间分辨率换取频率分辨率,因此您只能测量具有 16 毫秒粒度的峰值长度。您只需 计算 具有峰值的 FFT 帧数即可。
其他有用的提示:您可能想检查发现的主峰是否确实比其他值高得多。 10 或 20% 只是正常变化,您可能想要一个 10 倍平均值的峰值。
我需要一些帮助来分析 arduino 中的音频输入。这是我的代码(主要来自现有示例):
#include <arduinoFFT.h>
#include <PDM.h>
#include <Arduino_APDS9960.h>
#define SAMPLES 256 //Must be a power of 2
#define SAMPLING_FREQUENCY 16000 //On pin communication limit is 10k. Our microphone is on board
//Buffer for storing input values
short sampleBuffer[SAMPLES];
volatile int samplesRead;
//Timer variables
long t1=0;
long t2=-1;
//Fourier arrays
double vReal[SAMPLES];
double vImag[SAMPLES];
//Call back function
void onPDMdata(void);
//Led feedback
const int ledPin = 22; //red
const int ledPin2 = 23; //green
const int ledPin3 = 24; //blue
//Creating FFT obj
arduinoFFT FFT = arduinoFFT();
void setup()
{
Serial.begin(115200);
while (!Serial)
{
; // wait for serial port to connect.
}
PDM.onReceive(onPDMdata);
PDM.setBufferSize(SAMPLES);
// PDM: single channel (mono) sampling at 16K
if (!PDM.begin(1, SAMPLING_FREQUENCY))
{
Serial.println("Failed to start PDM!");
while (1);
}
if (!APDS.begin())
{
Serial.println("Error initializing APDS9960 sensor!");
}
//Pin setup!
pinMode(ledPin, OUTPUT);
pinMode(ledPin2 , OUTPUT);
pinMode(ledPin3, OUTPUT);
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin2, HIGH);
lightOne();
}
void loop()
{
// put your main code here, to run repeatedly:
//Check if i'm close to something
if (APDS.proximityAvailable())
{
// read the proximity
// - 0 => close
// - 255 => far
// - -1 => error
int proximity = APDS.readProximity();
/*print value to the Serial Monitor
Serial.print("Proximity ");
Serial.print(proximity);
Serial.print("\n");
*/
//If something is really near i'll check for sound
//Apparently can't see black
if(proximity < 200)
{
lightThree();
//If we have something to read
if (samplesRead)
{
for (int i = 0; i < SAMPLES; i++)
{
vReal[i] = sampleBuffer[i];
vImag[i] = 0;
}
//Magic Fourier transformation!
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_BLACKMAN_HARRIS, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
//Pick peak frequency
double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
if (peak >2500 && peak < 2800 && t1==0 )
{
Serial.println(peak);
t1=millis();
//lightTwo();
//delay(250);
//lightOne();
}
if(peak < 2500 && t2<0 && t1>0)
{
t2=millis();
Serial.print("TIME SPAN ");
//long n=t2-t1;
Serial.print(t2-t1);
Serial.print("\n");
t1=0;
t2=-1;
}
//Reset sample counts.
samplesRead = 0;
}
}
else
{
lightOne();
}
}
}
//Call back function, invoked when data is available to be read.
void onPDMdata()
{
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer, bytesAvailable);
samplesRead = bytesAvailable / 2;
}
//Led functions to get feedback
void lightOne()
{
digitalWrite(ledPin, LOW);
digitalWrite(ledPin2, HIGH);
digitalWrite(ledPin3, HIGH);
}
void lightTwo()
{
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, HIGH);
}
void lightThree()
{
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin2, HIGH);
digitalWrite(ledPin3, LOW);
}
所以基本上这个小脚本使用 arduino 来捕获和转换音频检查我是否可以感知特定频率 (2550-2800)。 频率识别工作正常,但我也想知道这种频率峰值持续多长时间。 有人可以解决我的问题吗?我对傅里叶变换有非常基本的了解(我知道我们应该如何使用它以及为什么要使用它),所以即使您不能为我提供解决方案,我也很高兴有一些文档可以帮助我安排解决方案。
短期傅立叶变换部分地从时域转换到频域 - 您的时间分辨率从 16000 下降到 16000/256,但您仍然知道哪些帧有峰值,哪些帧没有。
我不完全确定你的 否则,时机就很简单了。您每毫秒获得 16 个样本,因此您传递给 FFT 的每组 SAMPLES 代表 SAMPLES/16 毫秒。 FFT 以时间分辨率换取频率分辨率,因此您只能测量具有 16 毫秒粒度的峰值长度。您只需 计算 具有峰值的 FFT 帧数即可。 其他有用的提示:您可能想检查发现的主峰是否确实比其他值高得多。 10 或 20% 只是正常变化,您可能想要一个 10 倍平均值的峰值。SAMPLES
和 samplesRead
- 你的 Arduino 有没有可能有 samplesRead>0 但