Baseline Correction Project for Arduino DUE

Hello,

First off, I want to declare that I'm not an electrical or computer engineer, so I apologize ahead of time if some of this doesn't make sense or if I get things wrong. I'm just trying to make light of a minor bump in an exciting adventure with Arduino and electronics to solve a dilemma.

I have been working at this project where we are trying to generate signals to input into some main hardware. I'd like one sinusoidal signal as the main input and one square signal as the clock signal. At the moment, I'm using a DAQ for this, but it’s a bulky and expensive device to transport. Thus, I instead plan to use an Arduino to generate these signals.

I have an Arduino DUE, which has two DAC ports that can output the sinusoidal and square signals. I've written a code (in Arduino IDE that I'd like to convert to MATLAB later but that's another step in the project) to generate these signals using the Arduino.

For the most part my program produces the signals as they should but there is an offset where I can adjust the frequency, amplitude, and sampling rate respectively for each signal. Although the problem is that these DAC ports have an output range of 0.55V-2.75V. I need to thus adjust this so that the signals oscillate around a baseline of 0. This gave rise to another problem though...I believe Arduino assumes that the baseline of the signals are at their troughs though, is this correct? If so, how do I go about correcting this baseline offset so that it meets my purpose for different combinations of amplitudes, offsets, etc.?

I've included my program for generating these signals as well as a LTspice design to potentially solve this problem as I believe I may need to make hardware to fix this software problem. It solves it but only in the perfect combination of amplitude and offset voltages delivered by the "DAC" port (noted with the SINE() or V3). Let me know also if it is just something with my program...that could very well be it as well.

Thank you so much for any help at all as I am a bit lost at this point,

Jesse

// Variables for configuring the sinusoidal signal
int amplitudeSinus_mV = 1000;  // peak-to-peak amplitude for sinus signal in millivolts, can be changed
int frequencySinus = 10;       // frequency of the sinus signal in Hz, can be changed

// Variables for square signal configuration
int amplitudeSquare_mV = 1000;  // amplitude for square signal in millivolts, can be changed
int frequencySquare = 10;       // frequency for square signal in Hz, can be changed

int samplingRate = 1000;  // Sampling rate in Hz

// Constants for DAC output voltage range
const float minVoltage_mV = 550;  // Minimum voltage output of DAC port in millivolts
const float maxVoltage_mV = 2750; // Maximum voltage output of DAC port in millivolts
const int dacResolution = 4095;   // Resolution of the DAC (12 bits)

// Constants and variables for timing
const float pi = 3.14159;
unsigned long previous_time_Sinus = 0;                     // Store the previous time (in microseconds) when the sinusoidal signal was generated
const unsigned long intervalSin = 1000000 / samplingRate;  // Calculates the interval between each sample of the sinusoidal signal based on the sampling rate in microseconds
unsigned long previous_time_Square = 0;                    // Stores the previous timestamp for square wave generation
unsigned long intervalSquare = 0;                          // Interval for the square signal in microseconds, will be calculated based on frequency

// Variables for the sinusoidal signal generation
int sampleIndex = 0;                                // Used to keep track of the current sample index for the sinusoidal signal generation
const int numSamples = 100;                         // Number of samples per cycle
int offset = (amplitudeSinus_mV * 0.9365) + 0.4487; // Adjust for the offset anomaly to keep the trough at 0.55V (550 mV)

void setup() {
  // Initialize the DAC pins
  analogWriteResolution(12);  // Set the DAC resolution to 12 bits

  // Calculate interval for the square signal
  intervalSquare = 1000000 / (2 * frequencySquare); // The interval is calculated to achieve the desired frequency. It's divided by 2 because the square wave has two states (high and low)
}

void loop() {
  // Convert peak-to-peak amplitude from mV to bits
  int amplitudeSinus_bits = calculatedacValue_Square(amplitudeSinus_mV);  // Converts amplitude from mV to DAC bits

  // Calculate the time period of one cycle based on the desired frequency
  int period = 1000000 / frequencySinus;  // Convert frequencySinus to period in microseconds

  // Generate the sinusoidal signal
  unsigned long current_time_Sinus = micros();                            // Get the current time in microseconds
  if (current_time_Sinus - previous_time_Sinus >= period / numSamples) {  // Check if the time interval for the next sample has passed
    previous_time_Sinus = current_time_Sinus;                             // Update the previous time to the current time
    float angle = 2 * pi * sampleIndex / numSamples;                      // Calculate the angle for the current sample
    int dacValue_Sinus = offset + amplitudeSinus_bits / 2 * sin(angle);   // Calculate the DAC value for the sinusoidal signal, adjusting peak-to-peak amplitude to fit DAC range
    analogWrite(DAC0, dacValue_Sinus);                                    // Write the DAC value to the DAC pin
    sampleIndex = (sampleIndex + 1) % numSamples;                         // Increment the sample index, wrapping around after one cycle
  }
  
  // Generate the square signal
  unsigned long current_time_Square = micros();                                                                                                         // Get the current time in microseconds
  if (current_time_Square - previous_time_Square >= intervalSquare) {                                                                                   // If statement to check if the interval has passed
    previous_time_Square = current_time_Square;                                                                                                         // Update the previous time to the current time

    // Calculate the DAC value for the square wave and toggle between high and low values
    int dacValue_Square = (current_time_Square / intervalSquare) % 2 == 0 ? calculatedacValue_Square(amplitudeSquare_mV) : calculatedacValue_Square(0);  // Toggle between high and low with 0 mV offset
    analogWrite(DAC1, dacValue_Square);                                                                                                                  // Write the calculated DAC value to the DAC1 pin
  }
}

// Function to calculate DAC value from amplitude in millivolts with offset correction for sinusoidal signal
int calculatedacValue_Sinus(float amplitudeSinus_mV) {
  float amplitudeFraction = amplitudeSinus_mV / (maxVoltage_mV - minVoltage_mV); // Calculate the fraction of the amplitude relative to the DAC range
  return amplitudeFraction * dacResolution;                                      // Convert the amplitude fraction to a DAC value based on the DAC resolution
}

// Function to calculate DAC value from amplitude in millivolts with offset correction for square signal
int calculatedacValue_Square(float amplitude_mV) {
  float amplitudeFraction = amplitude_mV / (maxVoltage_mV - minVoltage_mV); // Calculate the fraction of the amplitude relative to the DAC range
  return amplitudeFraction * dacResolution;                                 // Convert the amplitude fraction to a DAC value based on the DAC resolution
}

the DUE DACs output a signal between 0 and approximately 3.0volts
Use a capacitor to remove the DC offset
be careful, if you short the DAC output to ground you can destroy the DAC
in practice I tend to use ESP32 microcontrollers which also have two DACs and are a lot cheaper and have onboard WiFi, Bluetooth Classic and BLE

When you say "the DUE DACs output a signal between 0 and approximately 3.0volts" did I then read this wrong from the DUEs product description:

Really! You're telling me there is no need for an op-amp, just hooking up a capacitor in series or something with the DAC will do the trick?

I've never heard of a ESP32, sounds exciting, I'll give that a look.

Thank you a lot for your response by the way, I appreciate your help and guidance.

you are correct as this waveform shows (it is sometime since I used a DUE DAC)
image

using a series capacitor and resistive load is a simple way to remove DC offset, e.g. 10HZ waveform using 1000uF capacitor and 1Kohm resistor
image
clearly depends on what load you are driving

EDIT: running a 10Hz square wave thru a capacitor distorts it, e.g.
image

the program uses a lookup table

// Arduino Due using timer3 interrupts output sine to DAC and square wave to GPIO

#include <DueTimer.h>

// Arduino Due - use DAC0 and DAC1 to generate two sine waves

// from https://forum.arduino.cc/t/how-can-i-get-2-sin-waves-on-the-due-at-same-time-one-out-of-phase-with-other/217778/4

const uint16_t sinTable[] = {
  0x7ff,
  0x823,
  0x846,
  0x86a,
  0x88e,
  0x8b1,
  0x8d5,
  0x8f9,
  0x91c,
  0x93f,
  0x963,
  0x986,
  0x9a9,
  0x9cc,
  0x9ee,
  0xa11,
  0xa33,
  0xa56,
  0xa78,
  0xa9a,
  0xabb,
  0xadd,
  0xafe,
  0xb1f,
  0xb40,
  0xb60,
  0xb81,
  0xba1,
  0xbc0,
  0xbe0,
  0xbff,
  0xc1e,
  0xc3c,
  0xc5a,
  0xc78,
  0xc95,
  0xcb2,
  0xccf,
  0xcec,
  0xd08,
  0xd23,
  0xd3e,
  0xd59,
  0xd73,
  0xd8d,
  0xda7,
  0xdc0,
  0xdd8,
  0xdf1,
  0xe08,
  0xe1f,
  0xe36,
  0xe4c,
  0xe62,
  0xe77,
  0xe8c,
  0xea0,
  0xeb4,
  0xec7,
  0xeda,
  0xeec,
  0xefe,
  0xf0f,
  0xf1f,
  0xf2f,
  0xf3f,
  0xf4d,
  0xf5c,
  0xf69,
  0xf77,
  0xf83,
  0xf8f,
  0xf9a,
  0xfa5,
  0xfaf,
  0xfb9,
  0xfc2,
  0xfca,
  0xfd2,
  0xfd9,
  0xfdf,
  0xfe5,
  0xfeb,
  0xfef,
  0xff3,
  0xff7,
  0xffa,
  0xffc,
  0xffd,
  0xffe,
  0xfff,
  0xffe,
  0xffd,
  0xffc,
  0xffa,
  0xff7,
  0xff3,
  0xfef,
  0xfeb,
  0xfe5,
  0xfdf,
  0xfd9,
  0xfd2,
  0xfca,
  0xfc2,
  0xfb9,
  0xfaf,
  0xfa5,
  0xf9a,
  0xf8f,
  0xf83,
  0xf77,
  0xf69,
  0xf5c,
  0xf4d,
  0xf3f,
  0xf2f,
  0xf1f,
  0xf0f,
  0xefe,
  0xeec,
  0xeda,
  0xec7,
  0xeb4,
  0xea0,
  0xe8c,
  0xe77,
  0xe62,
  0xe4c,
  0xe36,
  0xe1f,
  0xe08,
  0xdf1,
  0xdd8,
  0xdc0,
  0xda7,
  0xd8d,
  0xd73,
  0xd59,
  0xd3e,
  0xd23,
  0xd08,
  0xcec,
  0xccf,
  0xcb2,
  0xc95,
  0xc78,
  0xc5a,
  0xc3c,
  0xc1e,
  0xbff,
  0xbe0,
  0xbc0,
  0xba1,
  0xb81,
  0xb60,
  0xb40,
  0xb1f,
  0xafe,
  0xadd,
  0xabb,
  0xa9a,
  0xa78,
  0xa56,
  0xa33,
  0xa11,
  0x9ee,
  0x9cc,
  0x9a9,
  0x986,
  0x963,
  0x93f,
  0x91c,
  0x8f9,
  0x8d5,
  0x8b1,
  0x88e,
  0x86a,
  0x846,
  0x823,
  0x7ff,
  0x7db,
  0x7b8,
  0x794,
  0x770,
  0x74d,
  0x729,
  0x705,
  0x6e2,
  0x6bf,
  0x69b,
  0x678,
  0x655,
  0x632,
  0x610,
  0x5ed,
  0x5cb,
  0x5a8,
  0x586,
  0x564,
  0x543,
  0x521,
  0x500,
  0x4df,
  0x4be,
  0x49e,
  0x47d,
  0x45d,
  0x43e,
  0x41e,
  0x3ff,
  0x3e0,
  0x3c2,
  0x3a4,
  0x386,
  0x369,
  0x34c,
  0x32f,
  0x312,
  0x2f6,
  0x2db,
  0x2c0,
  0x2a5,
  0x28b,
  0x271,
  0x257,
  0x23e,
  0x226,
  0x20d,
  0x1f6,
  0x1df,
  0x1c8,
  0x1b2,
  0x19c,
  0x187,
  0x172,
  0x15e,
  0x14a,
  0x137,
  0x124,
  0x112,
  0x100,
  0xef,
  0xdf,
  0xcf,
  0xbf,
  0xb1,
  0xa2,
  0x95,
  0x87,
  0x7b,
  0x6f,
  0x64,
  0x59,
  0x4f,
  0x45,
  0x3c,
  0x34,
  0x2c,
  0x25,
  0x1f,
  0x19,
  0x13,
  0xf,
  0xb,
  0x7,
  0x4,
  0x2,
  0x1,
  0x0,
  0x0,
  0x0,
  0x1,
  0x2,
  0x4,
  0x7,
  0xb,
  0xf,
  0x13,
  0x19,
  0x1f,
  0x25,
  0x2c,
  0x34,
  0x3c,
  0x45,
  0x4f,
  0x59,
  0x64,
  0x6f,
  0x7b,
  0x87,
  0x95,
  0xa2,
  0xb1,
  0xbf,
  0xcf,
  0xdf,
  0xef,
  0x100,
  0x112,
  0x124,
  0x137,
  0x14a,
  0x15e,
  0x172,
  0x187,
  0x19c,
  0x1b2,
  0x1c8,
  0x1df,
  0x1f6,
  0x20d,
  0x226,
  0x23e,
  0x257,
  0x271,
  0x28b,
  0x2a5,
  0x2c0,
  0x2db,
  0x2f6,
  0x312,
  0x32f,
  0x34c,
  0x369,
  0x386,
  0x3a4,
  0x3c2,
  0x3e0,
  0x3ff,
  0x41e,
  0x43e,
  0x45d,
  0x47d,
  0x49e,
  0x4be,
  0x4df,
  0x500,
  0x521,
  0x543,
  0x564,
  0x586,
  0x5a8,
  0x5cb,
  0x5ed,
  0x610,
  0x632,
  0x655,
  0x678,
  0x69b,
  0x6bf,
  0x6e2,
  0x705,
  0x729,
  0x74d,
  0x770,
  0x794,
  0x7b8,
  0x7db,
};

int myLed = 13;   // square wave output

bool ledOn = false;
volatile long counter = 0;

void myHandler() {
  static int i = 0, k = 180;
  //analogWrite(DAC0, sinTable[i]);
  analogWrite(DAC1, sinTable[k]);
  if (++k == 180)
    digitalWrite(myLed, !digitalRead(myLed));
  if (k >= 360) {
    k = 0;
    digitalWrite(myLed, !digitalRead(myLed));
  }
  //if (++i >= 360) i = 0;
  counter++;
}

int frequency = 10;
void setup() {
  pinMode(myLed, OUTPUT);   // square wave output
  Serial.begin(115200);
  Serial.println("Arduino timer3 DAC sime wave generator ");
  Serial.print("sine wave table length ");
  Serial.println(sizeof(sinTable) / sizeof(int16_t));
  Timer3.attachInterrupt(myHandler);
  Timer3.start((int)(1000000 / (360.0 * frequency)));  //10);
  pinMode(DAC0, OUTPUT);    // sine wave output
  pinMode(DAC1, OUTPUT);
  analogWriteResolution(12);
  Serial.println("enter frequency Hz (integer range 1 to 250)");
}

void loop() {
  if (Serial.available()) {
    frequency = Serial.parseInt();
    Timer3.start((int)(1000000 / (360.0 * frequency)));
    while (Serial.available()) Serial.read();
  }
  static long timer1 = millis();
  if (millis() - timer1 >= 1000) {
    Serial.print("Counter ");
    Serial.println(counter);
    timer1 += 1000;
    counter = 0;
  }
}

Wunderbar!

I really appreciate this. Very straight forward and the visual examples of the signals is perfect @horace. It is also a valuable note that the capacitor distorts the square signal a bit, thank you for that.

I do have a few more questions though. I know you mentioned it was quite some time ago since you worked with DUE DACs, but if you can recall, were you able to configure the amplitude in this? I noticed you can configure the frequency... very awesome logic there. For my particular project though I'm trying to also have the ability to change not only the frequency but the amplitude and sampling rate for both signals.

With this in mind, if the series capacitor and resistor were utilized would I have to adjust them when I alter the amplitude of the signals or am I missing something?

Thank you again for your spectacular guidance on this!

the capacitor distorts the square signal a bit

The effect is more complicated than that, but well understood.

A series capacitor followed by a load resistor is a high pass filter, which will alter the input waveform in a frequency dependent manner. If you want the result to be a particular waveform, you have to take this "post processing" into account.

Naturally, the frequency of the input waveform must be taken into account when choosing R and C, or vice versa. The search phrase "high pass rc filter tutorial" turns up lots of useful info. Top hit in my search looks OK: https://www.electronics-tutorials.ws/filter/filter_3.html

try this to change frequency and amplitude

// Arduino Due using timer3 interrupts output sine and square wave to DAC
//  set frequency and amplitude enter on serial monitor, e.g. frequency 10Hz amplitude 50%
//  10 50


#include <DueTimer.h>

// Arduino Due - use DAC0 for square wave and DAC1 for sine wave

// from https://forum.arduino.cc/t/how-can-i-get-2-sin-waves-on-the-due-at-same-time-one-out-of-phase-with-other/217778/4

const uint16_t sinTable[] = {
  0x7ff,
  0x823,
  0x846,
  0x86a,
  0x88e,
  0x8b1,
  0x8d5,
  0x8f9,
  0x91c,
  0x93f,
  0x963,
  0x986,
  0x9a9,
  0x9cc,
  0x9ee,
  0xa11,
  0xa33,
  0xa56,
  0xa78,
  0xa9a,
  0xabb,
  0xadd,
  0xafe,
  0xb1f,
  0xb40,
  0xb60,
  0xb81,
  0xba1,
  0xbc0,
  0xbe0,
  0xbff,
  0xc1e,
  0xc3c,
  0xc5a,
  0xc78,
  0xc95,
  0xcb2,
  0xccf,
  0xcec,
  0xd08,
  0xd23,
  0xd3e,
  0xd59,
  0xd73,
  0xd8d,
  0xda7,
  0xdc0,
  0xdd8,
  0xdf1,
  0xe08,
  0xe1f,
  0xe36,
  0xe4c,
  0xe62,
  0xe77,
  0xe8c,
  0xea0,
  0xeb4,
  0xec7,
  0xeda,
  0xeec,
  0xefe,
  0xf0f,
  0xf1f,
  0xf2f,
  0xf3f,
  0xf4d,
  0xf5c,
  0xf69,
  0xf77,
  0xf83,
  0xf8f,
  0xf9a,
  0xfa5,
  0xfaf,
  0xfb9,
  0xfc2,
  0xfca,
  0xfd2,
  0xfd9,
  0xfdf,
  0xfe5,
  0xfeb,
  0xfef,
  0xff3,
  0xff7,
  0xffa,
  0xffc,
  0xffd,
  0xffe,
  0xfff,
  0xffe,
  0xffd,
  0xffc,
  0xffa,
  0xff7,
  0xff3,
  0xfef,
  0xfeb,
  0xfe5,
  0xfdf,
  0xfd9,
  0xfd2,
  0xfca,
  0xfc2,
  0xfb9,
  0xfaf,
  0xfa5,
  0xf9a,
  0xf8f,
  0xf83,
  0xf77,
  0xf69,
  0xf5c,
  0xf4d,
  0xf3f,
  0xf2f,
  0xf1f,
  0xf0f,
  0xefe,
  0xeec,
  0xeda,
  0xec7,
  0xeb4,
  0xea0,
  0xe8c,
  0xe77,
  0xe62,
  0xe4c,
  0xe36,
  0xe1f,
  0xe08,
  0xdf1,
  0xdd8,
  0xdc0,
  0xda7,
  0xd8d,
  0xd73,
  0xd59,
  0xd3e,
  0xd23,
  0xd08,
  0xcec,
  0xccf,
  0xcb2,
  0xc95,
  0xc78,
  0xc5a,
  0xc3c,
  0xc1e,
  0xbff,
  0xbe0,
  0xbc0,
  0xba1,
  0xb81,
  0xb60,
  0xb40,
  0xb1f,
  0xafe,
  0xadd,
  0xabb,
  0xa9a,
  0xa78,
  0xa56,
  0xa33,
  0xa11,
  0x9ee,
  0x9cc,
  0x9a9,
  0x986,
  0x963,
  0x93f,
  0x91c,
  0x8f9,
  0x8d5,
  0x8b1,
  0x88e,
  0x86a,
  0x846,
  0x823,
  0x7ff,
  0x7db,
  0x7b8,
  0x794,
  0x770,
  0x74d,
  0x729,
  0x705,
  0x6e2,
  0x6bf,
  0x69b,
  0x678,
  0x655,
  0x632,
  0x610,
  0x5ed,
  0x5cb,
  0x5a8,
  0x586,
  0x564,
  0x543,
  0x521,
  0x500,
  0x4df,
  0x4be,
  0x49e,
  0x47d,
  0x45d,
  0x43e,
  0x41e,
  0x3ff,
  0x3e0,
  0x3c2,
  0x3a4,
  0x386,
  0x369,
  0x34c,
  0x32f,
  0x312,
  0x2f6,
  0x2db,
  0x2c0,
  0x2a5,
  0x28b,
  0x271,
  0x257,
  0x23e,
  0x226,
  0x20d,
  0x1f6,
  0x1df,
  0x1c8,
  0x1b2,
  0x19c,
  0x187,
  0x172,
  0x15e,
  0x14a,
  0x137,
  0x124,
  0x112,
  0x100,
  0xef,
  0xdf,
  0xcf,
  0xbf,
  0xb1,
  0xa2,
  0x95,
  0x87,
  0x7b,
  0x6f,
  0x64,
  0x59,
  0x4f,
  0x45,
  0x3c,
  0x34,
  0x2c,
  0x25,
  0x1f,
  0x19,
  0x13,
  0xf,
  0xb,
  0x7,
  0x4,
  0x2,
  0x1,
  0x0,
  0x0,
  0x0,
  0x1,
  0x2,
  0x4,
  0x7,
  0xb,
  0xf,
  0x13,
  0x19,
  0x1f,
  0x25,
  0x2c,
  0x34,
  0x3c,
  0x45,
  0x4f,
  0x59,
  0x64,
  0x6f,
  0x7b,
  0x87,
  0x95,
  0xa2,
  0xb1,
  0xbf,
  0xcf,
  0xdf,
  0xef,
  0x100,
  0x112,
  0x124,
  0x137,
  0x14a,
  0x15e,
  0x172,
  0x187,
  0x19c,
  0x1b2,
  0x1c8,
  0x1df,
  0x1f6,
  0x20d,
  0x226,
  0x23e,
  0x257,
  0x271,
  0x28b,
  0x2a5,
  0x2c0,
  0x2db,
  0x2f6,
  0x312,
  0x32f,
  0x34c,
  0x369,
  0x386,
  0x3a4,
  0x3c2,
  0x3e0,
  0x3ff,
  0x41e,
  0x43e,
  0x45d,
  0x47d,
  0x49e,
  0x4be,
  0x4df,
  0x500,
  0x521,
  0x543,
  0x564,
  0x586,
  0x5a8,
  0x5cb,
  0x5ed,
  0x610,
  0x632,
  0x655,
  0x678,
  0x69b,
  0x6bf,
  0x6e2,
  0x705,
  0x729,
  0x74d,
  0x770,
  0x794,
  0x7b8,
  0x7db,
};

int myLed = 13;  // square wave output

bool ledOn = false;
volatile long counter = 0;
volatile unsigned int amplitude = 100;

// timer interrupt handler
void myHandler() {
  static int  index = 180, square = 1;
  analogWrite(DAC0, square * 0xfff * amplitude / 100);  // square wave
  analogWrite(DAC1, sinTable[index] * amplitude / 100);     // sine wave
  if (++index == 180) {               
    square = !square;             // change square wave amplitude
    digitalWrite(myLed, !digitalRead(myLed));
  }
  if (index >= 360) {                 
    index = 0;                    // reset index
    square = !square;             // change square wave amplitude
    digitalWrite(myLed, !digitalRead(myLed));
  }
  counter++;
}

int frequency = 10;
void setup() {
  pinMode(myLed, OUTPUT);  // square wave output
  Serial.begin(115200);
  Serial.println("Arduino timer3 DAC sime wave generator ");
  Serial.print("sine wave table length ");
  Serial.println(sizeof(sinTable) / sizeof(int16_t));
  Timer3.attachInterrupt(myHandler);
  Timer3.start((int)round(1000000 / (360.0 * frequency)));  //10);
  pinMode(DAC0, OUTPUT);                               // sine wave output
  pinMode(DAC1, OUTPUT);
  analogWriteResolution(12);
  Serial.println("enter frequency Hz (integer 1 to 250) and amplitude (0 to 100)");
}

void loop() {
  // read frequency and amplitude
  if (Serial.available()) {
    frequency = Serial.parseInt();
    amplitude = Serial.parseInt();
    Timer3.start((int)round(1000000 / (360.0 * frequency)));
    while (Serial.available()) Serial.read();
  }
  // display interrupt counter
  static long timer1 = millis();
  if (millis() - timer1 >= 1000) {
    Serial.print("Counter ");
    Serial.println(counter);
    timer1 += 1000;
    counter = 0;
  }
}

10Hz 50% amplitude (enter 10 50 on serial monitor)
image

not sure what you wish to do with sampling rate
that is determined by the size of the sine lookup table and the frequency required, e.g.

    Timer3.start((int)round(1000000 / (360.0 * frequency)));

10Hz gives a timer interrupt every 278uSec

Thank you @jremington for the insight. I was a bit curious about why there is obviously this distortion in the square wave. Perhaps I’ll have to refresh myself on low pass filters and their effects as I am looking to generate particular waveforms.

The link and recommended search phrase is extremely helpful, thank you for putting me on the right path here.

Sehr wunderbar!

Thank you once again @horace. I’m very grateful for your help and time on this. Your logic here also looks very good.

As for the sampling rate, alls I know is that apparently if you can adjust the sampling rate you can accurately capture a continuous signal without introducing distortions. Perhaps my terminology is just off in which case I must have meant “sampling frequency”. But the point is that I had the understanding that if your signal has quite a lot of noise you can raise the sampling frequency to obtain a better waveform. I’m I correct saying this?

running code of post 7 parameters 1Hz 100%amplitude
image

have a look at capacitorDischarge which displays the exponential decay.

yes - the program of post 7 uses a lookup table with 360 values - one for every degree
using a lookup with 36values (every 10 degrees) a sample output looks like
image

you could increase the size of the lookup table (say to 3600 values) to give a improved waveform but you can then run into the problem can the timer interrupt at the rate to give you the frequency required

usually the term “sampling frequency” is used when sampling a waveform using a ADC - in general rule is the sampling must be at lease twice the highest frequency required - see shannon-sampling-theorem

Thank you again @horace, I really appreciate your help with this, your thorough explanation helps very mush. I apologize for my late response as I was traveling this past weekend.

I wanted to note that I am not very versed in this electronics configurability field. So with that, would you perhaps remember how you configured or set up your hardware? I know we discussed that you simply put a capacitor and resistor in series with the DAC port on the DUE, but I was curious if there was any more configurability I should be aware of to build this for my project?

Let me know if this makes sense.

it was a very simple circuit to remove the DAC output DC offset for the oscilloscope
image

what are you intending to drive?
you may well require a more complex driver circuit

This is perfect @horace, thank you so much for the clarification. I've set up the circuitry and am glad to report it does exactly as you've described and shown.

My intentions are to use these generated signals, the sinus one being a stimulus signal and the square signal being the time, as a sudo-DAQ system. There's not really a particular device like a motor, LED, or display I'm sending these signals to if that is what you mean. This current hardware low pass filter will work perfectly though for my application.

I do have another question regarding this project though. I intend to send these signals via MATLAB. Would there be an advice you would be willing to give me to send a MATLAB program to generated these signals via the DUE? I could make a new post/topic but I figured it would be easier to just ask here.

Thank you so much again for all your help and patience through this process.

not sure what you require ?
are you simply going to transmit the required frequency and amplitude as text, e.g. "10 50" for 10Hz 50% amplitude.
if so you can use Matlab serialport to transmit text which can be read using Serial.parseInt() on the DUE (EDIT: remember to close the Arduino IDE serial monitor)

I don't tend to use Matlab these days (license expired some time ago)
on PCs mainly use GNU Octave or C# or Java

it is a high pass filter - see post 6 from @jremington

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