You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

包络跟踪与脉宽调制功能异常,FFT结果不符预期求助

问题描述

我正在实现包络跟踪(Envelope tracking)与脉宽调制(Pulse width modulation)功能。本次实验中,使用1MHz正弦波,以3MHz频率对其采样,每个采样值决定周期为0.33μs的脉冲信号的占空比。

脉冲信号:
Pulse

正弦波:
sine wave

对脉冲信号进行FFT分析时,期望能看到1MHz的频率成分,但实际频域图如下:
freq domain

请问哪里操作出错了?

以下是实验代码:

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
问题分析与修正方案

核心错误点

  1. 采样频率与PWM周期不匹配
    设定的采样频率是3MHz(采样周期≈0.333μs),但PWM周期设为0.33μs,两者周期存在偏差,导致每个PWM周期内的采样点数量不固定,且后续FFT计算时错误使用了3MHz作为采样率,实际生成的PWM波采样率远高于此(每个周期1000点,采样率≈3.03GHz),频率轴完全失真。

  2. FFT频率轴计算错误
    t_varying的生成逻辑错误,直接用length(square_wave_varying)/f_sample计算总时长,但实际PWM波的采样率是1000/T_square,不是3MHz,导致频率轴刻度完全错误,无法正确显示1MHz成分。

  3. 信号时长过短
    仅采集了2μs的正弦波(对应2个周期),FFT的频率分辨率为1/t_sine=500kHz,难以清晰分辨1MHz的频率成分,频谱会出现严重的泄漏。

  4. 占空比计算冗余
    对采样后的正弦波除以max_amplitude再乘以100,额外引入了缩放误差,原正弦波1+sin(...)的范围是02,直接归一化到0100%即可,无需除以最大值。

修正后的代码

pkg load signal

clear all;
close all;
% Parameters
f_sine = 1e6;        % 1MHz正弦波频率
t_total = 10e-6;     % 延长信号时长到10μs,提高FFT分辨率
f_sample = 3e6;      % 3MHz采样频率
T_sample = 1/f_sample; % 采样周期≈0.333μs,与PWM周期对齐
t_sample = 0:T_sample:t_total-T_sample;  % 采样时间向量

% 生成正弦波(范围0~2,直接用于占空比计算)
sine_wave_sample = 1 + sin(2 * pi * f_sine * t_sample);
% 归一化到0~100%的占空比,无需除以max_amplitude(原信号范围固定)
duty_cycles = (sine_wave_sample / 2) * 100;
% 可选:保留0.9的缩放,避免占空比达到100%
duty_cycles = duty_cycles * 0.9;

% 生成PWM波:每个采样周期对应一个PWM周期,每个周期用固定采样点
pwm_samples_per_cycle = 100; % 每个PWM周期采样点数
T_pwm = T_sample; % PWM周期与采样周期对齐
t_pwm_cycle = linspace(0, T_pwm, pwm_samples_per_cycle+1);
t_pwm_cycle = t_pwm_cycle(1:end-1); % 去掉最后一个点避免重叠

square_wave_varying = [];
for dc = duty_cycles
    % 生成单个PWM周期的波形
    pwm_cycle = 0.5 * (square(2*pi*(1/T_pwm)*t_pwm_cycle, dc) + 1);
    square_wave_varying = [square_wave_varying, pwm_cycle];
end

% 计算实际PWM波的采样率
f_pwm_sample = pwm_samples_per_cycle / T_pwm;
t_varying = linspace(0, t_total, length(square_wave_varying));

% 绘图部分
figure;
plot(t_sample*1e6, sine_wave_sample);
xlabel('时间 (μs)');
ylabel('幅度');
title('1MHz正弦波(3MHz采样)');
grid on;

figure;
plot(t_varying*1e6, square_wave_varying);
xlabel('时间 (μs)');
ylabel('幅度');
title('变占空比PWM波');
grid on;

% FFT分析
N = length(square_wave_varying);
% 用实际PWM采样率计算频率轴
f = (0:N-1)*(f_pwm_sample/N);
Y = fft(square_wave_varying);
% 归一化幅度
Y_amp = 2*abs(Y)/N;

figure;
% 只显示0~5MHz的范围,聚焦目标频率
plot(f(1:N/2)/1e6, Y_amp(1:N/2));
xlabel('频率 (MHz)');
ylabel('幅度');
title('PWM波频谱');
xlim([0 5]);
grid on;

修正后效果说明

  • 对齐了PWM周期与采样周期,保证每个采样点对应一个PWM周期,逻辑更清晰。
  • 延长信号时长到10μs,FFT分辨率提升到100kHz,能清晰分辨1MHz的频率成分。
  • 使用实际PWM波的采样率计算频率轴,频谱刻度准确。
  • 简化占空比计算,避免不必要的缩放误差。

内容的提问来源于stack exchange,提问作者fpga_noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:49:54