View previous topic :: View next topic |
Author |
Message |
iw2nzm
Joined: 23 Feb 2007 Posts: 55
|
Goertzel troubles |
Posted: Sat Apr 21, 2007 9:29 am |
|
|
Hello,
I wrote a simple code to detect DTMF tone using the modified Goertzel algorithm. Here is the code:
Code: |
#include <12F683.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOCPD //No EE protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES MCLR //Master Clear pin enabled
#FUSES PUT //Power Up Timer
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#use delay(clock=20000000)
#use fast_io(A)
#define OUT PIN_A0
#define IN PIN_A1
#define RING PIN_A2
#define TIMEOUT 100 // 30 sec
#define MAX_SAMPLES 200
#define MAX_DETECT 3
#define THRS 50
int1 ready = FALSE;
int8 index, i, detect;
int16 tick = 0;
int16 s, s_prev, s_prev2;
int16 pwr[8];
int16 coeff[8] = {1717, 1652, 1582, 1506, 1151, 840, 618};
char analyze();
#int_EXT
void EXT_isr(void) {
i = index = detect = s = s_prev = s_prev2 = 0;
ready = FALSE;
output_drive(RING);
output_low(RING);
delay_ms(10);
output_high(OUT);
tick = 0;
disable_interrupts(INT_EXT);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_TIMER1);
}
#int_TIMER1
void TIMER1_isr(void) { // 100 ms
set_timer1(0x0BDB);
if (++tick >= TIMEOUT) {
tick = 0;
output_float(RING);
output_low(OUT);
ready = FALSE;
disable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
}
}
#int_TIMER2
void TIMER2_isr(void) { // 125 us
if (++i < MAX_SAMPLES) {
s = input(IN) + ((coeff[index] * s_prev) >> 10) - s_prev2;
s_prev2 = s_prev;
s_prev = s;
} else {
disable_interrupts(INT_TIMER2);
if (index == 7) {
ready = TRUE;
} else {
pwr[index] = s_prev2 * s_prev2 + s_prev * s_prev - (coeff[index] * s_prev2 * s_prev) >> 10;
index++;
i = s = s_prev = s_prev2 = 0;
enable_interrupts(INT_TIMER2);
}
}
}
void main() {
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_1,124,5);
setup_comparator(NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_EXT);
disable_interrupts(INT_TIMER1);
disable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
ext_int_edge(L_TO_H);
setup_oscillator(False);
output_float(RING);
output_float(IN);
output_drive(OUT);
output_low(OUT);
i = index = detect = s = s_prev = s_prev2 = 0;
ready = FALSE;
output_drive(RING);
output_low(RING);
delay_ms(10);
output_high(OUT);
tick = 0;
disable_interrupts(INT_EXT);
enable_interrupts(INT_TIMER2);
// enable_interrupts(INT_TIMER1);
for (;;) {
if (ready) {
ready = FALSE;
if(analyze() == '#') {
if (++detect > MAX_DETECT) {
output_float(RING);
output_low(OUT);
disable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
}
else {
index = s = s_prev = s_prev2 = 0;
enable_interrupts(INT_TIMER2);
}
}
else {
detect = 0;
index = s = s_prev = s_prev2 = 0;
enable_interrupts(INT_TIMER2);
}
}
}
}
char analyze() {
int8 j;
signed int8 first, second;
first = second = -1;
for (j = 0; j < 4; j++)
if (pwr[j] > first && pwr[j] > THRS) first = 0x01 << j;
for (j = 4; j < 8; j++);
if (pwr[j] > second && pwr[j] > THRS) second = 0x01 << j;
if (first == -1 || second == -1) return 0;
first += second;
switch (first) {
case 17:
return '1';
case 33:
return '2';
case 65:
return '3';
case 18:
return '4';
case 34:
return '5';
case 66:
return '6';
case 20:
return '7';
case 36:
return '8';
case 68:
return '9';
case 40:
return '0';
case 24:
return '*';
case 72:
return '#';
case 129:
return 'A';
case 130:
return 'B';
case 132:
return 'C';
case 136:
return 'D';
}
}
|
It doesn't work... It doesn't detect the '#' even if it sometimes detect any incoming dtmf tone.
Well, I don't hope you can find the error... but I ask you how to debug! I don't know how I can fix errors in this code...
Any suggestion is welcome!
Marco / iw2nzm |
|
|
Richard Arroyo
Joined: 04 Apr 2006 Posts: 22 Location: Sebastopol, CA
|
|
Posted: Sun Apr 22, 2007 2:25 am |
|
|
Hello,
I am too tired to go through all of your errors
but hopefully this will help you for now.
First, it appears you have forgotten one of the eight coefficients.
Your array only lists 7: (int16 coeff[8] = {1717, 1652, 1582, 1506, 1151, 840, 618};)
I belive CCS C defaults to unsigned integers. You did not specify the type therefor
you are using unsigned integers which is disastrous.
How did you calculate your coefficients?
1024? * (2 * Cos(2 * pi * (F / FS)))?
This algorithm is quite sensitive to truncation.
Scaling down will lead to truncation errors and
no scaling will cause overflow depending on the data type and n samples
so you must compromise between the two.
I think your program suffers from truncation errors resulting
in incorrect filter response.
Using a 1bit waveform as the input signal will
work but result in poor SNR and harmonic excitation.
With 1 bit the SINAD is only 7.78.
Do you have filtering and biasing present on
pin PIN_A1?
Keep in mind when using signed 16 bit integers
the product of two numbers greater than the sqrt(32767)
will cause an overflow. Also, 16 bit multiplies will take 48us @5mips
on this chip due to no hardware multiplier. It appears you're still
ok time wise.
I'm nodding off ... time to sleep.
-Richard _________________ RAA |
|
|
iw2nzm
Joined: 23 Feb 2007 Posts: 55
|
|
Posted: Sun Apr 22, 2007 2:40 am |
|
|
Richard Arroyo wrote: | Hello,
I am too tired to go through all of your errors
but hopefully this will help you for now.
|
I guess I was too tired too when I wrote that!
Thank you for your detailed answer. Now I go to fix those errors.
The coefficients was calculated in this way:
k = N * fi/fs
k, nearest integer
N, filter lenght
fs, sampling frequency
fi, input frequency
coeff = 2 * cos(2pik/N)
Then I use 1024 times coeff in order to manage integers instead floats.
I know the 1-bit AD is very poor, but I read it's possible to achieve quite good result even with small PICs.
Ok, I go to test again.
Thank you
Marco / iw2nzm |
|
|
iw2nzm
Joined: 23 Feb 2007 Posts: 55
|
|
|
subi
Joined: 29 Aug 2010 Posts: 24
|
Goertzel algorythm |
Posted: Mon Jan 02, 2012 8:41 am |
|
|
Dear programmers,
I would like to learn the goertzel algorythm in CCS with ADC to tone detect (697 - 1633Hz). But I have not found any good program and circuit about it. So if you can help me please do it.
Thank you for your help.
Sorry for my English.
Best regards,
Subi |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Mon Jan 02, 2012 9:24 am |
|
|
you might try Google 'dtmf decoder PIC' ther are 1,000s of hits. First one is a complete project, quite detailed, and up to you to convert to CCS C or just use as inline asm....
Honestly easier to use dtmf chip and use a few I/O pins unless your PIC has big memory space. |
|
|
subi
Joined: 29 Aug 2010 Posts: 24
|
|
Posted: Mon Jan 02, 2012 10:26 am |
|
|
temtronic wrote: | you might try Google 'dtmf decoder PIC' ther are 1,000s of hits. First one is a complete project, quite detailed, and up to you to convert to CCS C or just use as inline asm....
Honestly easier to use dtmf chip and use a few I/O pins unless your PIC has big memory space. |
Dear temptronic,
Thank you for your answer and your advise. But I would like to say that I have looked for Goertzel in the net to use Google for about one mounth. But as I wrote I would like to learn more about Goertzel and I am a hobbist and a beginner. So I tried to write over the other code to CCS C. It was unsuccessful. Therefore I thought to ask help from more humbler programmers. But I have not been a tax anybody.
Sorry for my trouble.
Best regards,
Subi from Hungary |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Jan 02, 2012 10:38 am |
|
|
Is this a STUDENT project?
Hobby effort?
Meant to be part of commercial product?
The Goertzel method is a cool demonstration -
but is SO processor intensive - there is not much else the pic can do Except perform a pretty low quality job of detection.
If you are creating a product - you should be aware that there are FAR better ways to do this with an external chip OPTIMIZED for the DTMF detection task. And I already know from experience that a shared 3.57954 mhz xtal can do a fine job at 9600 baud too.
|
|
|
subi
Joined: 29 Aug 2010 Posts: 24
|
|
Posted: Mon Jan 02, 2012 12:25 pm |
|
|
Hi asmboy,
It is a hobby project for me. I do not want to use external IC only softver. I have some good pics for example 18F45K20 or 18F46K80 and I would like to use them. So I have enough memory. If you can halp me I will able to be glad.
Subi |
|
|
|