PLL输出频谱分析 - 杂散和相位噪声检测
function pll_spectrum_analysis(t, vout, f_ref, f_out)
% 输入参数:
% t: 时间向量
% vout: 输出电压向量
% f_ref: 参考频率 (Hz)
% f_out: 输出载波频率 (Hz)
%% 基本参数计算
N = length(vout);
Fs = 1/(t(2)-t(1)); % 采样频率
T_total = t(end) - t(1); % 总采样时间
df = Fs/N; % 频率分辨率
fprintf('采样频率: %.3f MHz\n', Fs/1e6);
fprintf('总采样时间: %.3f us\n', T_total*1e6);
fprintf('频率分辨率: %.3f kHz\n', df/1e3);
%% 窗函数处理
window = hann(N); % 汉宁窗
window_power = norm(window, 2)^2 / N; % 窗函数功率修正因子
% 信号加窗
vout_windowed = vout .* window;
%% FFT计算
V_fft = fft(vout_windowed, N);
V_fft = V_fft / (N * sqrt(window_power)); % 幅度归一化
% 计算单边频谱
if mod(N,2) == 0
N_half = N/2 + 1;
else
N_half = (N+1)/2;
end
V_single_sided = V_fft(1:N_half);
V_single_sided(2:end-1) = 2 * V_single_sided(2:end-1); % 除DC外幅度加倍
% 频率轴 (单边)
f_single_sided = (0:N_half-1) * Fs / N;
%% 功率谱密度计算
PSD = abs(V_single_sided).^2 / (Fs/2); % 功率谱密度
PSD_dBm = 10*log10(PSD) + 30; % 转换为dBm (相对于1mW)
PSD_dBc = 10*log10(PSD/max(PSD)); % 相对于载波的dBc
%% 载波和杂散检测
% 找到载波位置
[carrier_power, carrier_idx] = max(PSD);
f_carrier = f_single_sided(carrier_idx);
fprintf('检测到的载波频率: %.3f MHz\n', f_carrier/1e6);
fprintf('载波功率: %.2f dBm\n', 10*log10(carrier_power) + 30);
%% 杂散检测
% 在参考频率附近搜索杂散
spur_bins = [];
spur_frequencies = [];
spur_levels_dBc = [];
% 检查参考频率及其谐波
max_harmonic = floor(Fs/2 / f_ref);
for k = 1:max_harmonic
spur_freq = k * f_ref;
[~, spur_idx] = min(abs(f_single_sided - spur_freq));
% 确保不是载波本身
if abs(f_single_sided(spur_idx) - f_carrier) > df
spur_power = PSD(spur_idx);
spur_level_dBc = 10*log10(spur_power / carrier_power);
if spur_level_dBc > -80 % 只记录显著的杂散
spur_bins = [spur_bins, spur_idx];
spur_frequencies = [spur_frequencies, f_single_sided(spur_idx)];
spur_levels_dBc = [spur_levels_dBc, spur_level_dBc];
end
end
end
%% 相位噪声估算 (简化版)
% 在载波附近计算相位噪声
offset_freqs = [1e3, 10e3, 100e3, 1e6]; % 常用偏移频率
phase_noise = zeros(size(offset_freqs));
for i = 1:length(offset_freqs)
offset = offset_freqs(i);
lower_bin = find(f_single_sided >= (f_carrier - offset), 1);
upper_bin = find(f_single_sided <= (f_carrier + offset), 1, 'last');
if ~isempty(lower_bin) && ~isempty(upper_bin)
noise_power = sum(PSD(lower_bin:upper_bin)) - PSD(carrier_idx);
phase_noise(i) = 10*log10(noise_power / carrier_power);
end
end
%% 绘图
figure('Position', [100, 100, 1200, 800]);
% 子图1: 完整频谱
subplot(2,2,1);
plot(f_single_sided/1e6, PSD_dBc, 'b-', 'LineWidth', 1);
hold on;
% 标记载波和杂散
plot(f_carrier/1e6, 0, 'ro', 'MarkerSize', 8, 'LineWidth', 2);
if ~isempty(spur_frequencies)
plot(spur_frequencies/1e6, spur_levels_dBc, 'rx', 'MarkerSize', 10, 'LineWidth', 2);
legend('频谱', '载波', '杂散', 'Location', 'best');
else
legend('频谱', '载波', 'Location', 'best');
end
xlabel('频率 (MHz)');
ylabel('幅度 (dBc)');
title('PLL输出完整频谱');
grid on;
% 子图2: 载波附近细节
subplot(2,2,2);
span = min(10*f_ref, Fs/4); % 显示范围
f_min = max(0, f_carrier - span);
f_max = min(Fs/2, f_carrier + span);
idx_range = find(f_single_sided >= f_min & f_single_sided <= f_max);
plot(f_single_sided(idx_range)/1e6, PSD_dBc(idx_range), 'b-', 'LineWidth', 1.5);
hold on;
if ~isempty(spur_frequencies)
plot(spur_frequencies/1e6, spur_levels_dBc, 'rx', 'MarkerSize', 10, 'LineWidth', 2);
end
xlabel('频率 (MHz)');
ylabel('幅度 (dBc)');
title('载波附近频谱细节');
grid on;
% 子图3: 时域波形
subplot(2,2,3);
plot(t(1:min(1000, length(t)))*1e6, vout(1:min(1000, length(vout))), 'b-');
xlabel('时间 (us)');
ylabel('电压 (V)');
title('时域波形 (前1000点)');
grid on;
% 子图4: 杂散和相位噪声表格
subplot(2,2,4);
axis off;
% 显示杂散信息
text(0.1, 0.9, '杂散检测结果:', 'FontSize', 12, 'FontWeight', 'bold');
if ~isempty(spur_levels_dBc)
for i = 1:length(spur_levels_dBc)
text(0.1, 0.8 - i*0.08, ...
sprintf('%.3f MHz: %.1f dBc', spur_frequencies(i)/1e6, spur_levels_dBc(i)), ...
'FontSize', 10);
end
else
text(0.1, 0.8, '未检测到显著杂散 (< -80 dBc)', 'FontSize', 10);
end
% 显示相位噪声估算
text(0.1, 0.4, '相位噪声估算:', 'FontSize', 12, 'FontWeight', 'bold');
for i = 1:length(offset_freqs)
text(0.1, 0.3 - i*0.08, ...
sprintf('@ %.0f kHz: %.1f dBc/Hz', offset_freqs(i)/1e3, phase_noise(i)), ...
'FontSize', 10);
end
%% 输出详细报告
fprintf('\n=== PLL频谱分析报告 ===\n');
fprintf('载波频率: %.6f MHz\n', f_carrier/1e6);
fprintf('载波功率: %.2f dBm\n', 10*log10(carrier_power) + 30);
fprintf('\n杂散检测:\n');
if ~isempty(spur_levels_dBc)
for i = 1:length(spur_levels_dBc)
fprintf(' %.3f MHz: %.1f dBc\n', spur_frequencies(i)/1e6, spur_levels_dBc(i));
end
else
fprintf(' 无显著杂散\n');
end
fprintf('\n相位噪声估算:\n');
for i = 1:length(offset_freqs)
fprintf(' %.0f kHz偏移: %.1f dBc/Hz\n', offset_freqs(i)/1e3, phase_noise(i));
end
end
%% 使用示例
% 假设您已经有时域数据 t 和 vout
% pll_spectrum_analysis(t, vout, 10e6, 2.4e9); % 10MHz参考, 2.4GHz输出
%% 数据读取函数 (如果从文件读取)
function [t, vout] = read_spectre_data(filename)
% 读取Cadence Spectre输出数据
% 这里需要根据实际文件格式调整
data = load(filename);
t = data(:,1); % 第一列为时间
vout = data(:,2); % 第二列为电压
end
