arduino fft 和 matlab ifft
arduino fft and matlab ifft
我们目前与 Arduino 合作。
我正在使用"open music labs FFT library"
的fft库
我的问题有两点。
Arduino 代码问题
Matlab 中的逆 fft(使用 Arduino 的 FFT 结果)
以下代码使用 Arduino FFT 库进行 FFT(快速傅里叶变换)
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
//#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
}
fft_window(); // window the data for better frequency response
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
//fft_mag_log(); // take the output of the fft
sei();
Serial.print("start");
for (byte i = 0 ; i < FFT_N ; i+=2) {
if (! ((i>=20 && i<=40) || (i>=FFT_N-40 && i<=FFT_N-20)))
{
fft_input[i] = 0;
fft_input[i+1] = 0;
}
Serial.println(fft_input[i]); // send out the data
}
}
}
matlab串口通信代码
clear all
clc
arduino=serial('COM22','BaudRate',115200 );
fopen(arduino);
data = fread(arduino, 256);
ifft(data , 'symmetric');
fclose(arduino);
delete(instrfindall);
使用此代码进行实验。但是没有恢复。
在Arduino上执行fft_run ()
,我想在matlab中进行逆fft
有很多问题。
想以某种方式请教一下。
更新
我已根据 进行了更改。但有一个问题。
-arduino代码-
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
//#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h> // include the library
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
}
fft_window(); // window the data for better frequency response
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
// fft_mag_log(); // take the output of the fft
sei();
Serial.println("start");
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
}
}
-matlab端-
clear all
clc
arduino=serial('COM22','BaudRate',115200 );
fopen(arduino);
header = fread(arduino, 5); % skip "start" header
data = fread(arduino, 512); % read actual data
% now rearrange the data
rearranged = data(1:2:end) + 1i * data(2:2:end);
recoverd = ifft(rearranged, 'symmetric');
fclose(arduino);
delete(instrfindall);
我的问题是:它删除了过滤器部分。
Arduino 将数据发送到 MATLAB。来自 Arduino 的 512 数据。 (FFT_N-实数256,虚数256。)
不是确切的恢复。在 matlab 中执行 ifft,而不是原始数据。
数据格式有问题。
这种形式的数据好像是通信有问题(arduino转matlab)
data = fread(arduino, 512); % read actual data.
但我猜。具体原因没找到。
更新
感谢您的回复。
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
已发现不需要此代码。
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
我的困难是,
当您执行此代码时,OUTPUT 的部分是 256 REAL 和 256 IMAGINARY。
但是,
header = fread(arduino, 5); % skip "start" header
data = fread(arduino, 1024); % read actual data sent in binary form
% now rearrange the data
rearranged = (data(1:4:end) + 256*data(2:4:end)) + 1i *(data(3:4:end) + 256*data(4:4:end));
recovered = ifft(rearranged, 'symmetric');
"SIZE * PRECISION must be less than or equal to InputBufferSize.."
缓冲区大小问题...
所以再试一次。
我不得不按照你说的修改代码。
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
//#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h> // include the library
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
}
fft_window(); // window the data for better frequency respons
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
// fft_mag_log(); // take the output of the fft
sei();
Serial.println("start"); // header send
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
}
}
你的回答让我很忙。使活跃。好答案。
我假设额外的频谱转换是有意的,而不是您认为有问题的地方。例如,您不应该期望取回 bins 20-40 中的频谱值,因为您明确地将它们归零。另外,代码
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
是的一个技巧。由于您从时间样本开始,我假设您只需要正向变换(因此不需要那部分代码)。
现在,与 Arduino's FFT example 相比,有一些差异可能暗示了正在发生的事情。第一个显着差异是示例发送的是频谱幅度的下半部分(128 个值),不足以重建原始信号。在您的情况下,您正确地注释掉了 fft_mag_log
,它应该允许您发送频谱的复数值。但是,当您遍历 fft bin 时,您只会发送每个第二个值(因此会丢失所有虚部)。
另一件需要注意的事情是数据的打包。更具体地说,您正在发送一个数据头("start" 字符串),您必须在 Matlab 的接收端读取它,否则它只会混入您的实际数据中。
二进制传输
您正在使用 Serial.println
which sends your number in ASCII form, whereas you read them back with Matlab's fread
which reads them assuming they are in binary form. For consitency you should send your data in binary form with Serial.write
:
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
然后,由于您将 256 个复值作为交错的 real/imaginary 部分发送(总共 512 个值),您将需要读取这 512 个值(通常每个值 2 个字节,以小端顺序排列)并在 Matlab 端重新排列数据:
header = fread(arduino, 5); % skip "start" header
data = fread(arduino, 1024); % read actual data sent in binary form
% now rearrange the data
rearranged = (data(1:4:end) + 256*data(2:4:end)) + 1i *(data(3:4:end) + 256*data(4:4:end));
recovered = ifft(rearranged, 'symmetric');
ASCII 传输
或者您可以使用 Serial.println
发送数据(即以纯 ASCII 格式):
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.println(fft_input[i]); // send out the real part
Serial.println(fft_input[i+1]); // send out the imaginary part
}
然后用 fscanf
:
在 matlab 中以 ASCII 格式读回
fscanf(arduino, "start"); % skip "start" header
data = fscanf(arduino, "%d"); % read actual data sent in plain ASCII form
% now rearrange the data
rearranged = data(1:2:end) + 1i * data(2:2:end);
recovered = ifft(rearranged, 'symmetric');
我们目前与 Arduino 合作。
我正在使用"open music labs FFT library"
的fft库我的问题有两点。
Arduino 代码问题
Matlab 中的逆 fft(使用 Arduino 的 FFT 结果)
以下代码使用 Arduino FFT 库进行 FFT(快速傅里叶变换)
/* fft_adc_serial.pde guest openmusiclabs.com 7.7.14 example sketch for testing the fft library. it takes in data on ADC0 (Analog0) and processes them with the fft. the data is sent out over the serial port at 115.2kb. */ //#define LOG_OUT 1 // use the log output function #define FFT_N 256 // set to 256 point fft void setup() { Serial.begin(115200); // use the serial port TIMSK0 = 0; // turn off timer0 for lower jitter ADCSRA = 0xe5; // set the adc to free running mode ADMUX = 0x40; // use adc0 DIDR0 = 0x01; // turn off the digital input for adc0 } void loop() { while(1) { // reduces jitter cli(); // UDRE interrupt slows this way down on arduino1.0 for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples while(!(ADCSRA & 0x10)); // wait for adc to be ready ADCSRA = 0xf5; // restart adc byte m = ADCL; // fetch adc data byte j = ADCH; int k = (j << 8) | m; // form into an int k -= 0x0200; // form into a signed int k <<= 6; // form into a 16b signed int fft_input[i] = k; // put real data into even bins fft_input[i+1] = 0; // set odd bins to 0 } fft_window(); // window the data for better frequency response for (int i = 0 ; i < 512 ; i += 2) { fft_input[i] = (fft_input[i] >> 8); fft_input[i+1] = -(fft_input[i+1] >> 8); } fft_reorder(); // reorder the data before doing the fft fft_run(); // process the data in the fft //fft_mag_log(); // take the output of the fft sei(); Serial.print("start"); for (byte i = 0 ; i < FFT_N ; i+=2) { if (! ((i>=20 && i<=40) || (i>=FFT_N-40 && i<=FFT_N-20))) { fft_input[i] = 0; fft_input[i+1] = 0; } Serial.println(fft_input[i]); // send out the data } } }
matlab串口通信代码
clear all
clc
arduino=serial('COM22','BaudRate',115200 );
fopen(arduino);
data = fread(arduino, 256);
ifft(data , 'symmetric');
fclose(arduino);
delete(instrfindall);
使用此代码进行实验。但是没有恢复。
在Arduino上执行fft_run ()
,我想在matlab中进行逆fft
有很多问题。
想以某种方式请教一下。
更新
我已根据
-arduino代码-
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
//#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h> // include the library
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
}
fft_window(); // window the data for better frequency response
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
// fft_mag_log(); // take the output of the fft
sei();
Serial.println("start");
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
}
}
-matlab端-
clear all
clc
arduino=serial('COM22','BaudRate',115200 );
fopen(arduino);
header = fread(arduino, 5); % skip "start" header
data = fread(arduino, 512); % read actual data
% now rearrange the data
rearranged = data(1:2:end) + 1i * data(2:2:end);
recoverd = ifft(rearranged, 'symmetric');
fclose(arduino);
delete(instrfindall);
我的问题是:它删除了过滤器部分。
Arduino 将数据发送到 MATLAB。来自 Arduino 的 512 数据。 (FFT_N-实数256,虚数256。)
不是确切的恢复。在 matlab 中执行 ifft,而不是原始数据。
数据格式有问题。
这种形式的数据好像是通信有问题(arduino转matlab)
data = fread(arduino, 512); % read actual data.
但我猜。具体原因没找到。
更新
感谢您的回复。
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
已发现不需要此代码。
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
我的困难是, 当您执行此代码时,OUTPUT 的部分是 256 REAL 和 256 IMAGINARY。
但是,
header = fread(arduino, 5); % skip "start" header
data = fread(arduino, 1024); % read actual data sent in binary form
% now rearrange the data
rearranged = (data(1:4:end) + 256*data(2:4:end)) + 1i *(data(3:4:end) + 256*data(4:4:end));
recovered = ifft(rearranged, 'symmetric');
"SIZE * PRECISION must be less than or equal to InputBufferSize.."
缓冲区大小问题...
所以再试一次。 我不得不按照你说的修改代码。
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
//#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h> // include the library
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input[i] = k; // put real data into even bins
fft_input[i+1] = 0; // set odd bins to 0
}
fft_window(); // window the data for better frequency respons
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
// fft_mag_log(); // take the output of the fft
sei();
Serial.println("start"); // header send
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
}
}
你的回答让我很忙。使活跃。好答案。
我假设额外的频谱转换是有意的,而不是您认为有问题的地方。例如,您不应该期望取回 bins 20-40 中的频谱值,因为您明确地将它们归零。另外,代码
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
是
现在,与 Arduino's FFT example 相比,有一些差异可能暗示了正在发生的事情。第一个显着差异是示例发送的是频谱幅度的下半部分(128 个值),不足以重建原始信号。在您的情况下,您正确地注释掉了 fft_mag_log
,它应该允许您发送频谱的复数值。但是,当您遍历 fft bin 时,您只会发送每个第二个值(因此会丢失所有虚部)。
另一件需要注意的事情是数据的打包。更具体地说,您正在发送一个数据头("start" 字符串),您必须在 Matlab 的接收端读取它,否则它只会混入您的实际数据中。
二进制传输
您正在使用 Serial.println
which sends your number in ASCII form, whereas you read them back with Matlab's fread
which reads them assuming they are in binary form. For consitency you should send your data in binary form with Serial.write
:
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
然后,由于您将 256 个复值作为交错的 real/imaginary 部分发送(总共 512 个值),您将需要读取这 512 个值(通常每个值 2 个字节,以小端顺序排列)并在 Matlab 端重新排列数据:
header = fread(arduino, 5); % skip "start" header
data = fread(arduino, 1024); % read actual data sent in binary form
% now rearrange the data
rearranged = (data(1:4:end) + 256*data(2:4:end)) + 1i *(data(3:4:end) + 256*data(4:4:end));
recovered = ifft(rearranged, 'symmetric');
ASCII 传输
或者您可以使用 Serial.println
发送数据(即以纯 ASCII 格式):
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.println(fft_input[i]); // send out the real part
Serial.println(fft_input[i+1]); // send out the imaginary part
}
然后用 fscanf
:
fscanf(arduino, "start"); % skip "start" header
data = fscanf(arduino, "%d"); % read actual data sent in plain ASCII form
% now rearrange the data
rearranged = data(1:2:end) + 1i * data(2:2:end);
recovered = ifft(rearranged, 'symmetric');