Create voltage function that varies with time

Greetings Experts,

I am attempting to generate a signal from an equation that varies with time. I am very new to arduino so I am probably missing something obvious. The code is below. I have tried using the current function in the void loop section of my code to alter based on time.

const int analogOutPin = DAC0;  // Analog input pin that the potentiometer is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)
int duration = 1000;
int start = 0;
double current = 0.0;
double voltage = 3;
double A = 1;            // Amplitude
double offset = 2;
double tf = 500;         //# of sec
double phi = 1;          //Phase change
double pi = 3.14159;
int fi = 2;           //frequency initial
int ff = 0.1;         // frequency final
double F = ff/fi;
double N = N=log(ff/fi)/log(2);
double R = N/500;
//double omega = 2*3.14159*0.1/1000;
double P = 0;
double Z = 0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  start = millis();
}

void loop() {

  current = double(millis() - start;
  P = pow(2, R*current));
  voltage = ((-A*sin(2*pi*((fi*(-1+P)))/(R*log(2)))-phi));
  outputValue = int((255.0/5.0)*voltage);
  analogWrite(analogOutPin, outputValue);

  Serial.print("\t output = ");
  Serial.println(outputValue);
  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:
  delay(2);
}

// wait 2 milliseconds before the next loop // for the analog-to-digital converter to settle // after the last reading:

?

Is this a Due question?

You haven't mentioned an actual question or problem you are trying to solve, but in this bit:

ejin:   current = double(millis() - start;   P = pow(2, R*current));   voltage = ((-A*sin(2*pi*((fi*(-1+P)))/(R*log(2)))-phi));

It looks like P is the absolute phase angle of a sine wave of geometrically increasing frequency over time. My observation is that P will get quite enormous quite quickly. Within 1 minute P ~= 2^120. within 2 mins P is above the range of float.

double N = N=log(ff/fi)/log(2);

The WTF light came on.

  current = double(millis() - start;

That statement won't even compile.

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:

Why? You are not using the analog to digital converted. analogWrite() is a poor name for the function, since it has nothing to do with analog pins or analog signals.

Thanks to everyone's help I found a few obvious errors. By getting rid of those, I managed to get my function to vary with time! However, I now think that there is an error in my code that is causing the equation I am using to be read incorrectly. My goal is to generate a triangle wave that starts at an initial frequency and ends at a final frequency over a set period of time. When I graph my equation in matlab, it works perfectly. However, when I type in what seems like the same equation in Arduino, it doesn't give me a triangle wave.

EQUATION: Voltage = (-A*sin(2*pi*((fi*(-1+2^(R*t)))/(R*log(2)))))

I suspect I am doing something wrong with the power function of my code but there could be other causes as well. I have posted the code below to show what I have so far.

Thank you again for all the help!

const int analogOutPin = DAC0;  // Analog input pin that the potentiometer is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)
int duration = 1000;
int start = 0;
double current = 0.0;
double voltage = 5;
double t = 0;
double A = 2;            // Amplitude
double offset = 2;
double tf = 500;         //# of sec
double pi = 3.14159;
double fi = 2;           //frequency initial
double ff = 0.1;         // frequency final
double F = (ff/fi);
double N = ((log(ff/fi))/(log(2)));
double R = (N/500);
double P = 0.0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  start = millis();
}

void loop() {
  t = (millis() - start);
  P = double(pow(2, (R*(t/1000))));
  voltage = (-A*sin(2*pi*((2*(-1+(P)))/(R*log(2)))));
  outputValue = int((255.0/5.0)*voltage);
  analogWrite(analogOutPin, outputValue);
}
  voltage = (-A*sin(2*pi*((2*(-1+(P)))/(R*log(2)))));

and

EQUATION: Voltage = (-Asin(2pi*((fi*(-1+2^(Rt)))/(Rlog(2)))))

don’t look the same to me.

Sorry for any discrepancies. The original equation that correctly generated my waveform in Matlab was EQUATION: Voltage = (-A*sin(2*pi*((fi*(-1+2^(R*t)))/(R*log(2))))) I took the same equation and tried to use it in arduino but arduino doesn’t accept the ‘^’ symbol. I used the arduino code ‘pow(2, R*t/1000)’ instead in my equation to replace the highlighted section. The t in my matlab equation was in seconds but in arduino is in milliseconds which is why it is divided by 1000.

The only other difference: -A*sin(2*pi*((2*(-1+P)))/(R*log(2))))); Here, I plugged in 2 for fi when I was trying to figure out why my equation was generating a different waveform that the one I had anticipated. This isn’t what is causing the issue though.

My best guess is that I have misused the power function in arduino which is why the waveform is different. I’m pretty new to using Arduino though so there could also be other things that are causing issues.

When I graph my equation in matlab, it works perfectly.

In that case, post your entire matlab code here so that it can be verified and then it might be worthwhile trying to figure out where you are going wrong.

Pete

Matlab Code:

t=.1:.001:510;
tf=500;
pi=3.14159;
fi=2; %frequency initial
ff=.1; %frequency final
F=ff/fi;
A=1; %amplitude
N=log(ff/fi)/log(2);
R=N/500;
Y=(-A*sin(2*pi*((fi*(-1+2.^(R*t)))/(R*log(2))))).*(.01<=t&t<=500)+(-A*sin(2*pi*((fi*(-1+2.^(R*500)))/(R*log(2)))-phi)).*(t>500);
plot(t,Y)

Your Matlab code has a syntax error.
I fixed it and, as I suspected, your equation does not generate a triangle wave - it generates a sine wave. So please explain how “in matlab, it works perfectly”.

Pete

Thanks for pointing that out. Here is the corrected waveform that works in Matlab.
Either way though, my sin or triangle wave in Matlab creates a different waveform in Arduino. I’m trying to figure out where I’m going wrong.

t=.1:.001:510;
tf=500;
pi=3.14159;
fi=2; %frequency initial
ff=.1; %frequency final
F=ff/fi;
A=1; %amplitude
N=log(ff/fi)/log(2);
R=N/500;
Y=(sin(2*pi*((fi*(-1+2.^(R*t)))/(R*log(2)))));
Z=A*asin(Y).*(.01<=t&t<=500)+(-A*sin(2*pi*((fi*(-1+2.^(R*500)))/(R*log(2)))-phi)).*(t>500);
plot(t,Z)

That produces the same error.

Pete

I don't understand what error you mean. When run the exact code I posted it graphs a triangle waveform.

What is phi? When I change that to pi, this version does plot a triangle. Now that you have an equation that works, you can start converting it to work on an Arduino. Start by working the correct equation into the Arduino code you had before and then post it here.

Pete

Thanks for pointing that out. Phi represented phase shift but it isn't necessary for this application so I've taken it out.

My code is below. Overall, things are much better but the waveform still isn't what I would expect. I'm getting a sawtooth wave that switches direction every 6th cycle. This same pattern continues as the frequency decreases so I think I haven't converted my equation correctly? I've tried adding in parenthesis but that didn't help much.

const int analogOutPin = DAC0;  // Analog input pin that the potentiometer is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)
int duration = 1000;
int start = 0;
double current = 0.0;
double voltage = 1;
double t = 0;
double A = 2;            // Amplitude
double offset = 1;
double tf = 500;         //# of sec
double pi = 3.14159;
double fi = 2;           //frequency initial
double ff = 0.1;         // frequency final
double F = (ff/fi);
double N = ((log(ff/fi))/(log(2)));
double R = (N/500);
double P = 0.0;
double X = 0.0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  start = millis();
}

void loop() {
  t = (millis() - start);
  P = double(pow(2, (R*((t)/1000))));
  X = (sin(2*pi*((fi*(-1+(P)))/(R*log(2)))));
  voltage= (-A)*(asin(X));
  outputValue = int((255.0/1)*voltage);
  analogWrite(analogOutPin, outputValue);
}

It is likely that adding some debugging output to show what's happening in your calcs would be of value. Put some Serial.println()s in there to dump out the values so you can see what is actually calculated vs what your intent is.

  voltage= (-A)*(asin(X));

Why is voltage the arc-sin of X? I thought you wanted a sine-wave to come out?

I have just started looking at your code but a few things spring to mind: - which Arduino are you using? - This line is confusing:

const int analogOutPin = DAC0;  // Analog input pin that the potentiometer is attached to

obviously you are using it as an output, so why the comment? - on most Arduinos, 'double' is the same as 'float' so if you're expecting/need double precision, you aren't getting it.

More later Pete @gardner. The asin is correct in this case. It is generating a triangle wave.

P.S. you have a lot of variables there that don't seem to do much. For example, you declare A to be 2 and then use it once.

Pete

Your code assumes that ‘t’ will increase every time through the loop() function, but that doesn’t happen. The loop() function is executed as fast as possible which means that on several consecutive passes through loop(), ‘t’ will be the same value. Your loop needs to execute only once per millisecond (or whatever sampling rate you want to use).
Change the first line of loop() to this:

  while(millis() - start < SAMPLE_INTERVAL);
  t = millis() - start;
  start = millis();

and add this at the top of the file:

// Number of milliseconds between samples
#define SAMPLE_INTERVAL 1

Your matlab code plots the function for t=0.1 to t=500 seconds and then for another 10 seconds it plots a different function (which appears to be just DC) and then it stops. The Arduino will keep going after that time so you should decide what it should do after 500 seconds:

  • continue to reduce the output frequency of the triangle wave?
  • output the fixed frequency defined by ‘ff’?
  • don’t care because 500 seconds is long enough
  • or …?

Pete

el_supremo: @gardner. The asin is correct in this case. It is generating a triangle wave.

But in the posting I replied to, the O/P said

ejin: the waveform still isn't what I would expect. I'm getting a sawtooth wave that switches direction every 6th cycle.

He's never really clarified what he WANTs, so I took this to mean he doesn't want the sawtooth. Still no news what board this is trying to run on. I'm starting to lose interest anyway.