Problem in analogic sine wave created with PWM

Hi people,
as the title says, I'm trying to create a simple sine wave (5 V peak-peak, wave 0-5 V), using a low pass filter (RC) to create it from the PWM. Unfortunately, since I have no more accurate ways to visualize the output (aka an oscilloscope), I'm using the serial plotter (specified also because I have a quite old computer, in case the following problem is due to something about computer -maybe high resources consumption? Even if I don't think so-). I use an Arduino Uno rev. 3.
This is my code:

const int echopin = A2;
const int sinepin = 6;
int i;

int sine256[] = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124};

void setup() {
  TCCR0B = TCCR0B & B11111000 | B00000001;
  Serial.begin(9600);
  pinMode(sinepin, OUTPUT);
  pinMode(echopin, INPUT);

}

void loop() {
  i = 0;
  for (i = 0; i < sizeof(sine256) - 1; i++) {
    analogWrite(sinepin,sine256[i]);
    //delay(1);
    int V = analogRead(echopin);
    Serial.println(V);
    //float Vfloat = (V/1023.0)*5.0;
    //Serial.println(Vfloat);
  }  

}

Quick notes about it:

  • I increased the frequency of the PWM, leaving the serial at its standard speed. I don't know if this combination affects somehow the output
  TCCR0B = TCCR0B & B11111000 | B00000001;
  Serial.begin(9600)
  • I know I used a quite long sinetable, I just wanted my output as smooth as possible (tried also with shorter arrays).
  • Some parts (delay and some prints) in the loop part are commented. Don't think it changes something, it was just to test various conditions (slower wave, and the print just rescales the output to 0-5 V).
    Important: A PNG image taken from the Serial Plotter should be attached to the post (if not, let me know because I'm still quite a newbie in using forums in general). In any case I'll also describe it: basically the wave works fine until the end of the period, and then it starts again after a short time in which the output seems more like a noise. Printing that for a longer period of time shows that the "noise part" substitutes part of the period of the wave, in some configuration (different R and C) it substitutes an entire period.
    Honestly, I have no idea in what can be wrong in the hardware configuration, but trying different ways on how to solve this one thing that made me realize that something is going wrong in the code itself: I tried to double the sine256 array, meaning that I defined all the values for two periods, in this way
int sine256[] = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124,127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124};

This made me think that the loop() function (or maybe just the for() loop) has some trouble when is starts again taking values from sine256[] (aka from the last value to the first again). I honestly don't understand why it does this and how to solve it, since it seems correct to me: it starts with i = 0, then executes the for() for every value of sine256[] and then it starts again, resetting i = 0 and doing the work again.
Do you see anything wrong with it? Thanks to everybody who will bright me up.

int sine256[]I don't know how many elements that array has, but it looks to me like it is using twice as much memory as it should.

First of all there is A sinus function built in to the core with which you should be able to get the most accurate result while using a lot less resources.
Since you are not using a lot of processing power i suspect you may be overrunning the Serial buffer at 9600 kbps.

has some trouble when is starts again taking values from sine256[] (aka from the last value to the first again).

How many 16-bit values have you declared ?

The following is a big problem:

  for (i = 0; i < sizeof(sine256) - 1; i++)

sizeof is the size of the array IN BYTES! This means you are indexing past the end of the array and reading whatever happens to be in memory there. Also you do not need to subtract 1.

You can do this:

for (i = 0; i < (sizeof(sine256)/sizeof(sine256[0])); i++)

OR you can change the sine256 array type to byte.

You can do this:

Code: [Select]

for (i = 0; i < (sizeof(sine256)/sizeof(sine256[0])); i++)

OR you can change the sine256 array type to byte.

This. It was quite hard for me to find the problem since I didn't think at all the problem was sizeof().
In any case, I found also another easy way to implement the code, which doesn't use any sinetable. I'll leave it here in case someone finds it useful.

const int echopin = A2;
const int sinepin = 6;
int i;

void setup() {
  TCCR0B = TCCR0B & B11111000 | B00000001;
  Serial.begin(9600);
  pinMode(sinepin, OUTPUT);
  pinMode(echopin, INPUT);

}

void loop() {
  i = 0;
  for (i = 0; i < 256; i += 1) {
    int sinloop = 127 + floor(127*sin(2*3.141*i/255));
    analogWrite(sinepin,sinloop);
    //delay(1);
    int V = analogRead(echopin);
    Serial.println(V);
    //float Vfloat = (V/1023.0)*5.0;
    //Serial.println(Vfloat);
  }

}

QUICK NOTE: Obviously someone who can code better than me can write this last code in a nicer way (even though the code is really small, but who knows), but essentially these solutions solve the concept behind the error.

In any case, I found also another easy way to implement the code, which doesn't use any sinetable greatly limit the performance of the code.

In any case, I found also another easy way to implement the code, which doesn't use any sinetable greatly limit the performance of the code.

Could you explain why?

Because floating point operations and trig functions are sloooow.
Putting a 100us analogRead in every iteration isn't helping either.

Because floating point operations and trig functions are sloooow.
Putting a 100us analogRead in every iteration isn't helping either.

Of course it all depends on which resource you want to use up, though admittedly a sinetable could be put in progmem.

Also, you only have to represent a quarter of a sine wave in that table, that is 64 entries, and still achieve the same resolution. This is because the sine wave is symmetric. For example, 90 to 180 degrees is simply 0 to 90 degrees, mirrored about a vertical axis at 90 degrees. 180 to 360 degrees is the same as 0 to 180 degrees mirrored about the horizontal axis.

ToddL1962:
sizeof is the size of the array IN BYTES!

Well spotted. That's OP's problem, producing exactly the result that you'd expect.

6v6gt:
Also, you only have to represent a quarter of a sine wave in that table, that is 64 entries, and still achieve the same resolution. This is because the sine wave is symmetric. For example, 90 to 180 degrees is simply 0 to 90 degrees, mirrored about a vertical axis at 90 degrees. 180 to 360 degrees is the same as 0 to 180 degrees mirrored about the horizontal axis.

This is really nice. I didn't think about that since my problem was elsewhere (in the end was because of sizeof() with the array), but now that it works with the sinetable I can think about improving it and making it more efficient (ex. variable frequency wave or a sine with both positive and negative outputs, with the appropriate circuit connected). (This is why I also tried to implement the code without any array. Probably less efficient, but more immediate for me to have a result that actually worked without any problem)