Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Envelope tracking and pulse width modulation not working

Tags:

matlab

octave

I am trying to implement envelope tracking and pulse width modulation. In this example, I have a 1 MHz sine wave. I sample this sine wave at 3MHz and each sample will determine a duty cycle for a pulse width signal with period of 0.33us.

Pulse: Pulse

Sine wave: sine wave

I am expecting to see the 1MHz frequency when I take the FFT of Pulse signal. but it looks like this

Freq. domain: freq domain

What am I doing wrong?

Here is my code:

pkg load signal

clear all;
close all;
% Parameters
f_sine = 1e6;        % Frequency of the sine wave (1 MHz)
t_sine = 2e-6;       % Time duration to plot (2 us)
f_sample = 3e6;      % Sampling frequency (3 MHz)
t_sample = 0:1/f_sample:t_sine;  % Time vector for sampled signal
t_cont = linspace(0, t_sine, 1000);

% Sine wave
sine_wave_cont = 1 + sin(2 * pi * f_sine * linspace(0, t_sine, 1000));  % Continuous sine wave from 0 to 2
sine_wave_sample = 1 + sin(2 * pi * f_sine * t_sample);  % Sampled sine wave

% Compute percentage of sampled amplitude compared to max amplitude
max_amplitude = max(sine_wave_sample);
percentage_amplitude = (sine_wave_sample / max_amplitude) * 100;

% Square wave parameters
T_square = 0.33e-6;  % Period of the square wave (0.33 us)

% Initialize the array for the square wave with varying duty cycles
square_wave_varying = [];

% Generate the square wave with varying duty cycle
for i = 1:length(percentage_amplitude)
    duty_cycle = percentage_amplitude(i)*0.9;
    t_current = linspace(0, T_square, 1000);   % Time vector for the current period
    if length(t_current) > 1
        square_wave_current = 0.5 * (square(2 * pi * (1/T_square) * t_current, duty_cycle) + 1);
        square_wave_varying = [square_wave_varying, square_wave_current(1:end-1)];  % Avoid overlapping periods
    end
end

% Adjust time vector for the concatenated square wave
t_varying = linspace(0, length(square_wave_varying)/f_sample, length(square_wave_varying));

% Plot continuous sine wave
figure;
plot(linspace(0, t_sine, 1000) * 1e6, sine_wave_cont);  % Time in us for x-axis
ylim([-0.5 2.5]);
xlabel('Time (us)');
ylabel('Amplitude');
title('Sine Wave at 1 MHz');
grid on;  % Turn on grid

% Plot square wave with varying duty cycle
figure;
plot(t_varying * 1e3, square_wave_varying);  % Time in us for x-axis
ylim([-0.2 1.4]);
xlabel('Time (us)');
ylabel('Amplitude');
title('Square Wave with Varying Duty Cycle');
grid on;  % Turn on grid

% Plot percentage amplitude
figure;
stem(t_sample * 1e6, percentage_amplitude, 'filled');  % Time in us for x-axis
ylim([0 110]);
xlabel('Time (us)');
ylabel('Percentage Amplitude');
title('Percentage Amplitude of Sampled Sine Wave at 3 MHz');
grid on;  % Turn on grid

% Frequency domain analysis
N = length(square_wave_varying);  % Number of points
f = (0:N-1)*(f_sample/N);         % Frequency range
Y = fft(square_wave_varying);     % Compute FFT

% Plot frequency spectrum
figure;
plot(f(1:N/2)/1e6, abs(Y(1:N/2)));  % Plot single-sided amplitude spectrum
xlabel('Frequency (MHz)');
ylabel('Magnitude');
title('Frequency Spectrum of Square Wave with Varying Duty Cycle');
grid on;  % Turn on grid

like image 525
fpga_noob Avatar asked Jan 22 '26 13:01

fpga_noob


1 Answers

I believe you are confusing the frequency of a sine wave, to the sampling frequency of a signal.

sine-wave frequency versus sample frequency

The frequency of the sine wave is the inverse of its period. It is a direct representation of how many periods the signal will have per second. For example, if you plot a 2 Hertz sine wave over 1 second, you will see two periods:

enter image description here

On the other hand, the sampling frequency represents how many times per second a given signal will be acquired (as in measured if you are in a real life situation). Taking the former example, the following plots represent the same sine wave sampled at 8Hz, 32Hz and 256Hz. Note the "smoothness" of the signals that gets better as the sampling frequency gets big with respect to the frequency of the sine wave:

enter image description here

Back to your question

Now that things are a bit clearer, let's go through your code, with a few changes:

% Parameters
f_sine = 1e6;        % Frequency of the sine wave (1 MHz)
t_sine = 2e-6;       % Time duration to plot (2 us)
f_sample = 64e6;      % Sampling frequency (64 MHz <-- that means 64 points per period, it's a minimum)
t_sample = 0:1/f_sample:t_sine;  % Time vector for sampled signal

% Sine wave
sine_wave_sample = 1 + sin(2 * pi * f_sine * t_sample);  % Sampled sine wave

You should only keep the sine_wave_sample variable. It is the discrete representation of the continuous sine wave.

Here is the plot:

% Plot sampled sine wave
figure;
plot(t_sample*1e6, sine_wave_sample);  % Time in us for x-axis
ylim([-0.5 2.5]);
xlabel('Time (us)');
ylabel('Amplitude');
title('Sine Wave of frequency 1 MHz, sampled at 64 MHz');
grid on;  % Turn on grid
set(gcf,'color','w')
set(gca,'fontsize',10)

enter image description here

Now you can go on with the construction of your square wave collection:

% Compute percentage of sampled amplitude compared to max amplitude
max_amplitude = max(sine_wave_sample);
percentage_amplitude = (sine_wave_sample / max_amplitude) * 100;

% Square wave parameters
T_square = 0.33e-6;  % Period of the square wave (0.33 us)

% Initialize the array for the square wave with varying duty cycles
square_wave_varying = [];

% Generate the square wave with varying duty cycle
for i = 1:length(percentage_amplitude)
    
    duty_cycle = percentage_amplitude(i)*0.9;
    square_wave_current = 0.5 * (square(2 * pi * (1/T_square) * t_sample(2:end), duty_cycle) + 1);
    square_wave_varying = [square_wave_varying, square_wave_current];

end

You can plot the percentage amplitudes (note that with the 64 MHz sampling frequency it looks way nicer):

figure;
stem(t_sample * 1e6, percentage_amplitude, 'filled');  % Time in us for x-axis
ylim([0 110]);
xlabel('Time (us)');
ylabel('Percentage Amplitude');
title('Percentage Amplitude of Sine Wave of frequency 1 MHz, sampled at 64 MHz');
grid on;  % Turn on grid
set(gcf,'color','w')
set(gca,'fontsize',10)

enter image description here

The time signal corresponding to your square is calculated using the time_sample vector:

% Time vector for the concatenated square wave
t_varying_stacked = (0:(length(percentage_amplitude)-1))*max(t_sample)+t_sample(2:end).';
t_varying = t_varying_stacked(:);

It has a lot of points but zooming on the plot you can clearly see the increase / decrease of the square wave durations:

% Plot square wave with varying duty cycle
figure;
plot(t_varying * 1e6, square_wave_varying.');  % Time in us for x-axis
ylim([-0.2 1.4]);
xlabel('Time (us)');
ylabel('Amplitude');
title('Square Wave with Varying Duty Cycle');
grid on;  % Turn on grid
set(gcf,'color','w')
set(gca,'fontsize',10)

enter image description here

Last part is the FFT, which you actually already calculated properly:

% Frequency domain analysis
N = length(square_wave_varying);  % Number of points
f = (0:N-1)*(f_sample/N);         % Frequency range
Y = fft(square_wave_varying);     % Compute FFT

% Plot frequency spectrum
figure;
plot(f(1:N/2)/1e6, abs(Y(1:N/2)));  % Plot single-sided amplitude spectrum
xlabel('Frequency (MHz)');
ylabel('Magnitude');
title('Frequency Spectrum of Square Wave with Varying Duty Cycle');
grid on;  % Turn on grid
set(gcf,'color','w')
set(gca,'fontsize',10)

enter image description here

If you zoom on the spectrum plot, you can see the following frequencies:

  • The nil frequency corresponding to the average of your signal

  • The 3 MHz frequency (and multiples) corresponding to the frequency of your 0.33us-period square wave

  • The 1 MHz frequency (and multiples) corresponding to the sine wave modulation of the duty cycle

  • The 0.5 MHz frequency (and multiples) corresponding to the average modulation given by your sine-wave

enter image description here

like image 102
BillBokeey Avatar answered Jan 26 '26 00:01

BillBokeey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!