FHT whistle detection

Hi guys,

Objective:
To detect whistling.

Hardware:

  • Arduino Yun

  • Electret Microphone Amplifier - MAX4466 with Adjustable Gain
    Wiring:

  • Vcc -> 3.3v

  • Ground -> ground

  • Output -> A0
    Library:
    OpenMusicLabs FHT

Question:
I have read many, many forum threads about the FHT and the FFT, but some of them I do not understand, and many of them does not really give an answer, but just ends with OP going silent or finding a tweak that helped his individual project.

I need to be able do detect a human whistle, or at least just sounds around a high pitched frequency.

When I run the code (posted below), I get the same output every time, which of course tells me something is wrong. I have read that disabling the window function helps this problem, but I have also read that this function must be kept.

Can someone give me something to work from as I am completely lost where to begin? Right now I understand that the output is a collection of bins, each representing a frequency range, and the integer shows the amplitude of that range - is that correct?

Code:

/*
fht_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

#include <FHT.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 < FHT_N ; i++) { // 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
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei();
    Serial.println("start");
    for (int i = 0; i < FHT_N / 2; i++)
    {
      Serial.println(fht_log_out[i]);
    }
    Serial.flush();
  }
}

Output:

start
232
216
80
60
47
42
38
32
33
19
27
27
19
19
19
19
8
19
19
27
16
19
19
19
19
19
19
16
19
19
19
19
0
8
8
16
16
0
19
19
19
19
19
19
16
19
19
16
0
16
19
8
19
8
8
19
19
0
19
19
0
19
8
0
8
0
8
0
0
0
0
0
0
0
8
8
0
8
0
0
0
0
19
0
0
0
0
0
0
0
0
19
16
0
8
8
0
0
0
0
0
16
0
0
0
0
0
0
16
8
0
0
8
0
0
0
0
8
8
0
0
0
8
0
8
0
19
0

I need to be able do detect a human whistle, or at least just sounds around a high pitched frequency.

That is surprisingly difficult to do. The FFT or FHT just tell you what RANGES of frequencies at what amplitudes are present in a small audio sample.

To detect a particular sound, you must first clearly define it, and the term "human whistle" covers an extremely large range of possible sounds. Furthermore most sounds have high frequency components.

To start, you need to spend quite a bit of time analyzing various sounds that you are likely to encounter, until you can come up with some scheme to detect the one of interest.

Okay, I see. I once thought this was going to be the easy part of the project.. :slight_smile:

Anyway, then lets just say I want to detect when there is a high frequency sound at a certain amplitude. I guess that is a start?

Define "high frequency".

SomethingClever:
When I run the code (posted below), I get the same output every time, which of course tells me something is wrong.

Before you spend too much time and energy fretting about the output of the FHT, you should probably verify that your input has meaning.

When I run your code with the sole modification that I set the analog input uniformly to zero, I get exactly the output that you posted. When I turn off the windowing function, I get an output that shows a high value in the first bin, and zeros thereafter - again, just what I'd expect. That suggests that your Arduino finds a zero every time it reads the ADC.

Try printing the contents of the array fft_input[], after the acquisition is complete, and before any further processing.

A schematic of your analog input circuit, including the microphone, would help. Can you post one?

A human whistle is remarkably like a sin wave and should be easy to detect.
Being a hardware sort of person then I would use a simple UM3763 and have done.

I would use a simple UM3763 and have done.

And where might you buy one?

Got a bag of them in my component draw. :slight_smile:

You could always use on of these:-
http://uk.farnell.com/texas-instruments/lm567cn-nopb/tone-decoder-dip-8/dp/1496187

@jremington

Good question! :slight_smile:

@tmd3

I will get back to you about the schematic. But ground is to ground, vcc is to 3.3, out is to A0. Nothing else is connected at all.

When I loop through the fht_input array every value is "-10496".

@Grumpy_Mike

The tone decoder chip you linked to, which different parts of hardware will I need to get that working as a whistle detector?

which different parts of hardware will I need to get that working as a whistle detector?

What do you mean?
You will put your microphone output into that chip and it will output a logic level when it detects the sound. Down load the data sheet and read it.

Ah okay. I have just seen another chip where I needed a bunch of other hardware.

Well, that seems to be the solution then? :slight_smile:

Edit: Does it matter if the chip is called LM567CN or LM567CN/NOPB? Because then I found it at a local dealer.

Edit2: What I meant when saying hardware was resistors, capacitors and so on. I only have a very basic understanding of electronics and circuits, and after reading the data sheet three times I am still lost.

SomethingClever:
... ground is to ground, vcc is to 3.3, out is to A0. Nothing else is connected at all.

I'll read between the lines and guess that you're using this device. Based on the documentation, that's how you hook it up.

When I loop through the fht_input array every value is "-10496".

A uniform value of -10946 for fht_input[] didn't yield the results you showed in the original post. To get that output, the input must be uniformly -32768, negative full scale for an int, corresponding to an analog input voltage of zero. Here's a bit of the output that a uniform -10946 yields:

start
206
190
56
45
38
27
19

Similar to the posted results, but lower in magnitude.

A uniform value of -10946 for fht_input[] suggests that you're getting an analog reading of 348, corresponding to an input voltage of about 1.7V - supiciously close to 1.65V, which is 3.3V/2. That's about what you should be getting from the Adafruit device, if the microphone output is zero - corresponding to VCC/2. Maybe it's quiet when you run the test, or maybe it's just kind of quiet, and the gain is dialed all the way down.

I'd suggest whistling at the microphone from a few inches away while you run the test program to print the values of fht_input. If that yields nothing, try turning the gain potentiometer to the other end, and testing again. Note that you'll want to whistle for several seconds, at least until you see output, in order to be sure that there was sound while the ADC was taking readings.

[Edit: Delete stray text]

The suffix in an IC is normally something to do with the package, it should say what in the data sheet. The NOPB is normaly when it is a lead free part ( no Pb - no lead ).
Yes you have to put resistors and capacitors round in order to define what the frequency you detect actually is.

@tmd3

Yes, that is the device I got. I should have put a link in post #1.

I have tried replicating the output from yesterday, but now I just get -1xxxx in every output the first time, and then it slowly progresses towards -32768. I have tried reassembling everything, changing the microphone (I have two similar), adjusting the gain, using 5v instead, and nothing works.

All of a sudden my computer could not recognize the Arduino, and just said it was an unknown device. I tried uploading another sketch through wifi, and when that was loaded the computer recognized the Arduino and assigned it another port. I don't know what the heck is going on.

Now whenever I upload the sketch below and run it, my computer can't recognize the Yun.

/*
fht_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

#include <FHT.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 < FHT_N ; i++) { // 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
      fht_input[i] = k; // put real data into bins
    }
    Serial.println("start");
    for (int i = 0; i < FHT_N / 2; i++)
    {
      Serial.println(fht_input[i]);
    }
    Serial.flush();
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei();
    
  }
}

@Grumpy_Mike

I see, thank you.

The problem is that I simply don't understand how to assemble everything in the right way and what the different components do. This project is a part of a small university cause, and the whistle detection part of the prototype is a really, really small part of everything which I have spend waaay too much time on, and I simply don't have the time to get into how the circuit works, as I lack a lot of knowledge about the basics.

If you can tell me what components to buy and how to assemble them, I would be very grateful!

Buy an LM567 tone detector module here. http://indo-ware.com/produk-2459-sound-frequency-sensor-module-sound-activation-lm567.html

Or follow these instructions: Tone Detector

If you want to continue with the microphone module you have, and actually learn something, here is a tutorial from Adafruit on sound detection: Overview | FFT: Fun with Fourier Transforms | Adafruit Learning System

SomethingClever:
Now whenever I upload the sketch below and run it, my computer can't recognize the Yun.

I've never as much as seen a live Yun, so I may not be able to help, but I'll hazard a guess.

The sketch disables interrupts, and then tries to print the input array while interrupts are disabled. That won't work, because Serial.print() relies on interrupts being enabled to do its work. Serial.print() merely sets up the print operation by putting the characters into a buffer, for the serial communication ISR to send. When interrupts are disabled, no characters are transmitted, and the serial buffer fills to capacity. Once it's full, any further call to Serial.print() will cause the processor to wait until there's space in the buffer for the new data. With no characters leaving the serial buffer, it will wait forever. It won't be able to do anything else.

You can fix this by moving the sei() instruction, which reenables interrupts, to the point right before your first call to Serial.print. Or, perhaps better yet, you can eliminate the cli() and sei() instructions entirely. My tests with with this FHT library don't find any change in performance with interrupts either on or off, and I suspect that the notion that they somehow interfere is a relic of wither an old IDE, or of some other implementation of the test program.

If you can tell me what components to buy and how to assemble them, I would be very grateful!

I'm not sure what I would improve. For easy design and installation, the Adafruit gizmo looks to be a very good solution. It manages most of the details of an analog audio interface for you.

I don't know what your goal is. It might be to get a whistle-identifier working, in which case you may be well-advised to pursue a hardware solution, as others have suggested. Or, it might be that the learning component of this project is what's really important you here - in that case, a hardware solution short-circuits your aims. You know what you want to accomplish. I'd recommend that you select the option that suits your needs, and carry on.

I'll note that this is a difficult project for a beginner. We've seen a lot of questions about frequency estimation using the FFT or FHT, but I can't recall anyone reporting a clear success. After you get past these initial hurdles, you may find that this project is more difficult than you imagine. A wiser man than I might advise you to whet your skills on something that's more achievable.

@jremington

Thank you - I am looking in to all options right now :slight_smile:

I really would like to learn something, but as I am learning tons of other stuff right now this has a low priority.

@jremington

I followed the instructions, and I have tried everything and adjusted everything, but the circuit doesn't work.

I hope someone can help me out. The light is turned off no matter what, and as I can understand it should be turned on until the right frequency is detected. I have checked and double checked all capacitors and resistors, and they should be right.

Attached an image, but I can't see it. Here it is: Imgur: The magic of the Internet

Assuming you are referring to this: Tone Detector

I can't tell for sure whether you have wired everything correctly or have the correct components, but the LED should be OFF unless a tone is detected. Have you wired the LED the right way around? Briefly connect pin 8 of the LM567 to ground to check -- the LED will light if it is OK.

The audio input of the LM567 must see an audio signal of at least 20 mV rms (around 60 mV peak-to-peak) for the LM567 to respond. What voltage does that microphone module output?

I thought it had to be ON unless a tone was detected due to the sentence "The output of the circuit goes low when a tone is detected".

I am sure I have the right components. Have checked and rechecked. The LED is wired the right way, yes. I will check everything again tomorrow and get back to you about the voltage.