Reading a Sinusoidal Signal and observing serial values

Hello everyone. :slight_smile:

Im working on reading a sinusoidal signal having (1V amplitude and 0.75 offset) and observing the serial values on the serial monitor. I have a separate program in Labview to graph this serial data back into its original waveform shape. I want to read sinusoidal signals starting from 10Hz up to 200Hz. I have used the following code:

int potPin = 0; // select the input pin
int val = 0; // variable to store the value coming from the function generator

void setup()
{
Serial.begin(19200); // opens serial port, sets data rate to 9600 bps
}

void loop() {
val = analogRead(potPin); // read the value from the function generator
Serial.println(val);
delay(0.5); //Sampling rate for the signal
}

At 10Hz, the serial values are alright, for example 202, 208, 214,220.. which results in an alright sinusoid being graphed by Labview.

However, as I increase the frequency of the sinusoid to 80Hz, 100Hz, 150Hz.. The serial values no longer accurately represent the sinusoidal signal being inputted to the arduino input pin.. for example 234,330,400,600..

I have tried decreasing delay at the end of the code to increase the sampling rate, however below 0.5 serial data can no longer be seen when COM port is open.

Is there any programming method I can use to to accurately sample the sinusoidal signal and observe more precise values on the serial monitor? I have tried using an array to 'force' 500 data points to be read however the problem still occurs.

int potPin = 0; // select the input pin for the potentiometer
int ctpinvalue[500]; // variable to store the value coming from the sensor
int i = 0;

void setup()
{
Serial.begin(19200); // opens serial port, sets data rate to 9600 bps
}

void loop()
{
for (i=0; i<=499; i = i+1) // reads 200 values for waveform
{
ctpinvalue = analogRead(potPin); // Pin 0 Current transformer
_ Serial.println(ctpinvalue*);_
_
delay(0.5);_
_
} // end of count loop*_

}
Appreciate any help from all of you

Jazlan:
void loop() {
val = analogRead(potPin); // read the value from the function generator
Serial.println(val);
delay(0.5); //Sampling rate for the signal
}

At 10Hz, the serial values are alright, for example 202, 208, 214,220.. which results in an alright sinusoid being graphed by Labview.

However, as I increase the frequency of the sinusoid to 80Hz, 100Hz, 150Hz. The serial values no longer accurately represent the sinusoidal signal ...

150 Hz means you need to sample every 1/300 seconds which is once every 3.333mS (3333 uS).

For a start, you have introduced a 0.5 mS delay (500 uS) which is hardly going to help.

Second, by my calculations, printing the value will take 347 uS (to print 3 numbers plus a newline at 115200 baud) so that is an extra delay.

On top of that the analogRead takes 100 uS.

So your reading time, delay, and printing time, is taking over 1 mS. Whilst this doesn't totally explain your problems at 100 Hz, I don't think they are helping.

Try to remove the delay, and collect the data into an array, and then output the array after the sampling is done.

Plus, sampling at the Nyquist frequency is only going to give you the presence of that frequency, to get nice slopes (ie. up and down the wave) you would need to sample somewhat more often.

Oh I see you did some of that:

  Serial.begin(19200);   // opens serial port, sets data rate to 9600 bps

...

  for (i=0; i<=499; i = i+1) // reads 200 values for waveform

You need to fix your comments, they are confusing.

Is there any programming method I can use to to accurately sample the sinusoidal signal and observe more precise values on the serial monitor? I have tried using an array to 'force' 500 data points to be read however the problem still occurs.

You are still using the delay and the Serial.println, which is where I think the major problem is.

More like:

  for (i=0; i < 500; i++) // reads 500 values for waveform
  {   
      ctpinvalue [ i ] = analogRead(potPin); // Pin 0 Current transformer
  } // end of count loop

// now loop again and display the results

 for (i = 0; i < 500; i++) // display 500 values 
  {   
      Serial.println (ctpinvalue [ i ]);
  } // end of loop

I have tried decreasing delay at the end of the code to increase the sampling rate, however below 0.5 serial data can no longer be seen when COM port is open.

Huh? Anyway, put the delay in the second loop, it won't matter there.

For a start, you have introduced a 0.5 mS delay (500 uS) which is hardly going to help.

Worse than that, OP introduced a 0 mS delay, since the delay() function takes an integer argument. The delay() function exhibits unpredictable results when called with a value of 0.

I almost said something about that, but wasn't sure. Finding the code for delay isn't the easiest thing in the world. I found 8 copies of delay.h in my hardware subdirectories. They had stuff like this in them:

void
_delay_us(double __us)
...

Now I know that is not delay, but some versions of delay seem to take a double argument.

Thank you very much for the valueble feedback.

As suggested, I have changed parts of the previous code i posted to include two loops, one loop to read data into the array and another loop to display the serial values stored in the array here is the latest version:

int potPin = 0; // Select the input pin for the potentiometer
int ctpinvalue[300]; // Array to store the value coming from function generator
int i = 0; //counter

void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps

}
void loop()
{
for (i=0; i < 299; i++) // reads 300 values for waveform
{
ctpinvalue [ i ] = analogRead(potPin); //Pin 0 Current transformer

} // end of count loop

// now loop again and display the results

for (i = 0; i < 299; i++) // display 300 values
{
Serial.println (ctpinvalue [ i ]);

} // end of loop
delay (1);
}

Even at higher frequencies such as 180Hz and 200Hz, the serial values are 'smooth', from the serial monitor, Im getting these serial values (at 150Hz)

386
391
397
401
406
410
414
418
421
424
428
431
433
436
439
440

I have a labview program which reads these serial data from the COM part and converts it back to a sinusoidal waveform. However the sinusoidal signal has 'discontinuities'. 'These 'discontinuities' occur regardless of the frequency of the sinusoidal. I have attached images of both 'good sinusoids' and 'poor sinusoids'

Is there any programming in arduino i can do to ensure getting a smooth sinusoidal signal? Would really appreciate your feedback.

Thanks!

I forget to mention, the last 'good sinusoid' only smoothly alternates for a few seconds, before becoming 'discontinuous' and becoming smooth back again. 'Discontinuous' is probably not the correct term to describe the sinusoids but im not sure how to describe them :slight_smile:

I'm not familiar with Labview, but I suspect that your sample of 300 is too small. During the pause while it gathers another 300 the program might be generating this discontinuity.

Try increasing 300 to (say) 600, and see if that alters the behaviour.

And to save effort, start using defines, eg.

#define POINTS 600

int ctpinvalue[POINTS]; // Array to store the value coming from function generator

...

for (i = 0; i < POINTS; i++) // reads POINTS values for waveform

...

for (i = 0; i < POINTS; i++) // display POINTS values

Then to experiment, you only have to change one line, not lots of them.

PaulS:

The delay() function exhibits unpredictable results when called with a value of 0.

No, this is wrong. Calling delay() with a zero argument is perfectly valid and predictable (although it may have limited practical purpose). Actual delay will be zero milliseconds plus the overhead of the function call.

Actual delay will be zero milliseconds plus the overhead of the function call

...plus the call to "micros()"

By any chance do these discontiunuities occure every 300 data points?

for (i=0; i < 299; i++) // reads 300 values for waveform

sp. "reads 299 values for waveform"

Thanks for the replies :slight_smile:

I have changed the loop counter,'i' to 800 in order to represent more points of the sinusoid. However I am still facing this 'discontinuity' at every 800th point. Even when I changed the loop counter to 200, 300 and 500, there is still this discontinuity at every 200th, 300th and 500th point. These are the values appearing at the serial monitor (left column loop counter, right column serial values).

788 338
789 334
790 330
791 326
792 322
793 318
794 313
795 310
796 304
797 300
798 295
799 289
0 135
1 137
2 141
3 144
4 148
5 150
6 153
7 157
8 160
9 164
10 169

The counter values from 788 to 799 (and also 0 to 10) represent the smooth and good part of the sinusoidal signal. However the discontinuity occurs at the 'transition' point from 799 to 0.

Is there any programming method to make this 'transition' smooth just like the rest of the signal?

This is the code I have used:

#define POINTS 800
int potPin = 0;    // Select the input pin for function generator.
int ctpinvalue[POINTS]; // Array to store the value coming from function generator
int i = 0; //counter

void setup()
{
  Serial.begin(19200); // opens serial port, sets data rate to 19200 bps

}
void loop()
{
for (i=0; i < POINTS; i++) // reads 800 values from waveform
  {   
     ctpinvalue [ i ] = analogRead(potPin); //Pin 0 Current transformer
     
  } // end of count loop
  
// now loop again and display the results

for (i = 0; i < POINTS; i++) // display 800 values 
  {   
      Serial.print(i);
      Serial.print(" ");
      Serial.print(ctpinvalue [ i ]);
      Serial.println("");
      
  } // end of loop
  delay(1);
}

You expect a discontinuity, because you are taking readings, and then you pause to transmit them.

I'm not sure there is an easy way around that, perhaps using an interrupt to take readings at a fixed rate, but I'm not sure about that.

Thanks Sir.

I came across this article: http://sites.google.com/site/measuringstuff/the-arduino

I will try out the code described on this page and see how it goes

For example, if i want to measure the sine wave for just 10 seconds instead of continuous measurement, Is there code i can write in order to read 10 seconds of sine wave data into an array (lets say value[800]) and then use another loop placed outside the main loop to write these 800 values to the serial port?

That way I hope to avoid the discontinuity problem. I tried using two loops, one loop to read the sine wave values into an array and the other loop to write these array values to the serial port but my method is incorrect and returns errors because the second for loop is not placed within the main loop (code attached) .

#define POINTS 800 //Number of sine wave samples.
int value[POINTS];   // variable to store sine wave serial values.
int i=0;

void setup() 
{
 Serial.begin(9600) ;
}


void loop() //loop to read sine values into array
{ 
 for (i=0;i<POINTS;i++)
{
  value[i]=analogRead(0);
} 

}

for (i=0;i<POINTS;i++) //loop to send serial sine values to the serial monitor
{
  Serial.println(value[i]);
}

For example, if i want to measure the sine wave for just 10 seconds instead of continuous measurement, Is there code i can write in order to read 10 seconds of sine wave data into an array (lets say value[800])

You loop takes maybe 120microseconds, including the analogRead.
There is no way you can store data at that rate for ten seconds.
With an 800 element array, you'd barely make 100 milliseconds.

In order to transmit one byte at 9600 baud you need 1/960 of a second (as that byte takes 10 bits, including the start and stop bit). So, each byte takes 0.00104167 seconds. To transmit a 3-byte number followed by a newline (which is 4 bytes) you will need 0.004167 seconds per number. Now for 800 numbers that will take 3.33 seconds. So there is your discontinuity.

I don't know if you can do much about that, and I think even oscilloscopes take a sample, and then display it. The very expensive ones can probably sample and display more or less continuously, but we are talking about more expensive than a $6 processor here. A lot more. Try $10000.

As AWOL points out, you can take a larger sample, but you are constrained by the amount of memory in the processor. The Atmega328 has 2Kb of RAM, which would hold at most 1000 samples of 2 bytes each (ints in other words).

But to sample a 200 Hz signal you need at the very least to be sampling 400 times a second, probably a lot more if you want to tell the difference between a square wave and a sine wave. So one second of samples at 200 Hz would be about the most you could hope for.

You could get fancy, for extra credit. Get something like the Amani CPLD, and some SRAM chips (maybe 256 Kb worth) and stream your samples straight into the SRAM. It would be quite a lot of work. But without it I don't see you getting much better results than you currently are.

I got a Kemani CPLD "key" - that runs at 32 Mhz and would be capable of handling more samples, coupled with some suitable RAM chips, but this isn't for beginners, honestly. In fact, I haven't done it myself (not that that proves much). :stuck_out_tongue:

http://majolsurf.net/wordpress/?page_id=1302