I'm building a synchronous rotating spark gap for a tesla coil. I have a working mcu (Kinetis K64F) driving a 230volt inverter board and it spins a 3 phase synchronous motor. The motor is a synchronous type itself, and the power I give to it must be as well: synchronized to the ac line. That's why I chose to build my own hardware. I can compare the performance of my running drive with a commercial one and I see that mine is underpowering the motor.

The store bought 3-phase inverter kicks the motor right up to speed, into a sync that slowly shifts to one side with no way to control it. Whereas my drive takes more than a minute of wobbling sound to come up to speed and then it's dead steady with the line frequency. I can move it to either side one degree at a time. That's what I need.

So I think it must be the data I'm sending to the 6 pwm channels. My naive solution for this has been to fill an array with sine values at startup. I make 2 positive half cycles like this:

int angle; double param; extern double hold[370];

 for (angle=0; angle<=179; angle++) {
   param  = 255 * sin (angle*PI/180);
   hold[angle] = param;      // fill first half of the array
   hold[angle+180] = param;  // fill second half with duplicate data

Then in a periodic interrupt I read out that array of sine values like this:

    if (angle1 < 180) { PWM1_SetRatio8(hold[angle1]); }
    else if (angle1 == 180) { PWM1_SetRatio8(0); }
    else if (angle1 > 180) { PWM2_SetRatio8(hold[angle1]); }
    if (angle1 >= 360) { angle1 = 0; PWM2_SetRatio8(0); }

    if (angle2 < 180) { PWM3_SetRatio8(hold[angle2]); }
    else if (angle2 == 180) { PWM3_SetRatio8(0); }
    else if (angle2 > 180) { PWM4_SetRatio8(hold[angle2]); }
    if (angle2 >= 360) { angle2 = 0; PWM4_SetRatio8(0); }

and so on for angle3, all of which are 120 degrees apart from each other. I see now that 180 per half cycle is too many so I divided it down to as low as 20 but with no change in the motor output.

I lock my 360 value internal array with a precision zero crossing pulse from the outside to keep them in sync.

So I read up about Magic Sine Waves and that sounds good. But I would have to rewrite a lot of code to use it, and I need to cover speeds from 58 to 62Hz which is what the power companies present me with. If I filled an array of Magic Sine values I think I would get crossover distortion when I shifted to the different line frequencies.

Then I read about triangle wave modulating the sine values and adding in some extra 3rd harmonic to get more power. That sounds like the way forward. I can read in a bunch of pre computed values at run time and away I go. Does anyone have experience with building a data set like this? Or can give me some pointers on how to do it?

  • \$\begingroup\$ If your MCU is fast enough then you can use a second timer to tweak the period of the first in order to keep to a single table. \$\endgroup\$ Jun 25, 2015 at 21:36
  • \$\begingroup\$ Is the PWM fast enough to need a 1 degree table accuracy? It's meaningless to refresh the output value more often than once per pulse. I would expect that you could get by with about 12 values, and still spin the motor on what will be basically just a square wave in each channel. \$\endgroup\$
    – tomnexus
    Jun 25, 2015 at 22:01
  • \$\begingroup\$ Yes, the cpu is at 120 Mhz so I have a lot of speed at my disposal. If I create a magic sine wave table for 60hz, then I can make small adjustments to the values "behind the scenes" so my output routine would always just toss out the freshest numbers without calculation. \$\endgroup\$
    – DonGarb
    Jun 26, 2015 at 1:50

2 Answers 2


I don't know if this helps at all but I did a little bit of work on this problem. Harmonic Elimination PWM It sounds exactly the same as magic sine waves. Just thinking off the top of my head, I'd precompute a combined single table of the switching times for all 3 phases of the waveform and use a single interrupt. As the interrupts happen, switch the particular channel then change the time until the next interrupt. To change frequency scale the data from the table. This shouldn't cause any problems with distortion over the frequency range you specify. It should be fairly accurate as well given you have a 120 MHz CPU. I had a basic version of this working on an ultrasonic transducer at 40 kHz on a 4 MHz AVR.

  • \$\begingroup\$ Thanks very much for that. I used blender to make an accurate drawing and went with triangle wave modulation. I set the length of half a sine wave cycle in blender units to the same number of microseconds that I need. That way I can read the pulse widths directly of the drawing in usecs. I know it's not the best solution but I have to get past this hurdle so I can get on to all the other problems! \$\endgroup\$
    – DonGarb
    Jun 29, 2015 at 12:45

I tried Grant's solution and the motor was even more underpowered! So I went back to my naive sine values and made this small change:

 for (angle=0; angle<=179; angle++) {
   param  = 265 * sin (angle*PI/180);
   if (param > 255) param = 255;
   hold[angle] = param;
   hold[angle+180] = param;

As you can see I multiplied the sine value by 265 instead of 255, and I clipped the values back down to 255 when they overflowed. This has the effect of amplifying and limiting the sine wave. When connected to the motor these values spin it up into sync in about 3 or 4 seconds. My meter measures an uncanny 120.0 volts between each of the 3 phases.

I still think this is a naive solution but it will do for now!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.