# Generating Sine Waves

A project log for An Old Fashion Acoustic Modem for the iPhone

My son recently returned from a holiday in China. His biggest complaint was the blocking of FaceBook!

## Generating Sine Waves

Who thought this would be hard?

I have spent a week trying to work this out. Here is the pseudo code so far:

Calculate the Mark and Space ratios:

• A= int(Fsample/Fmark+0.5)
• B= int(Fsample/Fpace+0.5)

Find the lowest common multiple N of A and B:

• N = LCM(A,B)

Where N is the sine (iSin[]) lookup array size.

To generated the sine wave step through the array using Phase:

• Phase=Phase +N/A, for the mark frequency

Note: B=N/A

So:

• Phase=Phase +B

or

• Phase=Phase +A, for the space frequency

The Phase needs to roll back to the start on overflow:

• if (Phase>=N) then Phase=Phase-N

The sine wave is:

• Sine=iSin[Phase]

To reduce the sine look up array size by a constant (C) we can divide the Phase by the constant (C):

• Sine=iSin[Phase/C]

or

• Sine=iSin[Phase>>M], as the maths is much faster

The sample frequency is restricted and depends on the Arduino clock (16 MHz), the pre-scaler (timer dependent) and the PWM type.

So I have spent a day trying different combinations of Fsample and M to minimise the array size and the error. Nothing great found!

---

I thinks I need help (at least my partner thinks so)!

I found a paper (http://www.analog.com/static/imported-files/tutorials/MT-085.pdf) that although a bit complicated, shows a way out of this mess:

Set N to a power of 2, say 65536 (an unsigned int):

• B=65536*Fmark/Fsample
• A=65536*Fspace/Fsample

Then phase is:

• Phase=Phase+B

or

• Phase=Phase+A

Choose a sine array size that is a power of 2 , say 64.

• Sine=iSin[Phase>>(16-6)]

or

• Sine=iSin[Phase>>10]

Phase rollover is implicit with an unsigned int.

Here is the code for the ISR:

```// TRANSMIT:
//   Phase Correct PWM frequency 31250 Hz
//   Originate modem Mark  frequency    1270 Hz (=2244)
//   Originate modem Space frequency    1070 Hz (=2663)
//   Answer modem    Mark  frequency    2225 Hz (=4666)
//   Answer modem    Space frequency    2025 Hz (=4247)
const byte iSin[64] = {
128,140,153,165,177,188,199,209,
218,226,234,240,245,250,253,254,
255,254,253,250,245,240,234,226,
218,209,199,188,177,165,153,140,
128,116,103, 91, 79, 68, 57, 47,
38, 30, 22, 16, 11,  6,  3,  2,
1,  2,  3,  6, 11, 16, 22, 30,
38, 47, 57, 68, 79, 91,103,116
};

volatile byte DataOut=0;
ISR(TIMER2_OVF_vect) {
static unsigned int phase=0;

OCR2A = iSin[(phase>>10)]; // Output on D11
if (true) { // Set true for Originate Modem
if (DataOut==0) {
phase+=2244;             // Fspace (Originate modem)
} else {
phase+=2663;             // Fmark (Originate modem)
}
} else {
if (DataOut==0) {
} else {
}
}
}```

Now is that not sweet code!

---

I used Phase Correct PWM instead of Fast PWM as it generates less interrupts rather than the phase correct feature.

Final note, don't put the iSin array inside the ISR like I did! It took ages to workout why the PWM was off frequency!

AlanX