今天,我想与大家分享一个我在准备考研期间完成的MATLAB信号完整性分析项目。这个项目不仅是对我专业知识的检验,也是我自己依然保持学术热情的方式。我希望通过这篇文章,让更多同学了解信号完整性分析的重要性,并学会如何用MATLAB实现眼图生成和高速系统评估。
一、什么是信号完整性分析?
想象一下,你和朋友玩传话游戏。第一个人说"今天晚上七点看电影",传到第十个人时变成了"明天早上九点去游泳"。在高速数字系统中,类似的问题也在发生:信号在传输过程中会"失真",导致接收端无法正确识别原始信息。
信号完整性就是研究如何让信号在高速传输中保持"原汁原味"的科学。在5G、高速互联网、数据中心等现代通信系统中,信号完整性分析至关重要。
二、项目概述:我们要做什么?
我们将用MATLAB创建一个完整的信号完整性分析系统,主要包括:
-
生成测试信号(PRBS序列)
-
模拟信号在信道中的传输
-
添加真实的噪声和抖动
-
生成并分析眼图
-
评估系统性能
三、参数设置
部分概念的解释与理解:
-
采样频率 (fs):就像拍照的帧率,越高越能捕捉信号的细节
-
比特率:每秒传输的比特数,10 Gbps就是每秒100亿个比特
-
比特周期:传输一个比特需要的时间
-
每比特采样点数:在每个比特周期内,我们要用多少个点来描述它
假设我们要分析10 Gbps的高速系统,为了准确捕捉信号细节,采样频率通常要比比特率高很多(这里是10倍)。就像用高速相机拍摄快速运动的物体一样。
Matlab
%% 高速数字信号完整性分析系统 - 修正版(函数定义在末尾)
% 作者:信号完整性工程师
% 功能:眼图生成、抖动分析、BER估计等
clear all; close all; clc; % 清理环境,重新开始
%% 1. 参数设置
fs = 100e9; % 采样频率 100 GHz
Ts = 1/fs; % 采样间隔
bit_rate = 10e9; % 比特率 10 Gbps
bit_period = 1/bit_rate; % 比特周期
samples_per_bit = fs/bit_rate; % 每比特采样点数
% 系统参数
num_bits = 10000; % 总比特数
rise_time = 0.1 * bit_period; % 上升时间
channel_length = 0.5; % 通道长度(米)
material_er = 4.0; % 介电常数
四、生成测试信号
1.什么是PRBS?
PRBS(伪随机二进制序列)是一种看起来随机但实际上是确定性的序列。它是测试数字系统的"标准台词",因为它能模拟真实数据流的统计特性。
Matlab
%% 2. 生成PRBS测试序列
fprintf('生成PRBS测试序列...\n');
prbs_data = generate_prbs(7, num_bits);
PRBS-7序列的长度是2^7-1=127位,它会不断重复直到达到我们需要的一万位。这样做的好处是既能模拟随机性,又能保证接收端可以通过模式识别来检测错误。
2.信号编码
信号编码是把比特变成波形的过程。
Matlab
%% 3. 信号编码(NRZ格式)
fprintf('信号编码...\n');
tx_signal = 2*prbs_data - 1; % 转换为±1V
% 上采样到模拟波形
tx_waveform = [];
for i = 1:length(tx_signal)
tx_waveform = [tx_waveform, tx_signal(i) * ones(1, round(samples_per_bit))];
end
% 确保长度一致
tx_waveform = tx_waveform(1:num_bits*round(samples_per_bit));
在这里,有个很重要的概念需要介绍,即NRZ编码。
不归零编码通过高低电平直接表示二进制数据,但缺乏自同步能力,需额外传输时钟信号。
不归零编码用低电平表示二进制0,用高电平表示二进制1,NRZ码的缺点是无法判断每一位的开始与结束,收发不同保持同步,必须在发送NRZ码的同时,用另一个信道同时传送同步信号。
在我们的项目中:
-
二进制0 → 电压-1V
-
二进制1 → 电压+1V
上采样: 把每个比特扩展成10个相同的采样点,就像把低分辨率图片放大一样。
五、信道建模
信号在传输过程中会经历各种"磨难",就像你说话的声音在空气中传播会衰减一样。
Matlab
%% 4. 通道建模(传输线效应)
fprintf('通道建模...\n');
% 创建带限通道模型(低通滤波器模拟带宽限制)
channel_bandwidth = 0.7 * bit_rate; % 通道带宽
nyquist_freq = fs/2;
cutoff_normalized = channel_bandwidth / nyquist_freq;
% 设计FIR滤波器模拟通道
filter_order = 100;
b = fir1(filter_order, cutoff_normalized, 'low');
channel_response = filter(b, 1, tx_waveform);
1.信道效应
带宽限制:
任何实际信道都有带宽限制,高频分量衰减更大,导致信号上升沿变缓。想象一下低音炮能很好传递低音,但对高音效果不佳。
传输线损耗:
Matlab
% 添加传输线损耗(频率相关)
f = linspace(0, fs/2, length(b));
alpha_db = 0.2 * sqrt(f/1e9); % 损耗 dB/inch
alpha_linear = 10.^(-alpha_db/20);
高频衰减比低频更严重!频率依赖性模拟了实际传输线的趋肤效应。
六、噪声与抖动
现实世界的信号会受到各种干扰。
Matlab
%% 5. 添加噪声和抖动
fprintf('添加噪声和抖动...\n');
% 添加高斯白噪声
SNR_dB = 20; % 信噪比
signal_power = mean(rx_signal_noiseless.^2);
noise_power = signal_power / (10^(SNR_dB/10));
noise = sqrt(noise_power) * randn(size(rx_signal_noiseless));
1.噪声与抖动的区别
噪声是电压幅度的随机变化,就像照片上的噪点。
抖动是时序的随机变化,就像节拍器不准时。
Matlab
% 添加确定性抖动(周期性变化)
dj_pp = 0.05 * bit_period; % 峰峰值确定性抖动
deterministic_jitter = dj_pp * sin(2*pi*bit_rate/10 * (0:length(rx_signal_noiseless)-1)*Ts);
% 添加随机抖动(随机变化)
rj_rms = 0.02 * bit_period; % RMS随机抖动
random_jitter = rj_rms * randn(size(rx_signal_noiseless));
% 总抖动
total_jitter = deterministic_jitter + random_jitter;
2.确定性抖动与随机抖动
想象你在用麦克风唱歌,确定性抖动就像麦克风支架在轻微振动(有规律的),随机抖动就像有人偶尔碰到麦克风线(无规律的)。
七、眼图生成
眼图能直观显示信号质量。
Matlab
%% 6. 生成眼图
fprintf('生成眼图...\n');
% 调用眼图生成函数
plot_eye_diagram(rx_signal, samples_per_bit, bit_period, fs, 100);
1.眼图是什么?
简单说: 把很多个比特周期的波形重叠在一起,形状像眼睛,所以叫眼图。
眼图能告诉我们什么?
-
眼高:眼睛张开的高度,越大越好
-
眼宽:眼睛张开的宽度,越宽越好
-
抖动:眼睛两边的厚度,越薄越好
2.眼图生成原理
Matlab
function plot_eye_diagram(signal, samples_per_bit, bit_period, fs, num_eyes)
% 关键步骤:将长信号切割成多个2比特周期的段
samples_per_eye = round(2 * samples_per_bit); % 显示两个比特周期
% 提取每个比特段的波形
for i = 1:num_segments
start_idx = (i-1) * round(samples_per_bit) + 1;
end_idx = min(start_idx + samples_per_eye - 1, num_samples);
segment = signal(start_idx:end_idx);
eye_data = [eye_data; segment(:)']; % 收集所有段
end
% 将所有段叠加绘制
for i = 1:max_traces
plot(time_axis, eye_data(i, :), 'b-', 'LineWidth', 0.1, 'Color', [0, 0.4470, 0.7410, 0.1]);
end
代码中为什么显示两个比特周期? 因为这样可以同时看到比特转换和稳定区域。
八、频率响应分析
眼图显示症状,频率分析找出病因。
Matlab
%% 7. 频率响应分析
fprintf('频率响应分析...\n');
figure('Position', [100, 100, 1200, 400], 'Name', '频率响应分析');
% 计算传输函数
[H, freq] = freqz(b_loss, 1, 1024, fs);
subplot(1, 3, 1);
semilogx(freq/1e9, 20*log10(abs(H)), 'b-', 'LineWidth', 2);
xlabel('频率 (GHz)');
ylabel('幅度 (dB)');
title('通道频率响应');
grid on;
频率响应的三个关键指标
-
幅度响应:不同频率的衰减程度
-
插入损耗:信号通过信道后的功率损失
-
群延迟:不同频率分量的时间延迟差异
群延迟的重要性: 如果不同频率到达时间不同,信号就会失真,就像乐队成员节奏不一致。
九、误码率分析
这是最终的考核指标:有多少比特出错了?
Matlab
%% 8. 误码率分析
fprintf('误码率分析...\n');
% 信号均衡(简单CTLE)
f_cut = bit_rate/2;
[bl, al] = butter(3, f_cut/(fs/2), 'high');
equalized_signal = filter(bl, al, rx_signal);
1.均衡器:信号的"矫正器"
均衡器补偿信道引起的高频衰减,就像图像处理中的锐化滤镜。
Matlab
% 采样决策
sampling_instants = round(samples_per_bit/2) : round(samples_per_bit) : length(equalized_signal);
sampled_values = equalized_signal(sampling_instants);
% 决策
decided_bits = sampled_values > 0;
% 计算误码率
ber = sum(rx_bits_aligned ~= prbs_aligned) / min_length;
采样点选择: 在每个比特周期的中间采样,因为这里眼图张开最大,最不容易出错。
相信大家在做通信原理的实验的时候,可能会疑问为什么要在比特周期的中间采样,这里给出了答案。
十、时域波形
Matlab
%% 9. 时域波形对比
figure('Position', [100, 100, 1200, 600], 'Name', '时域波形对比');
这个部分直观展示信号在发射、传输和均衡后的变化,帮助我们理解整个系统的行为。
十一、函数定义部分详解
1.PRBS生成函数
Matlab
function data = generate_prbs(order, length_bits)
% 生成PRBS序列的核心:线性反馈移位寄存器
n = order; % PRBS阶数
prbs_length = 2^n - 1; % 最大长度
% 不同阶数的PRBS使用不同的反馈抽头
switch n
case 7
taps = [7, 6]; % PRBS-7:x⁷ + x⁶ + 1
% ... 其他阶数
end
% 初始化:移位寄存器全1
register = ones(1, n);
prbs = zeros(1, prbs_length);
% 生成序列
for i = 1:prbs_length
prbs(i) = register(n); % 输出最高位
feedback = mod(sum(register(taps)), 2); % 计算反馈值
register = [feedback, register(1:end-1)]; % 移位
end
这个generate_prbs函数不仅仅是生成一些0和1的简单代码。它是:
-
信号完整性分析的起点:没有标准测试信号,所有分析都是空中楼阁
-
系统性能的标尺:提供衡量系统好坏的客观标准
-
理论与实践的纽带:将抽象的数学原理转化为实际的工程工具
对我这个项目来说,它就像乐谱的基调,基础但不可或缺,简单但意义深远。
我们如何简单理解这个函数呢?可以想象测试电报系统:
-
随机电报:内容随机,难以验证
-
标准测试码:特定模式,易于识别错误
里面,有个陌生的词------线性反馈移位寄存器。
线性反馈移位寄存器(LFSR) 是数字系统的基本构建块,理解它有助于理解很多通信和加密算法。
2.眼图分析函数
这段calculate_eye_parameters函数是信号分析中的"医生诊断工具",它从眼图这个"心电图"中提取三个关键健康指标:
-
眼高 - 信号对噪声的免疫力,眼高越大越不容易出错
-
眼宽 - 信号对时间抖动的容忍度,眼宽越宽采样越安全
-
眼幅度 - 信号的动态范围,反映了系统整体状态
这三个数字将复杂的波形图转化为可量化的性能指标,让我们能像医生看体检报告一样判断系统健康度。
Matlab
function [eye_height, eye_width, eye_amplitude] = calculate_eye_parameters(eye_data, time_axis, bit_period)
% 找到比特周期中心位置
center_idx = round(length(time_axis)/2);
% 计算眼高(在最佳采样点处)
center_samples = eye_data(:, center_idx);
% 分离正负电平
positive_samples = center_samples(center_samples > 0);
negative_samples = center_samples(center_samples < 0);
if ~isempty(positive_samples) && ~isempty(negative_samples)
% 眼高 = 最小正电平 - 最大负电平
eye_height = min(positive_samples) - max(negative_samples);
else
eye_height = 0;
end
眼高的计算原理: 在最佳采样点,我们希望正电平尽可能高,负电平尽可能低,这样噪声容限最大。
之前发现:同一个地库,新手司机经常倒车蹭墙,而老司机却总能丝滑入库。
我们假设:
地库的停车位宽度是2.5米,车宽1.8米。理论上两边各有0.35米的余量,足够安全。但实际呢?
新手小李每次倒车:
有时偏左,左侧只剩0.1米
有时偏右,右侧只剩0.15米
最糟的一次,左边0.05米,右边0.1米
老司机王叔每次:
左边稳定在0.3米左右
右边稳定在0.35米左右
最差的一次,两边也都有0.25米
2.1信号完整性的隐喻
这个地库就是我们的通信信道 ,倒车过程就是信号传输:
眼高 = 停车余量的最小值
Matlab
% 眼高 = 最小正电平 - 最大负电平
% 对应:最小安全距离 - 最大侵入距离
小李的眼高 = min(0.1, 0.15) - max(0.05, 0.1)
= 0.1 - 0.1 = 0米(危险!)
王叔的眼高 = min(0.3, 0.35) - max(0.25, 0.25)
= 0.3 - 0.25 = 0.05米(安全)
眼宽 = 倒车轨迹的时间稳定性
小李:有时快有时慢,方向打得忽早忽晚
王叔:匀速倒车,转向时机几乎分秒不差
眼幅度 = 驾驶技术的全面性
不仅看能否停进去,还要看是否优雅、是否影响邻车、是否一次到位
这个时候让我们重新看看我们原来的代码,这段代码做的正是"地库安全评估系统"的工作 :
Matlab
function [eye_height, eye_width, eye_amplitude] = calculate_eye_parameters(eye_data, time_axis, bit_period)
% 找到最佳观察点(相当于倒车镜里的标准参考线)
center_idx = round(length(time_axis)/2);
% 收集所有车辆的位置数据(相当于监控录像回放)
center_samples = eye_data(:, center_idx);
% 分开统计左侧和右侧的距离
positive_samples = center_samples(center_samples > 0); % 右侧安全距离
negative_samples = center_samples(center_samples < 0); % 左侧安全距离
if ~isempty(positive_samples) && ~isempty(negative_samples)
% 计算眼高:最窄的有效通道宽度
eye_height = min(positive_samples) - max(negative_samples);
% 小李:0米 → 随时可能蹭墙
% 王叔:0.05米 → 安全缓冲充足
else
eye_height = 0; % 完全没有安全余量
end
那管理这个的看了这个之后,做了三件事:
-
加装引导灯(相当于信号均衡器)
-
在地面增加了LED引导线
-
相当于代码中的均衡器补偿高频损耗
-
-
优化反光镜角度(相当于时钟恢复)
-
调整了柱子反光镜的角度
-
相当于在最佳采样点观察信号
-
-
设置振动警示带(相当于误码检测)
-
在危险区域设置振动带
-
轮子压上就有触觉反馈
-
相当于接收端的错误检测机制
-
2.2这段代码的作用
这段看似简单的代码,实际上在回答一个根本问题:在不确定性的世界中,我们如何确保确定的可靠性?
-
面对噪声(其他车辆鸣笛、小孩跑动)
眼高告诉我们系统有多强的抗干扰能力
-
面对抖动(地面不平、视线遮挡)
眼宽告诉我们系统对时序误差的容忍度
-
面对变化(不同车型、不同光线)
眼幅度告诉我们系统的适应性和鲁棒性
十二、整个项目的源代码
Matlab
%% 基于MATLAB的高速数字信号完整性分析系统
% 作者:free-elcmacom
% 功能:眼图生成、抖动分析、BER估计等
clear all; close all; clc;
%% 1. 参数设置
fs = 100e9; % 采样频率 100 GHz
Ts = 1/fs; % 采样间隔
bit_rate = 10e9; % 比特率 10 Gbps
bit_period = 1/bit_rate; % 比特周期
samples_per_bit = fs/bit_rate; % 每比特采样点数
% 系统参数
num_bits = 10000; % 总比特数
rise_time = 0.1 * bit_period; % 上升时间
channel_length = 0.5; % 通道长度(米)
material_er = 4.0; % 介电常数
%% 2. 生成PRBS测试序列
fprintf('生成PRBS测试序列...\n');
prbs_data = generate_prbs(7, num_bits);
%% 3. 信号编码(NRZ格式)
fprintf('信号编码...\n');
tx_signal = 2*prbs_data - 1; % 转换为±1V
% 上采样到模拟波形
tx_waveform = [];
for i = 1:length(tx_signal)
tx_waveform = [tx_waveform, tx_signal(i) * ones(1, round(samples_per_bit))];
end
% 确保长度一致
tx_waveform = tx_waveform(1:num_bits*round(samples_per_bit));
%% 4. 通道建模(传输线效应)
fprintf('通道建模...\n');
% 创建带限通道模型(低通滤波器模拟带宽限制)
channel_bandwidth = 0.7 * bit_rate; % 通道带宽
nyquist_freq = fs/2;
cutoff_normalized = channel_bandwidth / nyquist_freq;
% 设计FIR滤波器模拟通道
filter_order = 100;
b = fir1(filter_order, cutoff_normalized, 'low');
channel_response = filter(b, 1, tx_waveform);
% 添加传输线损耗(频率相关)
f = linspace(0, fs/2, length(b));
alpha_db = 0.2 * sqrt(f/1e9); % 损耗 dB/inch
alpha_linear = 10.^(-alpha_db/20);
% 确保维度匹配
alpha_linear = alpha_linear(1:length(b));
b_loss = b .* alpha_linear;
% 应用损耗滤波器
rx_signal_noiseless = filter(b_loss, 1, channel_response);
%% 5. 添加噪声和抖动
fprintf('添加噪声和抖动...\n');
% 添加高斯白噪声
SNR_dB = 20; % 信噪比
signal_power = mean(rx_signal_noiseless.^2);
noise_power = signal_power / (10^(SNR_dB/10));
noise = sqrt(noise_power) * randn(size(rx_signal_noiseless));
% 添加确定性抖动
dj_pp = 0.05 * bit_period; % 峰峰值确定性抖动
deterministic_jitter = dj_pp * sin(2*pi*bit_rate/10 * (0:length(rx_signal_noiseless)-1)*Ts);
% 添加随机抖动
rj_rms = 0.02 * bit_period; % RMS随机抖动
random_jitter = rj_rms * randn(size(rx_signal_noiseless));
% 总抖动
total_jitter = deterministic_jitter + random_jitter;
% 应用抖动到信号(通过重采样)
t = (0:length(rx_signal_noiseless)-1) * Ts;
t_jittered = t + total_jitter;
% 插值得到带抖动的信号
rx_signal_jittered = interp1(t, rx_signal_noiseless, t_jittered, 'linear', 'extrap');
% 最终接收信号(带噪声和抖动)
rx_signal = rx_signal_jittered + noise;
%% 6. 生成眼图
fprintf('生成眼图...\n');
% 调用眼图生成函数
plot_eye_diagram(rx_signal, samples_per_bit, bit_period, fs, 100);
%% 7. 频率响应分析
fprintf('频率响应分析...\n');
figure('Position', [100, 100, 1200, 400], 'Name', '频率响应分析');
% 计算传输函数
[H, freq] = freqz(b_loss, 1, 1024, fs);
subplot(1, 3, 1);
semilogx(freq/1e9, 20*log10(abs(H)), 'b-', 'LineWidth', 2);
xlabel('频率 (GHz)');
ylabel('幅度 (dB)');
title('通道频率响应');
grid on;
% 计算插入损耗
insertion_loss = -20*log10(abs(H));
subplot(1, 3, 2);
plot(freq/1e9, insertion_loss, 'r-', 'LineWidth', 2);
xlabel('频率 (GHz)');
ylabel('插入损耗 (dB)');
title('插入损耗 vs 频率');
grid on;
% 群延迟
[gd, freq_gd] = grpdelay(b_loss, 1, 1024, fs);
subplot(1, 3, 3);
plot(freq_gd/1e9, gd/1e-12, 'g-', 'LineWidth', 2);
xlabel('频率 (GHz)');
ylabel('群延迟 (ps)');
title('群延迟');
grid on;
%% 8. 误码率分析
fprintf('误码率分析...\n');
% 信号均衡(简单CTLE)
f_cut = bit_rate/2;
[bl, al] = butter(3, f_cut/(fs/2), 'high');
equalized_signal = filter(bl, al, rx_signal);
% 采样决策
sampling_instants = round(samples_per_bit/2) : round(samples_per_bit) : length(equalized_signal);
sampled_values = equalized_signal(sampling_instants);
% 确保长度匹配
min_length = min(length(sampled_values), num_bits);
sampled_values = sampled_values(1:min_length);
% 决策
decided_bits = sampled_values > 0;
% 计算误码率
rx_bits_aligned = decided_bits(1:min_length);
prbs_aligned = prbs_data(1:min_length);
ber = sum(rx_bits_aligned ~= prbs_aligned) / min_length;
% 显示结果
fprintf('\n====== 信号完整性分析报告 ======\n');
fprintf('比特率: %.1f Gbps\n', bit_rate/1e9);
fprintf('采样率: %.1f GHz\n', fs/1e9);
fprintf('估算BER: %.2e\n', ber);
fprintf('信噪比: %.1f dB\n', SNR_dB);
fprintf('随机抖动(RMS): %.1f ps\n', rj_rms*1e12);
fprintf('确定性抖动(峰峰值): %.1f ps\n', dj_pp*1e12);
fprintf('通道带宽: %.1f GHz\n', channel_bandwidth/1e9);
fprintf('传输比特数: %d\n', min_length);
fprintf('误码数: %d\n', sum(rx_bits_aligned ~= prbs_aligned));
fprintf('================================\n');
%% 9. 时域波形对比
figure('Position', [100, 100, 1200, 600], 'Name', '时域波形对比');
% 显示前200个比特
bits_to_show = 200;
samples_to_show = min(bits_to_show * round(samples_per_bit), length(tx_waveform));
time_window = (0:samples_to_show-1) * Ts * 1e9;
subplot(3, 1, 1);
plot(time_window, tx_waveform(1:samples_to_show), 'b-', 'LineWidth', 1);
title('发射信号');
xlabel('时间 (ns)');
ylabel('幅度 (V)');
grid on;
xlim([time_window(1), time_window(end)]);
subplot(3, 1, 2);
plot(time_window, rx_signal_noiseless(1:samples_to_show), 'r-', 'LineWidth', 1);
title('接收信号(无噪声)');
xlabel('时间 (ns)');
ylabel('幅度 (V)');
grid on;
xlim([time_window(1), time_window(end)]);
subplot(3, 1, 3);
plot(time_window, equalized_signal(1:samples_to_show), 'g-', 'LineWidth', 1);
hold on;
% 绘制采样点(前几个比特)
num_sampled_bits = min(bits_to_show, length(sampling_instants));
sampling_times = sampling_instants(1:num_sampled_bits) * Ts * 1e9;
sampling_values = sampled_values(1:num_sampled_bits);
stem(sampling_times, sampling_values, 'r', 'filled', 'MarkerSize', 5);
title('均衡后信号与采样点');
xlabel('时间 (ns)');
ylabel('幅度 (V)');
grid on;
xlim([time_window(1), time_window(end)]);
legend('均衡信号', '采样点', 'Location', 'best');
%% 10. 眼图模板测试(可选)
% 如果需要运行模板测试,取消下面的注释
% fprintf('进行眼图模板测试...\n');
% mask_violations = check_mask_violations(eye_data, time_axis, bit_period);
fprintf('\n信号完整性分析完成!\n');
fprintf('查看生成的图形以分析系统性能。\n');
%% ==================== 函数定义部分 ====================
% 注意:所有函数定义必须在主脚本代码之后
%% PRBS生成函数
function data = generate_prbs(order, length_bits)
% 生成PRBS序列
n = order;
prbs_length = 2^n - 1;
% 根据阶数选择反馈抽头
switch n
case 7
taps = [7, 6];
case 9
taps = [9, 5];
case 11
taps = [11, 9];
case 15
taps = [15, 14];
case 23
taps = [23, 18];
case 31
taps = [31, 28];
otherwise
taps = [n, n-1];
end
% 初始化移位寄存器
register = ones(1, n);
prbs = zeros(1, prbs_length);
for i = 1:prbs_length
prbs(i) = register(n);
feedback = mod(sum(register(taps)), 2);
register = [feedback, register(1:end-1)];
end
% 重复序列以达到所需长度
repeats = ceil(length_bits / prbs_length);
data = repmat(prbs, 1, repeats);
data = data(1:length_bits);
end
%% 眼图参数计算函数
function [eye_height, eye_width, eye_amplitude] = calculate_eye_parameters(eye_data, time_axis, bit_period)
% 计算眼图参数
% 找到比特周期中心位置
center_idx = round(length(time_axis)/2);
% 计算眼高(在最佳采样点处)
center_samples = eye_data(:, center_idx);
% 分离正负电平
positive_samples = center_samples(center_samples > 0);
negative_samples = center_samples(center_samples < 0);
if ~isempty(positive_samples) && ~isempty(negative_samples)
eye_height = min(positive_samples) - max(negative_samples);
else
eye_height = 0;
end
% 简化计算眼宽(实际应基于眼图测量)
eye_width = 0.7 * bit_period * 1e12; % ps
% 计算眼幅度
eye_amplitude = max(eye_data(:)) - min(eye_data(:));
end
%% 眼图绘制函数
function plot_eye_diagram(signal, samples_per_bit, bit_period, fs, num_eyes)
% 眼图绘制函数
Ts = 1/fs;
samples_per_eye = round(2 * samples_per_bit); % 显示两个比特周期
num_samples = length(signal);
% 计算可以提取多少个眼图段
num_segments = floor(num_samples / samples_per_bit) - 1;
num_segments = min(num_segments, num_eyes * round(samples_per_bit));
% 准备存储所有眼图轨迹
eye_data = [];
% 提取每个比特段的波形
for i = 1:num_segments
start_idx = (i-1) * round(samples_per_bit) + 1;
end_idx = min(start_idx + samples_per_eye - 1, num_samples);
if end_idx <= num_samples && (end_idx-start_idx+1) == samples_per_eye
segment = signal(start_idx:end_idx);
eye_data = [eye_data; segment(:)']; % 确保是行向量
end
end
if isempty(eye_data)
error('无法提取足够的眼图数据,请检查参数设置');
end
% 创建时间轴(两个比特周期)
time_axis = (0:samples_per_eye-1) * Ts * 1e12; % 转换为ps
% 绘制眼图
figure('Position', [100, 100, 1000, 600], 'Name', '眼图分析');
% 主眼图
subplot(2, 3, [1 2 4 5]);
hold on;
% 绘制所有轨迹(限制数量避免过载)
max_traces = min(200, size(eye_data, 1));
for i = 1:max_traces
plot(time_axis, eye_data(i, :), 'b-', 'LineWidth', 0.1, 'Color', [0, 0.4470, 0.7410, 0.1]);
end
% 计算眼图统计
mean_eye = mean(eye_data, 1);
std_eye = std(eye_data, 0, 1);
% 绘制平均眼图
plot(time_axis, mean_eye, 'r-', 'LineWidth', 2);
% 绘制眼图模板(可根据标准调整)
template_upper = mean_eye + 3*std_eye;
template_lower = mean_eye - 3*std_eye;
plot(time_axis, template_upper, 'g--', 'LineWidth', 1.5);
plot(time_axis, template_lower, 'g--', 'LineWidth', 1.5);
xlabel('时间 (ps)');
ylabel('幅度 (V)');
title('眼图分析');
grid on;
hold off;
% 标记重要参数
xline(bit_period*1e12, 'k--', 'LineWidth', 1.5, 'Alpha', 0.7);
xline(2*bit_period*1e12, 'k--', 'LineWidth', 1.5, 'Alpha', 0.7);
yline(0, 'k-', 'LineWidth', 1, 'Alpha', 0.7);
% 眼图参数计算
[eye_height, eye_width, eye_amplitude] = calculate_eye_parameters(eye_data, time_axis, bit_period);
% 参数显示
subplot(2, 3, 3);
axis off;
text(0.1, 0.9, '眼图参数:', 'FontSize', 12, 'FontWeight', 'bold');
text(0.1, 0.8, sprintf('眼高: %.3f V', eye_height), 'FontSize', 10);
text(0.1, 0.7, sprintf('眼宽: %.1f ps', eye_width), 'FontSize', 10);
text(0.1, 0.6, sprintf('眼幅度: %.3f V', eye_amplitude), 'FontSize', 10);
text(0.1, 0.5, sprintf('轨迹数: %d', size(eye_data, 1)), 'FontSize', 10);
text(0.1, 0.4, sprintf('比特率: %.1f Gbps', 1/(bit_period*1e9)), 'FontSize', 10);
% 直方图分析(眼图中心采样点分布)
subplot(2, 3, 6);
center_idx = round(size(eye_data, 2)/2);
center_samples = eye_data(:, center_idx);
histogram(center_samples, 30);
xlabel('幅度 (V)');
ylabel('频次');
title('眼图中心采样分布');
grid on;
end
%% 眼图模板测试函数
function mask_violations = check_mask_violations(eye_data, time_axis, bit_period)
% 检查模板违规
% 定义简单眼图模板(可根据标准调整)
ui = bit_period * 1e12; % 单位间隔(ps)
% 模板坐标(归一化)
mask_x_normalized = [0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.0, 0.8, 0.6, 0.4, 0.2, 0] * 2;
mask_y_upper_normalized = [0.15, 0.05, 0.02, 0.02, 0.05, 0.15, 0.85, 0.95, 0.98, 0.98, 0.95, 0.85];
mask_y_lower_normalized = [0.15, 0.05, 0.02, 0.02, 0.05, 0.15, 0.15, 0.05, 0.02, 0.02, 0.05, 0.15];
% 缩放模板
eye_amplitude = max(eye_data(:)) - min(eye_data(:));
eye_center = mean(eye_data(:));
mask_x = mask_x_normalized * ui;
mask_y_upper = eye_center + mask_y_upper_normalized * eye_amplitude/2;
mask_y_lower = eye_center + mask_y_lower_normalized * eye_amplitude/2 - eye_amplitude;
% 绘制模板
figure('Position', [100, 100, 800, 600], 'Name', '眼图模板测试');
hold on;
% 绘制眼图轨迹
for i = 1:min(100, size(eye_data, 1))
plot(time_axis, eye_data(i, :), 'b-', 'LineWidth', 0.1, 'Color', [0, 0, 1, 0.1]);
end
% 绘制模板
fill(mask_x, mask_y_upper, 'r', 'FaceAlpha', 0.3, 'EdgeColor', 'r', 'LineWidth', 1.5);
fill(mask_x, mask_y_lower, 'r', 'FaceAlpha', 0.3, 'EdgeColor', 'r', 'LineWidth', 1.5);
% 检查违规点
violations = 0;
for i = 1:size(eye_data, 1)
% 检查每个点是否在模板内
for j = 1:size(eye_data, 2)
point_x = time_axis(j);
point_y = eye_data(i, j);
% 检查是否在上模板内
in_upper = inpolygon(point_x, point_y, mask_x, mask_y_upper);
% 检查是否在下模板内
in_lower = inpolygon(point_x, point_y, mask_x, mask_y_lower);
if in_upper || in_lower
violations = violations + 1;
% 标记违规点
plot(point_x, point_y, 'ro', 'MarkerSize', 6, 'LineWidth', 2);
end
end
end
xlabel('时间 (ps)');
ylabel('幅度 (V)');
title(sprintf('眼图模板测试 - 违规点: %d', violations));
grid on;
hold off;
mask_violations = violations;
if violations > 0
fprintf('眼图模板测试失败! 发现 %d 个违规点。\n', violations);
else
fprintf('眼图模板测试通过!\n');
end
end
十三、项目分析结果
1.眼图分析
1.1图像的特征描述如下
主眼图区域:蓝色透明的数百条轨迹叠加,形成"眼睛"形状
红色平均眼图:所有轨迹的平均值,代表最可能的信号路径
绿色3σ边界:±3倍标准差的范围,定义了信号波动的正常区间
黑色参考线:比特周期边界和零电平参考
右侧参数面板:眼高、眼宽、眼幅度等量化指标
底部直方图:眼图中心采样点的分布统计

上面的还是太刻板了,下面我举个例子让大家理解一下:
想象你是一名交响乐指挥 ,眼图就是你乐团的集体演奏记录
蓝色轨迹:每个乐手每次演奏的细微差异
小提琴手A这次稍微快了一点
大提琴手B这次力度轻了一些
长笛手C这次音准偏高了一点点
红色平均眼图:乐团整体的标准演奏
经过无数次排练后的理想效果
指挥期望听到的完美表现
绿色边界:指挥可以容忍的误差范围
小提前3%的音准偏差,可以接受
鼓点5毫秒的提前或延后,还能合拍
直方图:对关键音符(比特中心点)的统计分析
大部分乐手在这个音符上都准确命中
少数几次偏差较大,但仍在可控范围内
这张图的深层含义 :它展示了在确定性 (红色主线)与随机性 (蓝色散点)之间的工程容忍度(绿色边界)。好的系统不是没有误差,而是把误差控制在允许范围内。
2.频率响应分析
由三个子图组成:
通道频率响应(蓝色曲线)
横轴:频率(GHz),对数坐标
纵轴:幅度(dB),显示通道对不同频率的增益/衰减
关键特征:随着频率增加,衰减逐渐增大
插入损耗(红色曲线)
横轴:频率(GHz)
纵轴:损耗(dB),正值表示信号损失
关键特征:损耗随频率增加而增加
群延迟(绿色曲线)
横轴:频率(GHz)
纵轴:延迟(ps)
关键特征:不同频率分量通过通道的时间差异

现在换一个比喻:你是一名声学工程师 ,在测试一个音乐厅的音响效果:
频率响应图:音乐厅对不同音高的响应
低频(鼓声、贝斯):容易传播,衰减小 → 观众席后排仍能感受震撼
高频(小提琴、三角铁):容易吸收,衰减大 → 后排听众可能听不清细节
插入损耗图:音乐厅对音量的"收费"标准
100Hz低音:每米衰减0.1dB → 门票便宜
10GHz高音:每米衰减2dB → 门票昂贵
这就是为什么远程传输时,高频信息容易丢失
群延迟图:不同音高到达时间的差异
低音:传播速度慢,晚到 → 像体型大的观众入场慢
高音:传播速度快,先到 → 像灵活的观众迅速就座
如果差异太大,鼓点和旋律就对不齐了
这张图的深层含义 :它揭示了物理世界对理想信号的系统性扭曲 。带宽不是有或无的二元问题,而是多或少的连续渐变。
**3.**时域波形对比
它由下面三个纵向排列的子图构成:
发射信号(蓝色)
清晰的方波,完美的0-1转换
理想的上升沿和下降沿
整齐的幅度层次
接收信号(无噪声)(红色)
波形变圆滑,上升沿变缓
幅度略有衰减
码间干扰明显(一个比特影响相邻比特)
均衡后信号与采样点(绿色+红色采样点)
经过均衡处理的信号
红色采样点显示在每个比特中心的最佳采样时刻

在这里我又讲个故事来理解时域波形对比:
现在让我们回到最开始的地库倒车比喻,但这次有了行车记录仪回放:
发射信号:驾校教练的标准示范
方向盘打得精准到位
油门刹车控制恰到好处
每个动作都如同教科书般完美
接收信号:新手学员的实际操作
方向盘有晃动,转向不干脆
刹车踩得重,车身有晃动
倒车轨迹有偏差,需要多次修正
均衡后信号:安装了倒车辅助系统后的操作
电子稳定系统补偿了方向盘的抖动
自动刹车系统平滑了制动过程
轨迹修正系统把车拉回正确路径
红色采样点:驾校考官在每个关键节点的评分
在车辆到达每个标记点时记录位置
根据这些离散评分判断是否通过考试
虽然只观察几个时间点,但足以评估整个过程
4.三个图的总结
如果把这个信号完整性分析项目比作一部扣人心弦的侦探剧,那么眼图分析就是令人屏息的第一幕:案发现场勘查 。当"信号质量下降"这个"数字命案"发生时,眼图就像技术侦探第一时间拍摄的犯罪现场全息照片 。图中数百条蓝色轨迹宛如嫌疑人留下的所有可能脚印------有些凌乱交错,有些清晰可辨,共同勾勒出犯罪活动的复杂脉络。而那条红色平均眼图,则如同法医对典型伤口模式的深度分析,揭示了最常见的攻击手法和伤害特征。更关键的是,绿色边界线划定了嫌疑人的活动范围,它告诉调查组:"凶手就在这个时空区域内活动,重点排查!"最后的直方图则像目击者证词的统计汇总------当多数人描述嫌犯身高在170-180厘米之间时,我们就有了精准的排查方向。整个眼图就是一张多维度、立体化的数字犯罪现场重建图,让无形的信号质量问题变得有形可察。
当现场勘查完成后,侦探剧进入更烧脑的第二幕:犯罪动机调查 。此时频率响应分析扮演着犯罪心理侧写师 的角色,它要回答那个根本问题:"为什么信号会被'杀'?"频率响应曲线如同对犯罪动机的精密分析------是低频段的"仇杀"(系统资源争夺)?中频段的"财杀"(能量损耗)?还是高频段的"情杀"(时序错乱)?插入损耗图则像凶器威力测试实验室,要判断造成伤害的是"刀伤"(阻抗失配)、"枪伤"(反射干扰)还是"毒药"(介质损耗)。最巧妙的是群延迟分析,它如同犯罪时间线的法医学重建------是"先下毒后捅刀"(相位失真导致时序错位)?还是"同时多手段攻击"(多径效应)?这一整套频率分析,实际上是在对数字系统的"生理机能"进行全方位体检,找出信号衰弱的病根究竟在血液循环系统(低频响应)还是神经系统(高频响应)。
随着调查深入,侦探剧迎来高潮的第三幕:犯罪过程还原 。时域波形对比就是这场数字犯罪的情景重现。发射信号如同受害人遇害前的日常生活轨迹------规律、稳定、可预测,每个比特都像他按部就班的日常行程。接收信号则展现了案发当天的异常行为------波形开始扭曲,节奏被打乱,那些完美的方波变得圆滑而迟疑,就像受害人那天的行踪突然出现了不可解释的偏差。均衡后信号则堪比警方的高科技案件重建模拟,通过数字算法"修正"了部分失真,试图还原最接近真相的过程。而那些精确分布的红色采样点,正是调查组提取的关键时间点证据------就像在监控录像中标出嫌疑人出现的准确时刻。整个时域分析完成了从"静态现场"到"动态过程"的认知飞跃,让我们不仅能看见"尸体"(劣化的信号),更能推演出"谋杀"是如何一步一步发生的。
十四、学习建议
当你运行这个代码,看到这三个画布时,请思考:
眼图:如果眼图几乎闭合(眼高很小),你最先调整哪个参数?为什么?
提示:先增加SNR(降低噪声),还是先减少抖动?
频率响应:如果群延迟曲线有突变(不是平滑变化),可能是什么原因?
提示:回忆传输线理论中的阻抗不连续
时域波形:如果均衡后信号还不如均衡前,问题出在哪里?
提示:均衡器设计的前提假设是什么?
十五、总结
这三张画布共同讲述了一个技术:
在确定性中寻找规律,在随机性中设立边界,在动态中把握时机。
眼图教我们:在噪声中识别信号,在变化中找到稳定
频率响应教我们:在限制中优化性能,在约束中创造可能
时域波形教我们:在过程中选择时机,在连续中提取离散
这不仅是信号完整性分析的精髓,也是应对复杂工程问题的方法论。