MATLAB信号分析:眼图生成与高速系统评估

今天,我想与大家分享一个我在准备考研期间完成的MATLAB信号完整性分析项目。这个项目不仅是对我专业知识的检验,也是我自己依然保持学术热情的方式。我希望通过这篇文章,让更多同学了解信号完整性分析的重要性,并学会如何用MATLAB实现眼图生成和高速系统评估。

一、什么是信号完整性分析?

想象一下,你和朋友玩传话游戏。第一个人说"今天晚上七点看电影",传到第十个人时变成了"明天早上九点去游泳"。在高速数字系统中,类似的问题也在发生:信号在传输过程中会"失真",导致接收端无法正确识别原始信息。

信号完整性就是研究如何让信号在高速传输中保持"原汁原味"的科学。在5G、高速互联网、数据中心等现代通信系统中,信号完整性分析至关重要。

二、项目概述:我们要做什么?

我们将用MATLAB创建一个完整的信号完整性分析系统,主要包括:

  1. 生成测试信号(PRBS序列)

  2. 模拟信号在信道中的传输

  3. 添加真实的噪声和抖动

  4. 生成并分析眼图

  5. 评估系统性能

三、参数设置

部分概念的解释与理解:

  1. 采样频率 (fs):就像拍照的帧率,越高越能捕捉信号的细节

  2. 比特率:每秒传输的比特数,10 Gbps就是每秒100亿个比特

  3. 比特周期:传输一个比特需要的时间

  4. 每比特采样点数:在每个比特周期内,我们要用多少个点来描述它

假设我们要分析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;

频率响应的三个关键指标

  1. 幅度响应:不同频率的衰减程度

  2. 插入损耗:信号通过信道后的功率损失

  3. 群延迟:不同频率分量的时间延迟差异

群延迟的重要性: 如果不同频率到达时间不同,信号就会失真,就像乐队成员节奏不一致。

九、误码率分析

这是最终的考核指标:有多少比特出错了?

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的简单代码。它是:

  1. 信号完整性分析的起点:没有标准测试信号,所有分析都是空中楼阁

  2. 系统性能的标尺:提供衡量系统好坏的客观标准

  3. 理论与实践的纽带:将抽象的数学原理转化为实际的工程工具

对我这个项目来说,它就像乐谱的基调,基础但不可或缺,简单但意义深远。

我们如何简单理解这个函数呢?可以想象测试电报系统:

  • 随机电报:内容随机,难以验证

  • 标准测试码:特定模式,易于识别错误

里面,有个陌生的词------线性反馈移位寄存器。

线性反馈移位寄存器(LFSR) 是数字系统的基本构建块,理解它有助于理解很多通信和加密算法。

2.眼图分析函数

这段calculate_eye_parameters函数是信号分析中的"医生诊断工具",它从眼图这个"心电图"中提取三个关键健康指标:

  1. 眼高 - 信号对噪声的免疫力,眼高越大越不容易出错

  2. 眼宽 - 信号对时间抖动的容忍度,眼宽越宽采样越安全

  3. 眼幅度 - 信号的动态范围,反映了系统整体状态

这三个数字将复杂的波形图转化为可量化的性能指标,让我们能像医生看体检报告一样判断系统健康度。

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

那管理这个的看了这个之后,做了三件事:

  1. 加装引导灯(相当于信号均衡器)

    • 在地面增加了LED引导线

    • 相当于代码中的均衡器补偿高频损耗

  2. 优化反光镜角度(相当于时钟恢复)

    • 调整了柱子反光镜的角度

    • 相当于在最佳采样点观察信号

  3. 设置振动警示带(相当于误码检测)

    • 在危险区域设置振动带

    • 轮子压上就有触觉反馈

    • 相当于接收端的错误检测机制

2.2这段代码的作用

这段看似简单的代码,实际上在回答一个根本问题:在不确定性的世界中,我们如何确保确定的可靠性?

  1. 面对噪声(其他车辆鸣笛、小孩跑动)

    眼高告诉我们系统有多强的抗干扰能力

  2. 面对抖动(地面不平、视线遮挡)

    眼宽告诉我们系统对时序误差的容忍度

  3. 面对变化(不同车型、不同光线)

    眼幅度告诉我们系统的适应性和鲁棒性

十二、整个项目的源代码

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.频率响应分析

由三个子图组成:

  1. 通道频率响应(蓝色曲线)

    • 横轴:频率(GHz),对数坐标

    • 纵轴:幅度(dB),显示通道对不同频率的增益/衰减

    • 关键特征:随着频率增加,衰减逐渐增大

  2. 插入损耗(红色曲线)

    • 横轴:频率(GHz)

    • 纵轴:损耗(dB),正值表示信号损失

    • 关键特征:损耗随频率增加而增加

  3. 群延迟(绿色曲线)

    • 横轴:频率(GHz)

    • 纵轴:延迟(ps)

    • 关键特征:不同频率分量通过通道的时间差异

现在换一个比喻:你是一名声学工程师 ,在测试一个音乐厅的音响效果

频率响应图:音乐厅对不同音高的响应

  • 低频(鼓声、贝斯):容易传播,衰减小 → 观众席后排仍能感受震撼

  • 高频(小提琴、三角铁):容易吸收,衰减大 → 后排听众可能听不清细节

插入损耗图:音乐厅对音量的"收费"标准

  • 100Hz低音:每米衰减0.1dB → 门票便宜

  • 10GHz高音:每米衰减2dB → 门票昂贵

  • 这就是为什么远程传输时,高频信息容易丢失

群延迟图:不同音高到达时间的差异

  • 低音:传播速度慢,晚到 → 像体型大的观众入场慢

  • 高音:传播速度快,先到 → 像灵活的观众迅速就座

  • 如果差异太大,鼓点和旋律就对不齐了

这张图的深层含义 :它揭示了物理世界对理想信号的系统性扭曲带宽不是有或无的二元问题,而是多或少的连续渐变。

**3.**时域波形对比

它由下面三个纵向排列的子图构成:

  1. 发射信号(蓝色)

    • 清晰的方波,完美的0-1转换

    • 理想的上升沿和下降沿

    • 整齐的幅度层次

  2. 接收信号(无噪声)(红色)

    • 波形变圆滑,上升沿变缓

    • 幅度略有衰减

    • 码间干扰明显(一个比特影响相邻比特)

  3. 均衡后信号与采样点(绿色+红色采样点)

    • 经过均衡处理的信号

    • 红色采样点显示在每个比特中心的最佳采样时刻

在这里我又讲个故事来理解时域波形对比:

现在让我们回到最开始的地库倒车比喻,但这次有了行车记录仪回放

发射信号:驾校教练的标准示范

  • 方向盘打得精准到位

  • 油门刹车控制恰到好处

  • 每个动作都如同教科书般完美

接收信号:新手学员的实际操作

  • 方向盘有晃动,转向不干脆

  • 刹车踩得重,车身有晃动

  • 倒车轨迹有偏差,需要多次修正

均衡后信号:安装了倒车辅助系统后的操作

  • 电子稳定系统补偿了方向盘的抖动

  • 自动刹车系统平滑了制动过程

  • 轨迹修正系统把车拉回正确路径

红色采样点:驾校考官在每个关键节点的评分

  • 在车辆到达每个标记点时记录位置

  • 根据这些离散评分判断是否通过考试

  • 虽然只观察几个时间点,但足以评估整个过程

4.三个图的总结

如果把这个信号完整性分析项目比作一部扣人心弦的侦探剧,那么眼图分析就是令人屏息的第一幕:案发现场勘查 。当"信号质量下降"这个"数字命案"发生时,眼图就像技术侦探第一时间拍摄的犯罪现场全息照片 。图中数百条蓝色轨迹宛如嫌疑人留下的所有可能脚印------有些凌乱交错,有些清晰可辨,共同勾勒出犯罪活动的复杂脉络。而那条红色平均眼图,则如同法医对典型伤口模式的深度分析,揭示了最常见的攻击手法和伤害特征。更关键的是,绿色边界线划定了嫌疑人的活动范围,它告诉调查组:"凶手就在这个时空区域内活动,重点排查!"最后的直方图则像目击者证词的统计汇总------当多数人描述嫌犯身高在170-180厘米之间时,我们就有了精准的排查方向。整个眼图就是一张多维度、立体化的数字犯罪现场重建图,让无形的信号质量问题变得有形可察。

当现场勘查完成后,侦探剧进入更烧脑的第二幕:犯罪动机调查 。此时频率响应分析扮演着犯罪心理侧写师 的角色,它要回答那个根本问题:"为什么信号会被'杀'?"频率响应曲线如同对犯罪动机的精密分析------是低频段的"仇杀"(系统资源争夺)?中频段的"财杀"(能量损耗)?还是高频段的"情杀"(时序错乱)?插入损耗图则像凶器威力测试实验室,要判断造成伤害的是"刀伤"(阻抗失配)、"枪伤"(反射干扰)还是"毒药"(介质损耗)。最巧妙的是群延迟分析,它如同犯罪时间线的法医学重建------是"先下毒后捅刀"(相位失真导致时序错位)?还是"同时多手段攻击"(多径效应)?这一整套频率分析,实际上是在对数字系统的"生理机能"进行全方位体检,找出信号衰弱的病根究竟在血液循环系统(低频响应)还是神经系统(高频响应)。

随着调查深入,侦探剧迎来高潮的第三幕:犯罪过程还原 。时域波形对比就是这场数字犯罪的情景重现。发射信号如同受害人遇害前的日常生活轨迹------规律、稳定、可预测,每个比特都像他按部就班的日常行程。接收信号则展现了案发当天的异常行为------波形开始扭曲,节奏被打乱,那些完美的方波变得圆滑而迟疑,就像受害人那天的行踪突然出现了不可解释的偏差。均衡后信号则堪比警方的高科技案件重建模拟,通过数字算法"修正"了部分失真,试图还原最接近真相的过程。而那些精确分布的红色采样点,正是调查组提取的关键时间点证据------就像在监控录像中标出嫌疑人出现的准确时刻。整个时域分析完成了从"静态现场"到"动态过程"的认知飞跃,让我们不仅能看见"尸体"(劣化的信号),更能推演出"谋杀"是如何一步一步发生的。

十四、学习建议

当你运行这个代码,看到这三个画布时,请思考:

  1. 眼图:如果眼图几乎闭合(眼高很小),你最先调整哪个参数?为什么?

    提示:先增加SNR(降低噪声),还是先减少抖动?

  2. 频率响应:如果群延迟曲线有突变(不是平滑变化),可能是什么原因?

    提示:回忆传输线理论中的阻抗不连续

  3. 时域波形:如果均衡后信号还不如均衡前,问题出在哪里?

提示:均衡器设计的前提假设是什么?

十五、总结

这三张画布共同讲述了一个技术:

在确定性中寻找规律,在随机性中设立边界,在动态中把握时机。

  • 眼图教我们:在噪声中识别信号,在变化中找到稳定

  • 频率响应教我们:在限制中优化性能,在约束中创造可能

  • 时域波形教我们:在过程中选择时机,在连续中提取离散

这不仅是信号完整性分析的精髓,也是应对复杂工程问题的方法论。

相关推荐
多则惑少则明1 小时前
【算法题4】找出字符串中的最长回文子串(Java版)
java·开发语言·数据结构·算法
【建模先锋】1 小时前
基于Python的智能故障诊断系统 | SmartDiag AI (基础版)V1.0 正式发布!
开发语言·人工智能·python·故障诊断·智能分析平台·大数据分析平台·智能故障诊断系统
T.O.P_KING1 小时前
Common Go Mistakes(IV 字符串)
开发语言·后端·golang
我命由我123451 小时前
微信小程序 - 避免在 data 初始化中引用全局变量
开发语言·前端·javascript·微信小程序·小程序·前端框架·js
盒马盒马1 小时前
Rust:Trait 标签 & 常见特征
开发语言·后端·rust
liulilittle1 小时前
C++ SSE/AVX/SHA/AES指令集检查,用于程序定向优化。
开发语言·c++·cpu·asm·detect·il·features
小龙在山东1 小时前
基于C++空项目运行汇编语言
开发语言·c++
MM_MS1 小时前
WinForm+C#小案例--->写一个记事本程序
开发语言·计算机视觉·c#·visual studio
郝学胜-神的一滴2 小时前
Linux信号屏蔽字详解:原理、应用与实践
linux·服务器·开发语言·c++·程序人生