繁体   English   中英

arduino fft和matlab ifft

[英]arduino fft and matlab ifft

我们目前与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的答案进行了更改。 但有一个问题。

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

但是我的猜测。 找不到确切原因。

UPDATE

感谢您的答复。

    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

      }
     }
    }

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

我认为其他频谱转换是有意的,而不是您认为有问题的频谱。 例如,您不应期望取回包含20至40的bin中的频谱值,因为您已明确将它们归零。 另外,代码

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的正向变换获得逆变换的技巧。 由于您从时间样本开始,因此我假设您只需要正向变换(因此不需要那部分代码)。

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

要注意的另一件事是数据的打包。 更具体地说,您正在发送一个数据标头(“开始”字符串),您必须在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
}

并使用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');

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM