Generate sin wave using pwm?

int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,255,253,250,244,237,228,217,204,191,176,160,144,127}; // array of PWM duty values for 8-bit timer - sine function

the value up there is use to generate sin wave from 0 to 255, but how to calculate those values exactly, btw the author said he specifically use 48 value too

Use the sine function stepping from 0 to 360, step 360/48. Know to convert degrees to radians.

The sinus function will move between -1 and 1 when you move around the circle.

You want to be between 0 and 255
so it means you need to translate and scale

sin(x) + 1 will be between 0 and 2
127*(sin(x) + 1) will be between 0 and 254

looking at your values

int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,255,253,250,244,237,228,217,204,191,176,160,144,127}; // array of PWM duty values for 8-bit timer - sine function

it looks like your sine wave is starting from the mid value (127) and by decreasing whereas sin(0) is 0 and as the angle increases, so does the sinus (until you reach 90°) ➜ so the values you got are not taken for a period starting at 0° but more at 180°

the formula would be to take 48 samples between 180° and 540° (the red portion of the sinus curve) for the formula

y = 127 * (sin(x° * PI / 180°) + 1)

(the sinus function uses radians not degrees)

In simple terms:
Values = 127 - [127sin (2π*t/48)] where t = 0,1,2,3,4 …. 47 for the 48 samples

This code will generate the values shown in post #1.

int pwmSin[48];

void setup() {
  Serial.begin(115200);

  for (int i = 0; i <= 48; i++) {
    pwmSin[i] = (127.5 * (1 - (sin(2 * PI * i / 48)))) ;
    Serial.println(pwmSin[i]);
  }
}

void loop() {
}

Edit:
Adjusted the equation to give improved correlation with the data from the original post.

A sine wave consists of four equal pieces, so your array can be reduced to 1/4 of the size.
Leo..

1 Like

Or, using repeated quarter wave values, you could get 4x the resolution using your 48 element array.

I've added to the code that I posted in reply #5.

The code originally just generated the array that FunnySunny was asking about.
Now I have used the array to produce a sine wave using PWM, passed through a low pass filter.

int pwmSin[48];
int scopeTrig = 12;
int outputPin = 11;
int i = 0;

unsigned long previousMicros = 0;
unsigned long interval = 5000;

void setup() {
  Serial.begin(115200);
  pinMode(scopeTrig, OUTPUT);
  pinMode(outputPin, OUTPUT);

  for (int i = 0; i <= 48; i++) {
    pwmSin[i] = (127.5 * (1 - (sin(2 * PI * i / 48)))) ;
    Serial.println(pwmSin[i]);
  }
}

void loop() {

  unsigned long currentMicros = micros();
  if (currentMicros - previousMicros >= interval) {
    previousMicros = previousMicros + interval;
    analogWrite(outputPin, pwmSin[i]);
    Serial.println(pwmSin[i]);
    i++;
    if (i > 47) {
      PORTB = B00010000;      // trigger oscilloscope
      i = 0;
      PORTB = B00000000;
    }
  }
}

Here is the output on the Serial Plotter:

And on an oscilloscope:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.