简体   繁体   English

arduino fft和matlab ifft

[英]arduino fft and matlab ifft

We currently work with Arduino. 我们目前与Arduino合作。

I am using the fft library of "open music labs FFT library" 我正在使用“开放音乐实验室FFT库”的fft库

My question is two things. 我的问题是两件事。

  1. Arduino code issues Arduino代码问题

  2. Inverse fft in Matlab (With the FFT results from Arduino) Matlab中的逆fft(来自Arduino的FFT结果)

    the following code using Arduino FFT library for FFT (fast Fourier transform) 以下代码使用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 serial communication code Matlab串口通讯代码

   clear all
   clc

   arduino=serial('COM22','BaudRate',115200 );

   fopen(arduino);

   data = fread(arduino, 256);

   ifft(data , 'symmetric');

   fclose(arduino); 
   delete(instrfindall);

With this code was an experiment. 这段代码是一个实验。 But it did not recover. 但是它没有恢复。

Perform fft_run () on the Arduino, and I'd like the inverse fft in matlab. 在Arduino上执行fft_run () ,我想在matlab中使用逆fft。

There are a lot of problems. 有很多问题。

I would like to ask what to in some way. 我想问些什么。

Update 更新

I've made changes based on SleuthEye's answer . 我已经根据SleuthEye的答案进行了更改。 But there is a problem. 但有一个问题。

-arduino code- -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 side- -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);

My problem is: it deletes the filter part. 我的问题是:它删除了过滤器部分。

Arduino sends the data to MATLAB. Arduino将数据发送到MATLAB。 512 data from Arduino. 来自Arduino的512数据 (FFT_N- real 256 and imaginary 256.) (FFT_N-实数256和虚数256。)

Not an exact recovery. 没有确切的恢复。 Performing ifft in matlab, not the original data. 在matlab中执行ifft,而不是原始数据。

There is a problem with the data form. 数据表单有问题。

This form of data seems to be a problem in communication.(arduino to matlab) 这种数据形式似乎是通信中的问题。(从arduino到matlab)

data = fread(arduino, 512); % read actual data.

But my guess. 但是我的猜测。 The exact reason was not found. 找不到确切原因。

UPDATE UPDATE

Thank you for your 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);
    }

This code has been found that it is not necessary. 已经发现此代码不是必需的。

    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
    }

My difficulty is, When you do this code, the part of OUTPUT is 256 REAL and 256 IMAGINARY. 我的困难是,执行此代码时,OUTPUT的部分为256 REAL和256 IMAGINARY。

but, 但,

   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.." “ SIZE * PRECISION必须小于或等于InputBufferSize。”

Problem of the buffer size... 缓冲区大小的问题...

So try again. 因此,请重试。 I had to modify the code as you said. 我不得不按照您所说的修改代码。

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

      }
     }
    }

Your answer makes me busy. 你的回答让我很忙。 Makes active. 使活动。 good answer. 好答案。

I assume that the additional spectrum transformations are intentional and not what you find problematic. 我认为其他频谱转换是有意的,而不是您认为有问题的频谱。 For example you shouldn't be expecting to get back the spectrum values in bins 20-40 inclusive since you are explicitly zeroing them out. 例如,您不应期望取回包含20至40的bin中的频谱值,因为您已明确将它们归零。 Also, the code 另外,代码

for (int i = 0 ; i < 512 ; i += 2) {
  fft_input[i] =  (fft_input[i] >> 8);
  fft_input[i+1] = -(fft_input[i+1] >> 8);
}

is a trick to obtain the inverse transform using Arduino's forward transform . 这是使用Arduino的正向变换获得逆变换的技巧。 Since you start with time samples, I assume you want only the forward transform (and so do not need that part of the code). 由于您从时间样本开始,因此我假设您只需要正向变换(因此不需要那部分代码)。

Now, comparing with Arduino's FFT example , there are a few differences which may hint at what's going on. 现在,与Arduino的FFT示例相比 ,有一些差异可能暗示发生了什么。 The first notable difference comes with what the example is sending which is the lower half of the spectrum magnitude (128 values), and is not sufficient to reconstruct the original signal. 第一个显着差异来自示例发送的内容,即频谱幅度的下半部分(128个值),不足以重建原始信号。 In your case you correctly commented out the fft_mag_log which should allow you to send spectrum's complex values. 在您的情况下,您已正确注释掉了fft_mag_log ,它应该允许您发送频谱的复数值。 However as you loop over the fft bins, you are only sending every second value (thus missing all the imaginary parts). 但是,当您遍历fft bin时,您仅发送第二个值(因此丢失了所有虚部)。

The other thing to notice is the packaging of the data. 要注意的另一件事是数据的打包。 More specifically you are sending a data header (the "start" string) which you will have to read on Matlab's receiving end otherwise it will just get mixed in your actual data. 更具体地说,您正在发送一个数据标头(“开始”字符串),您必须在Matlab的接收端读取该数据标头,否则它将被混入您的实际数据中。

Binary transfer 二进制转移

You are using 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. 您正在使用Serial.println以ASCII形式发送您的数字,而使用Matlab的fread读回它们,并假设它们为二进制格式。 For consitency you should send your data in binary form with Serial.write : 为了方便起见,您应该使用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
}

Then, since you are sending 256 complex values as interleaved real/imaginary parts (for a total of 512 values), you would need to read those 512 values (typically 2 bytes each, in little endian order) and rearrange the data on Matlab's side: 然后,由于您要发送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 transfer ASCII传输

Alternatively you can send the data with Serial.println (ie in plain 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
}

and read it back in ASCII form in matlab with fscanf : 并使用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