In this Task, we have to generate 2 sine waveforms, and the second waveform will be phase-shifted.
What is a Phase shift?
Phase shift refers to the time difference between two periodic signals of the same frequency.
Phase shift is measured in degrees 0° to 360°
Microcontrollers often implement it by delaying one waveform relative to another to create the desired phase shift offset.
In our task,
We will delay (phase shift) the sine waveform 2, based on the potentiometer's reading.
Which microcontroller are we using?
Since the ATmega328P (Arduino UNO) does not have a built-in DAC, we will use the ESP32 for this task.
While PWM can also be used to generate a sine wave (approximating an analog waveform), it needs extra filtering and does not offer the same accuracy or smoothness as a DAC.
DAC in ESP32:
Note: The output of the ESP32's DAC is not perfectly linear, which may affect the accuracy and precision of the waveform.
The hardware connection is simple
Input
DAC Outputs: Connect to DSO.
GPIO26 (DAC2) → Sine Wave 2 output (phase-shifted)
const int potPin = 34; // ADC pin connected to potentiometer
const int dacPin1 = 25; // DAC1
const int dacPin2 = 26; // DAC2
const int waveformSize = 256; // Size of sine wave table
uint8_t sineWave[waveformSize]; // 8-bit values for DAC
void generateSineWave() {
for (int i = 0; i < waveformSize; i++) {
float radians = (2 * PI * i) / waveformSize;
sineWave[i] = (uint8_t)(127.5 + 127.5 * sin(radians)); // scale to 0–255
}
}
void setup() {
Serial.begin(115200);
analogReadResolution(12); // ESP32 supports 12-bit ADC
generateSineWave();
}
void loop() {
int potValue = analogRead(potPin); // Read potentiometer (0 to 4095)
float phaseShift = (float)(potValue / 11.375); // Degrees (0–360)
int phaseShiftSamples = (int)(phaseShift / 360.0 * waveformSize);
for (int i = 0; i < waveformSize; i++) {
int index1 = i;
int index2 = (i + phaseShiftSamples) % waveformSize;
dacWrite(dacPin1, sineWave[index1]);
dacWrite(dacPin2, sineWave[index2]);
delayMicroseconds(100); // Adjust for ~2s waveform total period
}
}
Generating the Sine Wave:
We will use the sin(angle)
function, which returns the sine of an angle in radians. This value ranges from -1 to 1.
However, the ESP32's 8-bit DAC accepts values from 0 to 255
0 → 0V
255 → 3.3V
So, the sine values are converted from -1 to 1 into 0 to 255 using this formula: sineWave[i] = 127.5 + 127.5 * sin(angleInRadians);
To avoid repeating the same sine calculations in every cycle, we calculate them only once and store the values in the sineWave
array.
Phase shift calculation:
We are using a 12-bit ADC (0 to 4095) to read the value of the potentiometer. So, potValue
read from ADC is between 0 to 4095, which is converted to a range of 0 to 360 using the following formula.
float phaseShift = (float)potValue / 11.375;
Why 11.375?
It is the ratio of 4095.0 / 360
= 11.375
How to phase shift a signal?
To create a phase shift between two sine waves, we need to map the desired phase angle (from 0° to 360°) to an index range in the sineWave
array (0 to 255).
This allows us to generate the second waveform with the required offset.
For example:
This method delays the second waveform by the required phase angle using pre-shifted index values in the array.
Below given formula is used for calculating the phase shift offset value and storing it into the phaseShiftSamples
variable.
int phaseShiftSamples = (int)(phaseShift / 360.0 * waveformSize);
Circular Indexing
int index2 = (i + phaseShiftSamples) % waveformSize;
The % waveformSize
part ensures we wrap around the sine array when the index exceeds 255.
Frequency Control
delayMicroseconds(100)
sets the time between DAC updates, which controls the frequency of the waveform. Smaller delays mean higher frequency.
Setup
Circuit
Waveform