Close

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!

agpcooperagp.cooper 02/09/2017 at 23:550 Comments

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:

Find the lowest common multiple N of A and B:

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

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

Note: B=N/A

So:

or

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

The sine wave is:

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

or

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):

Then phase is:

or

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

or

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) {
      phase+=4247;             // Fspace (Answer modem)
    } else {
      phase+=4666;             // Fmark (Answer modem)
    }      
  }
}

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

Discussions