arduino fft和matlab ifft

时间:2016-01-19 16:12:29

标签: matlab arduino fft ifft

我们目前正与Arduino合作。

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

我的问题是两件事。

  1. Arduino代码问题

  2. Matlab中的逆fft(使用Arduino的FFT结果)

    以下代码使用Arduino FFT库进行FFT(快速傅立叶变换)

    @media (max-width: 600px) { - here you add the px**** and it will resize
      .YourImage/BoxClassGoesHere* {
        display: none;
      }
    }
    
  3. matlab串口通讯代码

    /*
    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
      }
     }
    }
    

    这段代码是一个实验。但它没有恢复。

    在Arduino上执行 clear all clc arduino=serial('COM22','BaudRate',115200 ); fopen(arduino); data = fread(arduino, 256); ifft(data , 'symmetric'); fclose(arduino); delete(instrfindall); ,我想在matlab中反向fft。

    有很多问题。

    我想问某些方法。

    更新

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

    -arduino代码 -

    fft_run ()

    -matlab side -

    /*
    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
        }
      }
    }
    

    我的问题是:它会删除过滤器部分。

    Arduino将数据发送到MATLAB。来自Arduino的512个数据。 (FFT_N-实数256和虚数256。)

    不是确切的恢复。在matlab中执行ifft,而不是原始数据。

    数据表格存在问题。

    这种形式的数据似乎是沟通中的问题。(arduino to 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);
    

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

    更新

    感谢您的回复。

    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);
        }
    

    我的困难是, 执行此代码时,OUTPUT的部分为256 REAL,256 IMAGINARY。

    但是,

        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
        }
    

    “SIZE * PRECISION必须小于或等于InputBufferSize ..”

    缓冲区大小问题......

    所以再试一次。 我不得不像你说的那样修改代码。

       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');
    

    你的回答让我很忙。活跃起来。好答案。

1 个答案:

答案 0 :(得分:0)

我认为额外的频谱变换是有意的,而不是你发现的问题。例如,您不应该期望在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箱上循环时,你只发送每一秒的值(因此缺少所有虚部)。

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