Step 7: Optional: Algorithm Details

The Goertzel algorithm is a signal processing algorithm which is used for detecting a single frequency. It is derived from the Fourier transform.

The algorithm acts as a very narrow band pass filter. It produces a very sharp response to frequencies within the pass band, and a much lower response for frequencies outside the pass band. The minute details of the Goertzel algorithm won’t be covered here.  

The algorithm loop samples the input using the microprocessor built in A/D converter. The necessary mathematical operations are performed in the time between successive samples.
The different variables used in the algorithm are defined as follows:

Xn_sample=The latest sample from the A/D converter
Xn=The latest sample from the A/D converter multiplied by the window function.
Y0=The output value presently being computed.
Y1=The previously computed output value. (The output value from the previous iteration of the loop).
Y2=The output value from the iteration the iteration before the l previous iteration of the loop.

The figure below shows a list of the variables used in the algorithm.

Refer to the flow chart in the attached PDF to see how the Goertzel algorithm portion of the program executes on the processor. Once the algorithm has processes all the samples (the attached *.hex and *.asm files use 200 samples), the real and imaginary components of the results are calculated. The real and imaginary portions are then used to compute the magnitude. The magnitude is a measure of the target frequency is present in the sampled data. The magnitude is then compared against the threshold. If the value is greater than the threshold value, the frequency is considered to be detected, and the output is set HIGH. If the magnitude is lower than the threshold, the output is set LOW.

The sharpness of the filter response versus frequency is proportional to the number of samples taken. The response of the algorithm must be sharp enough that it responds to the target frequency but produces much lower response for frequencies outside the target. A value of 200 samples was found to produce a reasonably narrow response in experimentation.

Windowing Function

After each sample is obtained from the A/D converter, it is first multiplied by a window value before being used in the subsequent calculations. Refer to the pictures below showing the frequency response of the algorithm to see the affects of the window. The magnitude of the response is lower and the width of the response is wider when the window is used, but ripples are nearly eliminated, making the determination of whether the target frequency is present easier.

There are many types of windows that can be applied in digital signal processing. This particular one is called a Hamming window. The shape of the hamming window is shown in a picture below. The plot below shows the value the window function that is used for each of the samples in the subroutine.

<p>i am very much interested in ur project. pls clarify the foll doubts:</p><p>1. will this project work with pic18f6520?</p><p>2. can this be changed for higher freq ranges? khz or mhz?</p><p>3. if yes, how to change the program?</p><p>4. do u use adc input channel for freq detect?</p><p>5. if so, can the program be carried out in such a way that we know in which channel the freq is detected?</p><p>6. can u help me with the pgmming? ill do the hardware part</p>
<p>Not sure if you are still monitoring this post but I'll give it a try. I found this project interesting but both versions of the source code appear to be truncated. Several labeled routines are missing when I try to assemble it. The files are also not formatted but that is a minor inconvenience.</p>
Trying to make the hex file but did not quit. MPLAB makes mistakes and the hex file that is included here, when you try to download recorded as TMP .. <br>Please help me ... if someone could send me an e-mail the latest code in hex​​? <br>dr.diodac@gmail.com <br>Thank you,
Hey <br>Great topic, sorry for my childish question :) I am not a good programmer. How do to lower the entry threshold of 100Hz for example, 30? would range from 30 Hz or even lower. This is a big change in the program?
Hi there, <br>I'm trying to build your circuit in my project, however, I don't know how to program the PIC 12F683. <br>I mean, I can't transfer the program you provide it to PIC 12F683. <br>So, any clue. <br>Thanks
Do you have a PIC programmer? I use one that I purchased from www.melabs.com years ago, but there are many other sources. There are also plans out there to build your own, but I haven't ever tried them so I can't give more guidance there.
Hi, Thanks for the help. <br> <br>So, this confirms that there is no real need to use an external Xtal if the problem comes from the rounded maths. <br>Not a big issue if you know it... <br>Anyway, it was fun tracking down the problem and i learned a lot looking at your code ! <br> <br>Thanks again,
I think that it is still necessary to use a crystal, otherwise the center of the response will be different from on processor to the next, and my vary over temperature as you discovered. If an oscillator with a greater tolerance is used there will be a corresponding change to the sample rate, and since the coefficents used are a function of the sampilng rate, the response will be different fhan expected. <br> <br>The limitations of the math cause the response to be at a slightly different frequency than expected. If the 1754 Hz center frequency (using the 1760Hz coefficients I mentioned in my last email) is close enough to 1750 Hz for your application, then I would use that along with the external crystal oscillator instead of the 1% tolerance internal oscillator. <br> <br>Working through these issues has identified many things I had not discovered when I first create this project. It has been really helpful to improve the design. If I get time, I would like to investigate these in more detail, and possibly add an update to this article to benefit anyone else who may want to use the program so they can avoid the issues you had to work through.
OK.<br><br>I'm glad if i could help to improve your design !<br>It works perfectly on 2 of our repeaters right now. I will see how they age and keep you informed if necessary.<br><br>I stay tuned on this discussion, so i will be alarmed when you improve the code one day.<br><br>Thanks for you great design and help. I also learned a lot looking at your code. I'm not a programmer, but a &quot;hardwarer&quot;...
Hello. <br>I digged into the code and found where to change the threshold pin from 3 to 6. <br>Now, with a 8 MHz external Xtal and threshold level set on pin 6, the circuit works ! <br> <br>Unfortunately, the bandpass is still not centered on the target frequency... <br> <br>I measured a center frequency of 1736 Hz for a target of 1748 Hz. <br> <br>The Xtal frequency is only a few Hz away from 8 MHz. So the problem is somewhere else.... :-( <br> <br>Can it be that the sin and cosin values are not correct ? <br> <br>Any guess ? <br>
I've been experimenting with the code today, and found the same issue you describe. I also found that the center frequency was low for what should have been about 1750 Hz. I tried using the coefficients for slightly higher frequencies, and found that the closest I could get was to use the values for 1760Hz. This resulted in a response that was centered around 1755Hz. <br> <br>I think the problem is the limitations in how accurately the coefficients can be represented the way I'm doing it. There isn't really much that can be done about that, as trying to represent them with greater precision means that multiplication operations would take much longer, such that the program wouldn't even be possible on this general purpose processor. <br> <br>I've attached the hex and asm files from my most recent build, which uses the 1760Hz values for response much closer to what you want. It is configured for HS_OSC. <br>This time, I've tested the code.
Hi again ! <br>I tried your latest version with an external Xtal, but it does not oscillate. <br> <br>You say, you used the XT mode, but according to the datasheets, it is to be used up to 4 MHz only. <br>Maybe, it is the only reason why my Xtal does not oscillate ? <br> <br>Or maybe there is another problem in the modified source ? <br> <br>I doublecheked my new board and it looks OK according your new design. <br>Pin 2 + 3 for the Xtal + capacitors. <br>Pin 6 AN3 for threshold setting. <br> <br>Can you have a look on it and/or send me the modified code, so i can make my own tests without bothering you. <br> <br>Thanks,
I checked my code, and I did set it up for XT mode. <br> <br>I programmed a part with the code and built the circuit using the crystal, but I could not get the crystal to oscillate either. I also tried a program for a different project I built that uses the 12f683 processor with an 8MHz crystal, but the crystal didn't oscillate with that either. <br> <br>I don't know what to make of that, but I suspect that there may be a problem with the crystal and capacitor circuit. I've only used that setup a couple times before, as I usually just use the intenal oscillator or an external oscillator module if the application requires higher precision. <br> <br>I plan to try again using an external oscillator instead of a crystal with capacitors. I should know how that turns out in a couple days, and then I can send you actual working, tested code that uses an oscillator module. I'll let you know when I have results.
HI !<br><br>I wanted to write a post again... I took the original asm file and modified ONLY the config to use the HS_OSC bit.<br>And now, i have a pure sine wave oscillation at 8 MHz on pin 3 i can see with my scope. Can't figure out why i don't have something on pin2 as this is an input...<br><br>I can't test the complete circuit, as i don't know how to modifiy the rest of the program to work with changed pin configuration.<br><br>So try to modify XT_OSC to HS_OSC on your latest version (with 1750HZ and changed threshold pin) and send me at least the HEX file.<br><br>Thanks for your help.<br><br>
I noticed that using a scope probe introduces some additional capacitance and that reading is disturbed by it. <br>Using a different probe, i have a clean 4V oscillation that stop only when power supply drops down to 2V ! <br>So, everything is just fine using HS_OSC ! I suppose XT_OSC does not have enough gain to start oscillation at 8 MHz. <br>
HI again ! <br>I found some time and having 2 other PICs, i programmed them and made some tests. <br>None of the PICs has the same frequency response.... One does even not detect at the right frequency, being out of band !! <br>Internal frequency precision seems to be quite critical for your decoding, which os logical if based on time. <br> <br>So, there must be a huge dispersion in these internal oscillator despite the 1% &quot;high precision&quot; claimed by the data sheet... <br>Or, there is something else interfering...... I saw in the data sheet that the OSCTUNE register can adjust the frequency.. <br> <br>I heated the PIC with my soldering iron, and the detection frequency changes also, which is quite normal... <br> <br>I don't know if there is a way to measure and change the internal oscillator, but i think that for precise decoding an extrenal oscillator is mandatory ! <br> <br>Can you try to modify your code, so that i can use the pin 2 and 3 for an external crystal ? Maybe you can use pin 6 left free now (when using a fixed frequency) for the threshold of change the code, for a software defined threshold level ? <br> <br>Patrick
I've made a modified version of the 1750Hz code for use with an external 8 MHz crystal (attached to pins 2 and 3). The threshold setting has been changed to pin 6. <br> <br>When you connect the crystal, you will need to have two small caps connected as well, one on each side as shown in the schematic I attached. I've used 22pF caps with an 8MHz crystal on this processor before on another project , and it worked properly. <br> <br>This code is configured for &quot;XT&quot; oscillator mode, and described in the oscillator section of the 12F683 datasheet. <br> <br>I haven't tested this code, but the modifications were very minor so hopefully it works.
Wow !<br><br>Thanks for that !<br>I will test it asap and keep you informed. Can you post the modified assembler, so i can see how you did that ?<br><br>BTW, on the 3 PICs i've tested, the bandpass is exactly the same. 34 Hz, so about 2%.<br><br>Thanks again !
I will send the asm file if the code checks out. Let me know once you get a chance to test it with the crystal.
Hello, <br> <br>I found the time to build a new pcb and ordered some 8 MHz Xtals. <br>I programmed a new PIC. But unfortunately, the xtal does not oscillate at all. <br> <br>Can you check you hex file if it is really configured for XT ? <br> <br>Thanks, <br> <br>
OK, <br> <br>Thanks for the explanations. <br>At least, we could make a test with a modified code for an external 8MHz oscillator, so we can eliminate one source of inaccuracy. <br> <br>I would be interested to test it; though. <br> <br>Patrick
Hi ! <br> <br>Yes, i already made an article on my page, but for the moment only in french. I will translate it in english for my radioamateur visitors. Actualy, it looks like that : http://www.egloff.eu/index.php?option=com_content&amp;view=article&amp;id=37&amp;Itemid=202&amp;lang=fr <br> <br>I have added the more or less universal pcb design i've made with KICAD. <br> <br>BTW, i made some measures and for a frequency target of 1750Hz, the decoder detects from 1713 to 1760 Hz. <br>Is there any reason for this asymetrical bandpass ? For a centered bandpass, should i choose a higher target frequency ? <br> <br>Thanks and apologize again, <br>Patrick
I couldn't say offhand exactly what the cause is. One thing I should add is that the constants I used in the fixed frequency code were for 1748 Hz, as they were calculated out in 4Hz increments. The next highest frequency was 1752Hz, so still 2 Hz off your target. <br> <br>Part of the reason for the actual detection range may be the limitations of how accurate the the math routines are. This PIC has no native multiplication instructions, just 8 bit add and subtract, so I had to write them myself. There is some inaccuracy and rounding involved, as I had to keep them simple so they would run fast enough on a general purpose PIC with only 8 bit add and subtract. <br> <br>Another source of inaccuracy may be from the fact that the program I wrote has the processor using an internal 8MHz oscillator, which doesn't have the accuracy of a crystal. <br> <br>I would suspect that as a result of the various sources of inaccuracy, the actual center frequency is about 1737Hz. In general the passband should be symetrical. <br> <br>I hope that this doesn't impact your application. If it does, I could look into a slightly modified version of the code that would use an external 8MHz oscillator instead of the internal one.
Hello LargeMouthBass, <br> <br>I have to apologize ! <br>Your modified code for a fixed frequency works perfectly ! <br> <br>I make some new tests today and found a broken transistor on my test board ! I should have double checked it before.... :-(( <br> <br>You know what ? I'm happy ! <br>Thanks and apologize again ! <br> <br>Patrick
I'm glad to hear that it is working! <br> <br>Are you going to include details of your project on your web site? <br> <br>Anyway, I'm glad it seems to be working out. Please let me know if you need any other help.
Hello, <br>I finaly found the time to test your design ... :-(( <br>I made a small board yesterday evening and wired it right now. <br>The modified 1750 Hz version you put here does not work. The serial output is disabled, but no tone is detected. <br>I tested with the normal software and it works just as predicted... So, there must be a small mistake in the modified code. <br> <br>One error i noticed in your text, the part describing the frequency selection. <br>The voltage divider used for the frequency setting should use R3+R4 and not R1+R2 in your formula. <br> <br>I don't have the assembler to make my own tests in modyfing the code to make it work at a given frequency. This would still be fine, as i wouldn't be dependent of the supply voltage fluctuation. <br> <br>Do you allow me to translate it in french and put it on my homepage ? <br>http://www.tk5ep.tk <br>I'm sure it will be useful to others as well. <br> <br>Thanks again for this nice circuit !!
Hello <br> <br>I'm sorry to hear that the 1750Hz code didn't work. It sounds like you can still make your application work by using the regular code and selecting the frequency using the analog input. <br> <br>Thanks for pointing out the error. I have corrected the article to refer to the right resistors. <br> <br>If you ever want to modify the code, the assembler I use is the free MPASM from www.microchip.com <br> <br>When you say you want to translate to French, are you referring to the text of the article? That should be fine, as I have posted all the details of the project here, so go ahead. Perhaps make a reference back to the original article. If anyone else can make use of the code that would be great. <br> <br>Thanks for your interest in this project, I'm glad you could make use of it.
what is the frequency you set here as default ?? and where to change in the coding?? ( am a beginner help me plz ). How can i know the desired frequency was found by the circuit if serial output is not taken??? i want to switch ON a diode if that desired frequency was found.. is it possible without serial output, help me with any alternative way??? ALSO WHAT IS THE RANGE OF FREQUENCY DOES THIS CIRCUIT COULD DETECT ( am expecting 25khz) plz help me out... its urgent buddy ....
There is no &quot;default&quot; frequency. It is determined by the voltage which is read on an analog input. There is an equation in the text that can be used to find the voltage to apply to the pin to set the desired frequency to detect. <br> <br>It is not necessary to use the serial output for any functions. It is there just for user information/debugging if needed. You can tell if the frequency is detected by the state of the detection output alone. <br> <br>Unfortunately, the range of detectable frequencies does not extend to 25kHz. The detectable range is only 148Hz tp 2148Hz. It was designed for use in detecting audio tones. The Goertzle algorithm concept and the related mathematics can apply be applied to any frequency, if it is sampled at a sufficient rate and the samples can be processed in time. With the project shown here it is not possible to go beyond that range, as to do so it far outside the processing capability of this small general purpose processor that is only running on an 8MHz clock.
i want analog output to analyse it... ie; i dont want only the detection, also i want the sound output from the pic. plz guide me
This program doesn't output any analog, just the detection output. I assume that you are wanting a narrow filter for audio? That is beyond my present knowledge of DSP, and probably isn't feasible for a general purpose processor like the 12F683 used here. It would need a &quot;real&quot; DSP.
thanks for your response... i hav some queries here . to operate this frequency detector, whether i want to load that .asm directly or i have to write the coding on own ??? plz guide me ,, am just a beginner
The *ASM file is what the assembler program uses to generate the *.hex file that is actually used to program the part. I attached both the asm and hex files to the article. If you just want to program the part with the code I created, use your programmer to load the *.hex file onto it. You won't need to do anything with the asm file just to use my code as-is. <br> <br>If you want to make your own modified versions of the code, you will have to open the *.asm file in Microchips MPLAB software, make your changes, and then reassemble to generate a new *.hex file that reflects your changes.
i want to analyse the amplitude i.e; output sound.... plz guide me that how to take the analog signal from the filtered output from the pic
Hi ! <br /> <br />Great project ! <br />I would like to use your circuit for a local repeater. I want to replace the unstable NE567 decoder with a small addon board. <br />I only need a fixed frequency ( 1750 Hz ) and no serial data output. So for simplicity and no tuning, i would like to remove the divider for the target frequency. <br />I saw in the previous posts that someone modified the code to do that. I'm not a programmer, so can you help me to do that ? <br /> <br />Thanks
I can probably make a separte version of the code that would just do a single frequency. I can also disable the serial output. (The serial output is just for information only, and it is not necessary to use it to use the circuit. It could also just be left disonnected. Disabling it improves response time, but only slightly). <br /> <br />I won't have time to test the new code myself to verify performance though. If you have a PIC programmer, I can send you a hex file for programming, and you can test it from there. <br /> <br />Let me know if you think that would work for you.
Hello! <br /> <br />Yes, that would be fine. If you can send the asm file as well, it would help me to understand what you did and probably be able to modify it for any tone. <br /> <br />I don't have 12F683 PICs, but will order a few. I have a PIC programmer. <br /> <br />BTW, is the internal clock precise enough for a stable operation ? Wouldn't a external Xtal be better ? <br /> <br />Thanks for the answer, <br />
For some reason, my file attachments to my earlier message didn't work right. I'll try again. The uploader didn't like the *.asm file externsion, so I had to change it to .txt. <br /> <br />
Thanks a million, <br /> <br />I will try this ASAP and will let you know. <br /> <br />Thanks for taking the time to answer me and being so helpful. <br />
I've made a special version of the code which is set to detect 1750Hz. Actually, it is for 1748 Hz, as the frequency cannot be selected that precisely with the math I am doing. The serial output has been disabled. <br /> <br />I made the changes by commenting out the sections that read the frequency setting. I deactivated the serial output by having the code immediately return from the subroutine that ordinarily would transmit the characters. I've added notes to the asm file to show where I have made the changes. I've left the code in the asm file, even unused code, for reference. The asm for the regular version is attached to the main article. <br /> <br /> I have not tried this special version of code in circuit, but the modifications were very straightforward, so the should work. Let me know if the code doesn't work. <br /> <br />The width of the frequency response is fairly narrow, refer to some of the diagrams in the main article. <br /> <br />The internal oscillator has a tolerance of about 1%. I've found that it works well. <br />The special version of code I made uses the internal oscillator, but since the serial is not used, you could connect an external oscillator to pin 2 (RA5) and modify the code to use an external oscillator. <br /> <br />I hope the code works for you. Let me know if you have any problems. I'd like to hear about your repeater project when you have it finished!
What are the advantages/disadvantage of using this PIC over a&nbsp;<a href="http://talkingelectronics.com/ChipDataEbook-1d/html/567.html" rel="nofollow">LM567 Tone Decoder</a>?<br> <br> I'm trying to design a circuit that detect/differentiate frequencies in the ranges of 190hz, 250hz and 285hz. Thanks!
I haven't worked much with the 567 decoder. From what I recall it was somewhat finiky, but that may not be a fair assesment. <br> <br>The design I made for this instructable should work well for your application. One downside might be if you don't have a PIC programmer available and so you would need to make or buy one. <br> <br>The 567 is probably somewhat less expensive than a 12F683, although the price of each is not very great. I think the 12F683 is less than $2 in small quantities from Digikey. <br> <br>One strength of the detector in my instructable is that it is easily configurable using just a voltage divider on the frequency select input. You could use 3 processors running the software included in the instructable. The analog signal inputs could all be driven in parallel. A separate voltage divider would be needed on each process to select the desired frequency. The three outputs would easily interface to whatever logic your application needs.
cool thanks for taking the time to review my question.<br><br>you said, &quot;if you don't have a PIC programmer available...&quot; yea.. I'm sure one of these days I'll want to move on from the Arduino prototype playland and actually hard code something.. eh? <br><br>So just for curiosity, could this code be easily adopted for compiling into an Arduino and/or why hasn't someone done that? cheers,
how about sensing 220v, 50 Hz frequency??
how the frequency detected output can be viewed ? do i need to attach a LCD display?<br>
The frequency detect output on pin 5 is just a digital output that goes high when the selected target frequency is detected. If the algorithm results are greater than the upper threshold setting, then the line will go high. <br> <br>The serial output line is optional. I included it for diagnostic purposes and to help the user better understand how the circuit works. To view the serial output, you need to convert the serial output to RS-232 levels (inverted) and connect it to a PC serial port. If your PC has no serial port, as is common on most newer PCs, you can get USB to Serial adapters that will provide a serial port. <br> <br>I hope that answeres your question. If you have any other questions, feel free to ask.
Great SW.<br><br>I am going to use the circuit for a CTCSS decoder in our local 434 MHz ham radio repeater. I have lowered the sampling frequency to 2000 Hz , disabled the analog frequency input and the serial data parts as I am not going to use them. As a concequence I can only detect one tone which is my need. With the SW set to detect 82.5 Hz, the circuit detects from 81 Hz to 85 Hz and no triggering on the adjacent tones. Very good performance<br><br>I have noticed one peculiarity. The time elapsed from a tone is applied to the input and until Pin 5 goes high varies between 110 msecs and 240 msecs. As i have disabled the serial communication and also the reading of the frequency at Pin 6, I would expect a fairly constant delay in detecting. any thougts about this?
I just thought of another detail that may make the detector output timing more consistent. <br> <br>All my previous comments still apply, but there may also be a bit of an issue with the coupling network of R1, R2, and C1. These parts essentially form a first order high pass filter. The roll off frequency is f = 1/ (2 * pi * C1 * R1 || R2). With the values of 10k and 1 uF as shown in the circuit, the roll off would be about 31Hz. This should be OK for your 82Hz signal, but I don't know the exact values you are using. If the roll off frequency using the values you are using is greater than say 60 Hz, I would choose some different values to make sure the roll off is well below 82 Hz. <br> <br>If you were attenuating the signal by using too high a roll off frequency, the circuit may be more likely to take 240 ms from the start of the tone until the detection output goes high.
The software computes the response based on taking a total of 240 samples. Since you've lowered the sample rate from 4400 to 2000 Hz, it will take a total of about 120ms to take the 240 samples. The other computations that follow take a very short amout of time compared to the 120ms worth of samples. This process repeats, and the digital output is set high or low depending on the results of each 240 sample &quot;sweep&quot;. <br> <br>If the tone is applied somewhere in the middle of a sweep, the magnitude of the response may not be high enough for the output to get set high. One the next sweep, the tone is present for the entire time, and so the magnitude is great enough to get exceed the threshold. If the tone was turned on, say, only 1/4 of the way through the sweep, then perhaps that sweep would result in a great enough magnitude to generate a high output. It will also depend on the detection threshold you have selected. In the instances where it takes 240 ms to detect, the tone must have turned on when the sweep was too close to the end for the magnitude to be great enough. <br> <br>So, it all depends on where the process is when the tone is first applied. This will end up being somewhat random, as the tone detection process won't be syncronized to the CTCSS tone. <br> <br>I don't think that there is much that can be done to improve the situation, as the scanning process is broken into 240 sample windows, as described. I hope that this doesn't impact your application too negatively. <br>
I am attempting to use this circuit to detect a sound that my bird is making at about 4kHz. I need to modify the program to detect this range. When I load the asm in MPLAB and try to compile it I get 106 instances of error[118] Overwriting previous address contents. What am I doing wrong?

About This Instructable


41 favorites


Bio: "But I was going to Toshi station to pick up some power converters!"
More by LargeMouthBass: Audio Delay Module Reverse Engineering an Electric Fence Charger Stop Time with an LED Stroboscope!
Add instructable to: