3
votes

I know this question been asked hundred times... But I am getting frustrated with my result so I wanted to ask again. Before I dive deep into fft, I need to figure this simple task out.

I need to detect a 20 hz tone in an audiofile. I insert the 20hz tone myself like in the picture. (It can be any frequency as long as listener can't hear it so I thought I should choose a frequency around 20hz to 50 hz)

enter image description here

info about the audiofile.

afinfo 1.m4a 
File:           1.m4a
File type ID:   adts
Num Tracks:     1
----
Data format:     1 ch,  22050 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Mono
estimated duration: 8.634043 sec
audio bytes: 42416
audio packets: 219
bit rate: 33364 bits per second
packet size upper bound: 768
maximum packet size: 319
audio data file offset: 0
optimized
format list:
[ 0] format:      1 ch,  22050 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Mono
----

I followed this three tutorials and I came up with a working code that reads audio buffer and gives me fft doubles.

http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html
https://github.com/alexbw/iPhoneFFT
How do I obtain the frequencies of each value in an FFT?

I read the data as follows

// If there's more packets, read them
        inCompleteAQBuffer->mAudioDataByteSize = numBytes;
        CheckError(AudioQueueEnqueueBuffer(inAQ,
                                           inCompleteAQBuffer,
                                           (sound->packetDescs?nPackets:0),
                                           sound->packetDescs),
                   "couldn't enqueue buffer");
        sound->packetPosition += nPackets;


        int numFrequencies=2048;
        int kNumFFTWindows=10;

        SInt16 *testBuffer = (SInt16*)inCompleteAQBuffer->mAudioData; //Read data from buffer...!

        OouraFFT *myFFT = [[OouraFFT alloc] initForSignalsOfLength:numFrequencies*2 andNumWindows:kNumFFTWindows];
        for(long i=0; i<myFFT.dataLength; i++)
        {
            myFFT.inputData[i] = (double)testBuffer[i];

        }
        [myFFT calculateWelchPeriodogramWithNewSignalSegment];
        for (int i=0;i<myFFT.dataLength/2;i++) {
            NSLog(@"the spectrum data %d is  %f ",i,myFFT.spectrumData[i]);
}

and my out out log something like

Everything checks out for 4096 samples of data
Set up all values, about to init window type 2
the spectrum data 0 is  42449.823771 
the spectrum data 1 is  39561.024361 
.
.
.
.
the spectrum data 2047 is  -42859933071799162597786649755206634193030992632381393031503716729604050285238471034480950745056828418192654328314899253768124076782117157451993697900895932215179138987660717342012863875797337184571512678648234639360.000000

I know I am not calculating the magnitude yet but how can I detect that sound has 20 hz in it? Do I need to learn Goertzel algorithm?

1
From your picture it is not clear to me if you are bursting a 20Hz sine bursted at a lower frequency or a higher frequency sine bursted at 20Hz.jaket
Do a low pass filtering first. Then use autocorrelation, it is usually better than the harmonics in FFT for noisy signalsSten
If those pulses in the bottom plot are 20Hz single cycles, then you're not going to be able to easily pick them up reliably in real-time with an FFT or Goertzel's algorithm. If you're using them as hidden markers in the file, then I would low-pass filter the data and then autocorrelate or even just watch for sections of the right width above some threshold value. (Edited: autocorrelation won't pick up those single cycles well)Katie
Also I see you're working with AAC - you may want to confirm that the added tone shows up in the final file by looking at it after compression in Audacity. Audio compression works by throwing out parts of the signal that can't be heard, so it may be removing the 20Hz tone before you get a chance to process it.Katie
@Katie yes I check the audio with several programs and I make sure that low frequency is not trimmed. My initial idea was to insert 5 cycles in 20z with a great magnitude so with a simple counter when I get positive boolean for 5 times just go ahead and apply my logic, bad idea?Mord Fustang

1 Answers

1
votes

There are many ways to convey information which gets inserted into then retrieved from some preexisting wave pattern. The information going in can vary things like the amplitude (amplitude modulation) or freq (frequency modulation), etc. Do you have a strategy here ? Note that the density of information you wish to convey can be influenced by such factors as the modulating frequency (higher frequencies naturally can convey more information as it can resolve changes more times per second).

Another approach is possible if both the sender and receiver have the source audio (reference). In this case the receiver could do a diff between reference and actual received audio to resolve out the transmitted extra information. A variation on this would be to have the sender send ~~same~~ audio twice, first send the reference untouched audio followed by a modulated version of this same reference audio that way the receiver just does a diff between these two audibly ~~same~~ clips to resolve out the embedded audio.

Going back to your original question ... if the sender and receiver have an agreement ... say for some time period X the reference pure 20 Hz tone is sent followed by another period X that 20 Hz tone is modulated by your input information to either alter its amplitude or frequency ... then just repeat this pattern ... on receiving side they just do a diff between each such pair of time periods to resolve your modulated information ... for this to work the source audio cannot have any tones below some freq say 100 Hz (you remove such frequency band if needed) just to eliminate interference from source audio ... you have not mentioned what kind of data you wish to transmit ... if its voice you first would need to stretch it out in effect lowering its frequency range from the 1 kHz range down to your low 20 Hz range ... once result of diff is available on receiving side you then squeeze this curve to restore it back to normal voice range of 1kHz ... maybe more work than you have time for but this might just work ... real AM/FM radio uses modulation to send voice over mega Hz carrier frequencies so it can work