Truncated match.
PICList
Thread
'DTMF  results'
1996\06\23@233030
by
Steve Hardy

I recently became the proud owner of a Clearview xx ICE. The first
application just _had_ to be the DTMF generator. For those who are
interested, here are the results:
1) Hardware.
Incircuit emulator used at 10MHz, with PIC16C74 pod. None of the magic
smoke has leaked out yet  always a consideration at >$300 a pop.
The PIC has enough grunt to directly drive a headphone speaker. The
PWM output was coupled via a 820ohm/0.1uF low pass RC directly into the
23ohm headphone. Surprisingly, this may be heard from quite a distance
in spite of the inefficiency and impedance mismatch. I suspect that
quite a loud sound may be produced from an 8ohm speaker if one of those
little 1K:8ohm 'transistor radio' transformers were used.
The acoustic output was coupled into the telecom network by holding the
handset against the headphone. As far as I am aware, my home is
connected to a stateoftheart digital exchange (we have pretty good
telecom here in Australia).
2) Software.
The DTMF generator code was used with a few mods (such as to direct
output to PWM). The PWM was set at a base rate of 19KHz. As a test,
my mobile phone number could be signalled at various rates; the
fastest rate being 50ms per tone with 50ms pause between tones.
3) Results.
At a rate of 100ms per tone, the setup was able to dial successfully.
At 75ms it was OK with the odd error. At 50ms the network got
awfully confused. Even at 100ms per tone, this is much faster than
any other automatic dialling equipment I have ever heard. In fact,
it is hardly recognisable as DTMF dialling.
When I first heard the tones produced, the thing that struck me was
that there is quite a high level of subharmonic content. This is
because the output sequence repeats at a rate substantially less than
the nominal output frequency. The subharmonics do not have
any affect on the DTMF receivers at the exchange, but they may be
considered detrimental if the PIC is to be used for musical purposes.
Regards,
SJH
Canberra, Australia
1996\06\24@142750
by
Scott Dattalo

(CAUTION: If you don't have much patience for longwinded emails then delete
this
message now.)
Steve,
In the very first posting of your DTMF threads you said that the sine waves for
the
two DTMF tones can be generated in 202 cycles (per sample). I have another way
to
generate sine waves that only takes 65 cycles per sample or for both tones, 130
cycles.
This could reduce the burden of your analog filters by allowing you to supply
more
samples per cycle of each sine wave. It may also give you that extra little
boost to
get you over the 50ms hurdle in the DTMF decoder.
Your approach which follows that of AN616, is based on a trigonometric recursion
relationship. It's the basis of the Goertzel algorithm  an algorithm that
efficiently
computes the DFT (discrete Fourier Transform).
In essence, you want to compute a series of sine wave samples that are equally
spaced in
frequency. We can define the starting angle as a and the step in angles as b. So
the
series looks like this:
sin(a), sin(a + b), sin(a + 2*b), sin(a + 3*b), ..., sin(a + n*b)
The goal is to recursively compute sin(a+n*b) using the two previous values in
the sine
series, sin(a + (n1)*b) and sin(a + (n2)*b):
sin(a + n*b) = x * sin(a + (n2)*b) + y * sin(a + (n1)*b)
Here, x and y are two constants that need to be determined. Note that the next
value or
the n'th value depends on the previous two values, n2 and n1.
Rearranging and simplifying:
sin(a + n*b) = x * sin(a + n*b  2*b) + y * sin(a + n*b  1*b)
sin(a + n*b) = x * [ sin(a + n*b) * cos(2*b)  cos(a + n*b) * sin(2*b)] +
y * [ sin(a + n*b) * cos(b)  cos(a + n*b) * sin(b)]
sin(a + n*b) = [x * cos(2*b) + y * cos(b)] * sin(a + n*b) +
[x * sin(2*b) + y * sin(b)] * cos(a + n*b)
For this to be true for all n, we must have the two expressions in brackets
satisfy:
[x * cos(2*b) + y * cos(b)] = 1
[x * sin(2*b) + y * sin(b)] = 0
which, when solved yields
x = 1, <== A very convenient constant, turns multiplication into
subtraction
y = 2*cos(b), <== Another constant that requires multiplication.
Finally, substituting into the original equation we get:
sin(a + n*b) = sin(a + (n2)*b) + 2*cos(b) * sin(a + (n1)*b)
!
This algorithm is excellent for DSP's. For the low and mid range PICs, it is
hindered
slightly by the 8x8 multiplication. However, there is another algorithm that has
just
as much accuracy as this one. If you read "Embedded Systems" (I don't any more
since
they refused to forward my subscription to my new job) you might have read a
series by
Jack Crenshaw on how to efficiently compute the sine function. His approach,
which I've
implemented in PIC assembly, uses a lookup table plus first order linear
interpolation.
You can read the comments in the program to see how it works. But here's a brief
summary of its features:
1) 50 words of program memory, including 18 for a lookup table.
2) 65 cycles of execution time (for all cases)
3) 9 bytes of RAM  5 are temporary (actually you can save one off of this)
4) 8 bit signed output (+/ 1 count accuracy)
5) 0.022 degrees of frequency resolution (360 / 16384 ~ .022). With a few extra
words, this could be improved to 0.0055 degrees (360 /65536).
6) Sine values are randomly accessable (as opposed to the recursive, serially
accessed method of the Goertzel algorithm). This gives an extra flexibility on
dynamically tweaking the frequency, which is something I've found useful for
analog
phase locked loops.
cblock 0x20
f_hi ;Low byte of frequency variable
f_lo
x1
x2
interp
index
product
fstep_lo
fstep_hi
endc
ODD_QUADRANT equ 4 ;In f_hi
NEG_QUADRANT equ 5 ;In f_hi
INDEX_MASK equ 0x0f ;In f_hi
INTERP_MASK equ 0xf0 ;In f_lo
ORG 0 ;Reset Vector
GOTO Main
ORG 4 ;Interrupt Vector
Main
BCF STATUS,RP0 ;Point to BANK 0
;Initialize the step in frequency
MOVLW 0x10
MOVWF fstep_lo ;One unit of fstep corresponds to 360/16384
degrees
CLRF fstep_hi ;i.e. 0.02197 degrees. Set fstep = 455 (1c7) to
step
;10 degrees for example
CLRF f_hi ;Start off at 0 degrees
CLRF f_lo
xxx
CALL sine
NOP
;Now that the sine has been calculated, we could do something with it other
than
;throwing it away.
;Make a frequency step. Note, the frequency step doesn't necessarily have to
be
;constant. E.g. it could be changed as part of a PLL algorithm.
MOVF fstep_lo,W
ADDWF f_lo,F
SKPNC
INCF f_hi,F
MOVF fstep_hi,W
ADDWF f_hi,F
GOTO xxx
;
;sine
;
; The purpose of this routine is to take the sine of the
;16bit frequency variable f_hi:f_lo to produce a signed
;8bit result that is within +/ 1 count of the true sine
;value.
; Only the lower 14 bits of the frequency variable are
;actually used. The frequency variable maps into degrees
;by the following transfer function:
; degrees = (f & 0x3fff) * 360 / 0x4000
; The sine output is approximately
;sine = int(127*sin( (f & 0x3fff) * 360 / 0x4000) )
; where
; sin() is the true sine function
; int() is the nearest integer function
;
;The technique used to obtain the sine value is a combination
;of table lookup and first order linear interpolation. Sixteen
;equidistant frequency samples of the first quadrant of sin(x)
;are stored in sine_table.
;
; The frequency variable is broken down as follows:
; xxQQTTTT IIIIPPPP
; where
; xx  don't care
; QQ  Quadrant: 00 = quadrant 1, 01 = quadrant 2, etc.
; TTTT  Index into the sine_table.
; IIII  Interpolation between successive entries in the table
; PPPP  Phase accumulation (not needed in this function, it's
; only used to increase the dynamic range in frequency
; steps).
;Once the frequency has been broken down in to these parts, the
;sine function for the first quadrant can be calculated as follows:
; x1 = sine_table[index]
; x2 = sine_table[index+1]
; sine = x1 + ((x2x1) * interp) / 16
;The first term, x1, is seen to be a first order approximation to
;sine function. The second term improves on that approximation by
;interpolating between x1 and x2. The interpolation variable interp
;is 0 <= interp <= 15 and it is divided by 16. Consequently, the
;interpolation factor ranges between 0 and 15/16.
;
;The sine function in the other three quadrants can be obtained
;from calculations based on the first quadrant by using the following
;trig identities:
; first, let 0 <= f <= 90, i.e. f covers the first quadrant.
; quadrant 2: u = 90 + f, 90 < u < 180
; sin(u90) = sin(f)
; x1 = sine_table(16index), x2 = sine_table(15index)
; quadrant 3: u = 180 + f, 180 < u < 270
; sin(u) = sin(f+180) = sin(f)
; x1 = sine_table(index), x2 = sine_table(index+1)
; quadrant 4: u = 270 + f, 270 < u < 360
; sin(u90) = sin(f+180) = sin(f)
; x1 = sine_table(16index), x2 = sine_table(15index)
;
;Thus, for quadrants 2 and 4, the sine table is indexed in reverse
;order and for quadrants 3 and 4 the values from the sine table
;are negated. A slight change is made on this indexing and negation
;scheme so that the operation (x2x1) * interp / 16 only deals with
;positive numbers. This significantly simplifies the multiplication.
;The modification changes the formula for each quadrant as follows:
; quadrant 1: (no change)
; x1 = sine_table[index], x2 = sine_table[index+1]
; sine = x1 + ((x2x1) * interp) / 16
; quadrant 2:
; x1 = sine_table[15index], x2 = sine_table[16index]
; sine = x2  ((x2x1) * interp) / 16
; quadrant 3:
; x1 = sine_table[index], x2 = sine_table[index+1]
; sine = (x1 + ((x2x1) * interp) / 16)
; quadrant 4:
; x1 = sine_table[15index], x2 = sine_table[16index]
; sine = (x2  ((x2x1) * interp) / 16)
;
;Input
; f_hi:f_lo  16bit frequency variable
;Output
; W = int(127*sin( (f & 0x3fff) * 360 / 0x4000) )
;
;Execution time: 65 Cycles (for all cases)
;
sine
;Get the 4bit interpolation factor
SWAPF f_lo,W
ANDLW 0xf
IORLW 0x80 ;Set the MSB. Used below in the multiply loop
;as the "loop counter".
MOVWF interp
;Get the 4bit index and add 1 to it.
MOVF f_hi,W
ANDLW INDEX_MASK
ADDLW 1
BTFSC f_hi,ODD_QUADRANT
SUBLW 17 ;Odd quadrants, index = 16  index
;Actually: (index + 1) = 17  (index +
1)
; = 16  index
MOVWF index
CALL sine_table ;Get x2=sin(index+1)
MOVWF x2
DECF index,W
CALL sine_table ;Get x1=sin(index)
MOVWF x1
SUBWF x2,W ;W=x2x1, This is always positive.
;Initialize the product of (x2x1)*interp/16 to 1/2. Note 8/16 == 1/2
;(This rounds the product to the nearest integer.)
CLRF product
BSF product,3 ;(note, product and index could be aliased to
; save one byte of ram).
;multiply interp and x2  x1 and divide by 16. This is actually a 4 by 8
;bit multiplication. The division by 16 is implemented with a shift right
;one position for each of the four passes through the loop. Four passes
;are determined by monitoring the migration of the MSB of interp. It is
;initialized to 1 above and is shifted right one position each pass
;through the loop. On the fourth pass, it will be in bit position 3.
s1 RRF interp,F ;If the LSB is set
SKPNC
ADDWF product,F ;Then add (x2x1) to the product
RRF product,F ;Divide the product by two
BTFSS interp,3 ;If the MSB has not made it here yet
goto s1 ;then we need to loop again
MOVF product,W
BTFSS f_hi,ODD_QUADRANT
ADDWF x1,W
BTFSC f_hi,ODD_QUADRANT
SUBWF x2,W
BTFSC f_hi,NEG_QUADRANT
SUBLW 0
RETURN
sine_table
ADDWF PCL,F
RETLW 0 ;127*sin(0 * 90/16)
RETLW 12 ;127*sin(1 * 90/16)
RETLW 25 ;127*sin(2 * 90/16)
RETLW 37 ;127*sin(3 * 90/16)
RETLW 49 ;127*sin(4 * 90/16)
RETLW 60 ;127*sin(5 * 90/16)
RETLW 71 ;127*sin(6 * 90/16)
RETLW 81 ;127*sin(7 * 90/16)
RETLW 90 ;127*sin(8 * 90/16)
RETLW 98 ;127*sin(9 * 90/16)
RETLW 106 ;127*sin(10 * 90/16)
RETLW 112 ;127*sin(11 * 90/16)
RETLW 117 ;127*sin(12 * 90/16)
RETLW 122 ;127*sin(13 * 90/16)
RETLW 125 ;127*sin(14 * 90/16)
RETLW 126 ;127*sin(15 * 90/16)
RETLW 127 ;127*sin(16 * 90/16)
END
Scott
PS. Sorry about the length of the message.
PPS. This same algorithm implemented on a TMS320C50 executes in around 10
cycles. My guess
is that the Goertzel algorithm is comparable (probably faster).
1996\06\24@180724
by
John Payson

One approach I was considering for DTMF which would have been a little
tricky on the 16C71 [not quite as much RAM as I'd like] but should work
nicely on the '71A would be to use a "runningphase" counter which runs
from 0x00000x2FFF and do something like the following:
movf FreqLow,w
addwf PhaseLow,f
btfsc C
incf PhaseHi,f
movf FreqHi,w
addwf PhaseHi,f
rrf PhaseHi,w
andlw $1C
Boing:
addwf PC
Phase0:
movf Source,w
addwf Slot0
goto Gone
Phase1:
movf Source,w
addwf Slot1
goto Gone
Phase2:
movf Source,w
subwf Slot2
goto Gone
Phase3:
movf Source,w
subwf Slot0
goto Gone
Phase4:
movf Source,w
subwf Slot1
goto Gone
Phase5:
movf Source,w
subwf Slot2
goto Gone
Phase6:
movlw $30
subwf PhaseHi
movf Source,w
addwf Slot0
Gone:
...
Fourteen cycles per frequency per sample to produce 3 buckets; the largest
absolute value among (Slot0+Slot1), (Slot1+Slot2), (Slot2Slot0) will
correspond pretty well to the amount of energy at the desired frequency
(note: there will be a little bumpiness since your sampling points are
60 degrees apart, and you will pick up some 5th and 7th harmonics though
this method will filter out the 2nd and 3rd and all multiples thereof.
Running this algorithm on a PC yielded pretty good results, and it would
seem it should run decently on a 16MHz PIC (looking for 8 tones, sampling
rate of about 8KHz).
What do people think of this as an approach?
1996\06\24@215538
by
Steve Hardy

> From: John Payson <spam_OUTsupercatTakeThisOuTMCS.COM>
>
> One approach I was considering for DTMF which would have been a little
> tricky on the 16C71 [not quite as much RAM as I'd like] but should work
> nicely on the '71A would be to use a "runningphase" counter which runs
> from 0x00000x2FFF and do something like the following:
[code deleted]
{Quote hidden}> Fourteen cycles per frequency per sample to produce 3 buckets; the largest
> absolute value among (Slot0+Slot1), (Slot1+Slot2), (Slot2Slot0) will
> correspond pretty well to the amount of energy at the desired frequency
> (note: there will be a little bumpiness since your sampling points are
> 60 degrees apart, and you will pick up some 5th and 7th harmonics though
> this method will filter out the 2nd and 3rd and all multiples thereof.
> Running this algorithm on a PC yielded pretty good results, and it would
> seem it should run decently on a 16MHz PIC (looking for 8 tones, sampling
> rate of about 8KHz).
>
> What do people think of this as an approach?
>
I may have missed something, but what is sampling at 6 points per cycle
times 14 cycles gaining you over my approach of sampling at 4 points
per cycle times 10 cycles?
With DTMF, I wouldn't think that one would have to worry too much about
picking up spurious harmonics, since the harmonics will not overlap
until over the 4th harmonic which is high enough to be attenuated by
the telecom network.
Regards,
SJH
Canberra, Australia
1996\06\25@125905
by
Scott Dattalo
John Payson wrote:
> <snip>
> andlw $1C
> Boing:
> addwf PC
>
> Phase0:
> movf Source,w
> addwf Slot0
> goto Gone
> Phase1:
> movf Source,w
> addwf Slot1
> goto Gone
<snip>
Maybe I'm missing something (I must admit I did not try running this program),
but isn't it true that ANDing W with $1c will produce 0,4,8,$C,$10,$14,$18, and
$1C? However, the _case statements_ are only separated by three instructions.
Also, how large is the variable FreqLow:Hi? If it is small, then it seems that
consecutive samples will be binned together. If it is large, then consecutive
samples will go to separte bins. Could you please clarify this?
Thanks
Scott
1996\06\25@173533
by
John Payson

>
> John Payson wrote:
> > <snip>
> > andlw $1C
> > Boing:
> > addwf PC
> >
> > Phase0:
> > movf Source,w
> > addwf Slot0
> > goto Gone
> > Phase1:
> > movf Source,w
> > addwf Slot1
> > goto Gone
>
> <snip>
>
> Maybe I'm missing something (I must admit I did not try running this program),
> but isn't it true that ANDing W with $1c will produce 0,4,8,$C,$10,$14,$18,
and
> $1C? However, the _case statements_ are only separated by three instructions.
Oops... :) Well, I did say 'something like...'. Also, to be useful each
slot should probably hold 16 bits rather than 8 (which also slows things
down). Instead of AND'ing with $1C it would probably be better to AND with
$38; this would allow room to do a 16bit ADD and a Goto after each phase
spot.
> Also, how large is the variable FreqLow:Hi? If it is small, then it seems that
> consecutive samples will be binned together. If it is large, then consecutive
> samples will go to separte bins. Could you please clarify this?
Assuming we spread the movwf/add thingies 8 cycles apart so the phase went
$0000$2FFF, FreqHi:FreqLo should be 12288*Freq/SampRate where Freq is the
desired detection frequency in Hz and SampRate is the input signal sampling
rate (also in Hz). Assuming code is put in for the cases where PhaseHi & $38
is $30 or $38, the highest permissible FreqHi:FreqLow value would be $10:$00
which would correspond to a frequency of SampRate/3.
1996\06\25@175625
by
John Payson

> > From: John Payson <.....supercatKILLspam@spam@MCS.COM>
> > Fourteen cycles per frequency per sample to produce 3 buckets; the largest
> > absolute value among (Slot0+Slot1), (Slot1+Slot2), (Slot2Slot0) will
> > correspond pretty well to the amount of energy at the desired frequency
>
> I may have missed something, but what is sampling at 6 points per cycle
> times 14 cycles gaining you over my approach of sampling at 4 points
> per cycle times 10 cycles?
I would have to look at your code again, but all the DTMFstuff I remember
seeing here required doing a multiply for each sample as part of the DFT;
on a PIC such multiplies are somewhat expensive. While it would be possible
to only take 4 suitablytimed samples each wave and assume the cosine and
sine terms at the desired frequency are (s2s0) and (s3s1), this would be
highly succeptible to all odd harmonics (including the third). By contrast,
taking six samples each wave provides effective cancelation of the second,
third, fourth, and sixth harmonics.
1996\06\25@215754
by
Steve Hardy

{Quote hidden}> From: John Payson <
supercatKILLspamMCS.COM>
>
> > > From: John Payson <
.....supercatKILLspam.....MCS.COM>
>
> > > Fourteen cycles per frequency per sample to produce 3 buckets; the largest
> > > absolute value among (Slot0+Slot1), (Slot1+Slot2), (Slot2Slot0) will
> > > correspond pretty well to the amount of energy at the desired frequency
> >
> > From SJH <
EraseMEhardyspam_OUTTakeThisOuTsweng.stortek.com>
> > I may have missed something, but what is sampling at 6 points per cycle
> > times 14 cycles gaining you over my approach of sampling at 4 points
> > per cycle times 10 cycles?
>
>
> I would have to look at your code again, but all the DTMFstuff I remember
> seeing here required doing a multiply for each sample as part of the DFT;
> on a PIC such multiplies are somewhat expensive. While it would be possible
> to only take 4 suitablytimed samples each wave and assume the cosine and
> sine terms at the desired frequency are (s2s0) and (s3s1), this would be
> highly succeptible to all odd harmonics (including the third). By contrast,
> taking six samples each wave provides effective cancelation of the second,
> third, fourth, and sixth harmonics.
>
No, the multiply was required only for generation. My decoding routine
requires only 16bit addition/subtraction as does your routine.
Regarding harmonics: Harmonics greater than 4th may be effectively
ignored because of the 3KHz bandwidth of the PSTN (Public Switched
Telephone Network). Other harmonics are only a problem if they are 1)
of sufficient intensity 2) aliased onto a frequency within 2% of the
tone being sampled. Take the lowest tone, 697Hz, as an example. If
sampled at 4 times this, the nyquist frequency is 2*697 = 1394Hz. Find
where the harmonics of the other tones are aliased to, and see if any
get aliased to 697Hz +/ 2%. Apply the same logic to the other tones.
Although I don't have time to do the arithmetic, I don't think its a
problem.
1996\06\26@002300
by
John Payson

> No, the multiply was required only for generation. My decoding routine
> requires only 16bit addition/subtraction as does your routine.
>
> Regarding harmonics: Harmonics greater than 4th may be effectively
> ignored because of the 3KHz bandwidth of the PSTN (Public Switched
> Telephone Network). Other harmonics are only a problem if they are 1)
> of sufficient intensity 2) aliased onto a frequency within 2% of the
> tone being sampled. Take the lowest tone, 697Hz, as an example. If
> sampled at 4 times this, the nyquist frequency is 2*697 = 1394Hz. Find
> where the harmonics of the other tones are aliased to, and see if any
> get aliased to 697Hz +/ 2%. Apply the same logic to the other tones.
> Although I don't have time to do the arithmetic, I don't think its a
> problem.
Well, 2091Hz is well within the PSTN bandwidth and would alias very nicely
to 697Hz. If you use seperate filters/ADCs for your high and low band inp
uts, this may not be an issue (since your lowband filter could probably
take out 2091Hz pretty well) but if not, the aliasing here could be a
problem. In the method I'm proposing, by contrast, your lowest alias is
at 5x, which would be 3485Hzhigh enough to filter even if the telco doesn't.
Thinking about it, it might make sense to do a 6x sample for the lower tones
and a 4x sample for the upper ones. The 4x sample is a little easier to
do, probably, and the upper tones are high enough that you shouldn't get even
any 3rd harmonic signal. How does that sound for an approach?
More... (looser matching)
 Last day of these posts
 In 1996
, 1997 only
 Today
 New search...