2016-01-19 2 views
0

В настоящее время мы работаем с Arduino.arduino fft и matlab ifft

Я использую БПФ библиотеку «открытых музыкальные лаборатории FFT библиотеки»

Мой вопрос состоит из двух вещей.

  1. Arduino код выдает

  2. обратного БПФ в Matlab (С результатами FFT от Arduino)

    следующего кода с использованием библиотеки Arduino 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); 

С помощью этого кода был проведен эксперимент. Но он не восстановился.

Выполните fft_run() на Arduino, и я хотел бы получить обратный fft в matlab.

Есть много проблем.

Я хотел бы спросить, что именно.

Update

Я сделал изменения, основанные на 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. 512 данных от Arduino. (FFT_N-real 256 и мнимой 256.)

Неточное восстановление. Выполнение ifft в matlab, а не исходные данные.

Возникла проблема с формой данных.

Эта форма данных, как представляется, проблема в общении. (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 РЕАЛ и 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 * ТОЧНОСТЬ должно быть меньше или равно 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 

     } 
    } 
    } 

Ваш ответ заставляет меня заняться. Делает активным. хороший ответ.

+4

Какие проблемы? Что не вызвало? Вы должны быть более конкретными об ошибках, с которыми вы сталкиваетесь. Мы не ясновидцы, и мы не понимаем. – rayryeng

+1

@rayryeng Хотя я бы хотел иметь умение читать: D – GameOfThrows

+0

@GameOfThrows вы и я оба мой друг;) – rayryeng

ответ

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, который должен позволить вам отправлять сложные значения спектра. Однако, когда вы зацикливаете на флеш-булавках, вы отправляете только каждое второе значение (таким образом, не хватает всех мнимых частей).

Другая вещь, которую следует отметить, - это упаковка данных. Более конкретно, вы отправляете заголовок данных (строку «start»), которые вам нужно будет прочитать на принимающей стороне Matlab, иначе он просто будет смешиваться с вашими фактическими данными.

Binary передача

Вы используете Serial.println, который посылает свой номер в виде ASCII, в то время как вы читаете их с Matlab-х fread, который читает их при условии, что они находятся в двоичной форме. Для consitency вы должны отправить данные в двоичной форме с 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 байта каждый, в маленьком порядке Endian) и реорганизовать данные на стороне от 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

в качестве альтернативы вы можете отправить йа ta с 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 
} 

и читать его обратно в виде ASCII в MATLAB с 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'); 
+0

Лучший ответ. Но у некоторых есть больше проблем. – skzlzl