Weird output with FFT + doesn't completely work

Hi, I’m trying to record music as data from my guitar using FFT.

What I’ve done is :

  • I use the schematic provided on this page : https://www.arduino.cc/en/tutorial/knock. I replace the piezzo by a jack cable plugged into a female jack.
  • I use the code below to record each byte of data. It’s pure copy / paste of two different codes I found :-*
#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 - delay() and millis() killed
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc03
  DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
  Serial.write("begin");
  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
    }
    // window data, then reorder, then run, then take output
    fft_window(); // window the data for better frequency response
    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(); // turn interrupts back on
    Serial.write(255); // send a start byte
    for (int i=0; i<FFT_N/2; i++) {
      Serial.print(i);
      Serial.print(" ");
      Serial.print(fft_log_out[i]);
    }
    Serial.println("");
  }
}

I encounter two issues :

  • First one : the results that I get when nothing is recorded are non-sence but still identical : ÿ0 2241 2082 743 564 445 436 377 378 249 3010 3011 3012 3013 3014 3015 3516 817 2418 2419 2420 2421 2722 2423 3024 2425 2426 3027 2728 2729 3030 2731 3032 033 834 1935 1936 837 838 2439 2440 041 1942 1943 2744 845 1946 1947 2748 049 2450 2451 1952 853 054 2455 1956 1957 1958 1959 1960 061 1962 1963 1964 065 866 067 068 869 870 871 072 873 074 075 076 877 078 079 1980 081 1982 883 1984 085 086 887 088 889 890 091 1992 2493 894 895 096 897 098 099 0100 0101 0102 0103 0104 0105 8106 8107 8108 0109 0110 0111 19112 8113 0114 0115 8116 0117 8118 8119 8120 8121 8122 8123 8124 19125 8126 8127 0

  • Second one : if I plug the jack on my guitar and then play something, the results don’t change (= no signal received). But if I tap on the jack, I well receive something.

Any idea ?
(sorry if it’s not clear, don’t hesitate to ask for more details…)

It is working correctly. It was intended to send the data from the FFT to a PC which would then process it further and display results.

I use the code below to record each byte of data

No, it is reading 10-bit ADC values and storing them in the fft_input array. Once the array is full, it does an FFT.

   Serial.write(255); // send a start byte
    for (int i=0; i<FFT_N/2; i++) {
      Serial.print(i);
      Serial.print(" ");
      Serial.print(fft_log_out[i]);
    }

The “start byte” is why the first character is ÿ. Everything else is the decimal representation of the contents of each bin number.

With a reasonable set of input values, it is very unlikely that you would get log_bin values in the thousands. My guess is that you haven’t connected the audio input correctly.
Post a circuit diagram of how you connected the guitar audio to the ADC pin.

Pete

Run the [u]Analog Read Serial Example[/u] (with the guitar instead of the pot) to see what kind of "raw" readings you're getting. The direct signal from a guitar is probably a little on the weak side, depending the guitar's volume control the sensitivity of your pickup and on how hard you strum/pluck.

The ADC readings will "look random", but the peaks (highest readings) should tell you something useful. (Half the readings should be zero, since with the current setup you can't read the negative half of the signal.)

I don't know how much signal you need to get "useful" FFT and I don't know how much accuracy/resolution you need for your application, but the ADC range is 0-1023 and I'd guess you'll need to see peaks readings of at least 100-200.

What I've done is :
I use the schematic provided on this page : https://www.arduino.cc/en/tutorial/knock. I replace the piezzo by a jack cable plugged into a female jack.

That's not right, but it's probably not the only problem...

The Arduino is going to clip-off the negative-half of the AC audio signal resulting in distortion and a distorted FFT result. The electrical signal won't actually clip until you get somewhere around -0.5V so the guitar may sound OK, but the Arduino's ADC can't read negative at all, and it will simply read zero for any negative voltages.

The Arduino can actually be damaged by negative voltages, but a piezo or guitar pickup doesn't put-out enough current to hurt it.

In order to read the positive & negative halves of the signal you need to [u]bias[/u] the Arduino's input. With a guitar, you'll get better results with higher impedance, so change the resistors to around 1M. You can leave-out the 47pF capacitor, and with higher impedance the 10uF cap can optionally be a proportionally lower value.

With the 2.5V bias, silence should read about 512 (the raw ADC reading, not the FFT) and the louder the sound, the more the numbers will deviate above & below that.

The bias can be subtracted-out in software, or since DC is zero-Hz and it appears in the lowest FFT bin, you can ignore it.

But if I tap on the jack, I well receive something.

Do you mean when you touch the signal input? Like when you touch the input of your guitar amp and get a buzz sound?

Tapping it without touching the signal wire shouldn't do anything.

Hi,

First, thanks for your answers.

@el_supremo : here is a photo of what I've done. Let's assume in a first time that it's not correct before passing to DVDdoug solution, which seems to be far more complete but also far more complex :slight_smile:

What range of voltages does the guitar produce?

Usually when connecting an audio signal to an Arduino ADC, you have to put the signal through a capacitor and connect that to a voltage divider which is designed to raise the signal to 2.5V. That is then fed to the ADC.

Pete

@el_supremo : here is a photo of what I’ve done.

Yeah, that looks the schematic you linked to. So, what voltage are you reading, or if you don’t have a mulitmeter what does the Analog Read Serial sketch give you (with that setup)?

I tested through Analog Read Serial sketch.
With my electro-accoustic guitar, I still get zero.
Then I tested with my electric guitar, and I get between 0 and about 38 by I play loud.

And if I touch the signal input, I also get a value (less than 10 I think)

I think I don't get how all the stuff works... Why is it different than using a piezzo glued on my guitar ?

You have to do what was told you in reply #4