• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Transformata Foureira + ADC 16bit.
#1
Dzień dobry

Mam układ ADC-ads1115-16bit i mikrofon MAX9814 oraz ArduinoMEGA.
Mikrofon podłączony jest do wejścia A0 ADC a konwerter do arduino po I2c.
I Arduino poprawnie wyświetla wartości w postaci cyfrowej ale jak używam biblioteki FFT to wygląda to tak że FFT nie bierze kolejnych wartości w czasie tylko zczytuje jedną wartość i podstawia kolejno pod swoje próbki. Jak podłączam mikrofon bezpośrednio pod przetwornik arduino(10bit) to FFT bierze kolejne wartości w czasie czyli tak jak powinno i jest dobrze. Pytanie jak poprawnie przesłać wartości z ADC16bit do FFT?

To jest prawidłowe działanie FFT:

Kod:
0.000000 282.0000
0.000111 283.0000
0.000222 282.0000
0.000333 283.0000
0.000444 286.0000
0.000556 282.0000
0.000667 283.0000
0.000778 284.0000
0.000889 285.0000
0.001000 284.0000
0.001111 283.0000
0.001222 282.0000
0.001333 283.0000


To jest odczyt przy użyciu ADC16bit po I2c:

Kod:
0.000000 6438.0000
0.001000 6438.0000
0.002000 6438.0000
0.003000 6438.0000
0.004000 6438.0000
0.005000 6438.0000
0.006000 6438.0000
0.007000 6438.0000
0.008000 6438.0000
0.009000 6438.0000
0.010000 6438.0000
0.011000 6438.0000
0.012000 6438.0000


A to jest kod:

Kod:
#include "arduinoFFT.h"
#include <Wire.h>
#include <Adafruit_ADS1015.h>
Adafruit_ADS1115 ads;
int16_t adc0;

arduinoFFT FFT = arduinoFFT(); /* Create FFT object */
/*
These values can be changed in order to evaluate the functions
*/

const uint16_t samples = 64; //This value MUST ALWAYS be a power of 2
const double samplingFrequency = 1000; //Hz, must be less than 10000 due to ADC

unsigned int sampling_period_us;
unsigned long microseconds;

/*
These are the input and output vectors
Input vectors receive computed results from FFT
*/
double vReal[samples];
double vImag[samples];

#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03

void setup()
{
 sampling_period_us = round(1000000*(1.0/samplingFrequency));
 ads.begin();
 Serial.begin(115200);
 Serial.println("Ready");
}

void loop()
{
 adc0 = ads.readADC_SingleEnded(0);
 /*SAMPLING*/
 for(int i=0; i<samples; i++)
 {
     microseconds = micros();    //Overflows after around 70 minutes!

     vReal[i] = adc0;
     vImag[i] = 0;
     while(micros() < (microseconds + sampling_period_us)){
       //empty loop
     }
 }
 /* Print the results of the sampling according to time */
 Serial.println("Data:");
 PrintVector(vReal, samples, SCL_TIME);
 FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);  /* Weigh data */
 Serial.println("Weighed data:");
 PrintVector(vReal, samples, SCL_TIME);
 FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
 Serial.println("Computed Real values:");
 PrintVector(vReal, samples, SCL_INDEX);
 Serial.println("Computed Imaginary values:");
 PrintVector(vImag, samples, SCL_INDEX);
 FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */
 Serial.println("Computed magnitudes:");
 PrintVector(vReal, (samples >> 1), SCL_FREQUENCY);
 double x = FFT.MajorPeak(vReal, samples, samplingFrequency);
 Serial.println(x, 6); //Print out what frequency is the most dominant.
 while(1); /* Run Once */
 //delay(5000); /* Repeat after delay */
}

void PrintVector(double *vData, uint16_t bufferSize, uint8_t scaleType)
{
 for (uint16_t i = 0; i < bufferSize; i++)
 {
   double abscissa;
   /* Print abscissa value */
   switch (scaleType)
   {
     case SCL_INDEX:
       abscissa = (i * 1.0);
 break;
     case SCL_TIME:
       abscissa = ((i * 1.0) / samplingFrequency);
 break;
     case SCL_FREQUENCY:
       abscissa = ((i * 1.0 * samplingFrequency) / samples);
 break;
   }
   Serial.print(abscissa, 6);
   if(scaleType==SCL_FREQUENCY)
     Serial.print("Hz");
   Serial.print(" ");
   Serial.println(vData[i], 4);
 }
 Serial.println();
}
 
Odpowiedź
#2
Jak używasz MEGA to nie ma double, jest tylko float (jeśli to ma dla Ciebie znaczenie).
Coś takiego: round(1000000*(1.0/samplingFrequency)); lepiej zapisać  round(1000000.0/ samplingFrequency));
Jak chcesz mieć 64 sample odczytane co jakiś czas do adc0 musisz odczytywać wewnątrz tej pętli for, a nie przed nią.
No i zamień sobie warunek w while z micros, on tu nie ma żadnego sensu, po prostu możesz sobie zrobić delayMicroseconds. Micros() miałaby sens gdybyś ustawił sobie cykliczne uzupełnianie tablicy odczytów w pętli i po zebraniu 64 próbek wykonanie obliczeń, rozpoczęcie od nowa, a w między czasie procesor mógłby wykonywać inne zadania, np. resetować proces po wciśnięciu jakiegoś przycisku.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
Super dziękuję bardzo kaczakat za twoje cenne uwagi jutro przetestuje układ z naniesionymi poprawkami i dam znać jak to wyszło.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości