【问题标题】:arduino fft and matlab ifftarduino fft 和 matlab ifft
【发布时间】:2016-01-19 16:12:29
【问题描述】:

我们目前与 Arduino 合作。

我正在使用“开放音乐实验室FFT库”的fft库

我的问题是两件事。

  1. Arduino 代码问题

  2. 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。

有很多问题。

我想以某种方式问什么。

更新

我已根据SleuthEye's answer 进行了更改。但有一个问题。

-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 to 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 必须小于或等于 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

      }
     }
    }

你的回答让我很忙。使活动。好答案。

【问题讨论】:

  • 有什么问题?什么没有恢复?您必须更具体地了解您所面临的错误。我们不是千里眼,也不是读心术。
  • @rayryeng 虽然我很想拥有读心术的能力:D
  • @GameOfThrows 你和我都是我的朋友 ;)
  • 更新版本使用Serial.println("start")而不是Serial.print("start")作为标题(其中包括更多的行尾字节,您必须相应调整)。此外,循环滤除频率仓20-40是不可恢复的操作。您将无法获得完全相同的原始时间序列。我的回答确实存在一些问题,请参阅更新。
  • 这是一个很好的答案。但是,也存在一些问题。我已经更新了我的问题。请查看

标签: matlab arduino fft ifft


【解决方案1】:

我认为额外的频谱转换是有意的,而不是您发现的问题。例如,您不应该期望取回 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);
}

obtain the inverse transform using Arduino's forward transform 的一个技巧。由于您从时间样本开始,我假设您只需要前向变换(因此不需要这部分代码)。

现在,与Arduino's FFT example 相比,有一些差异可能暗示正在发生的事情。第一个显着差异来自示例发送的内容,它是频谱幅度的下半部分(128 个值),不足以重建原始信号。在您的情况下,您正确注释掉了fft_mag_log,它应该允许您发送频谱的复杂值。但是,当您遍历 fft 箱时,您只会发送每秒一次的值(因此会丢失所有虚部)。

要注意的另一件事是数据的打包。更具体地说,您正在发送一个数据头(“开始”字符串),您必须在 Matlab 的接收端读取它,否则它只会混入您的实际数据中。

二进制传输

您正在使用 Serial.println 以 ASCII 形式发送您的号码,而您使用 Matlab 的 fread 读取它们,假设它们是二进制形式。为了一致性,您应该使用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 个复数值作为交错的实部/虚部发送(总共 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
}

并在 matlab 中使用fscanf 以 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');

【讨论】:

  • 最佳答案。但有些还有更多问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
相关资源
最近更新 更多