Python信号分析项目:高速数字系统的眼图破案记

一、引言

去年,我在学习通信原理的时候,做了一个有趣的实验:用一根50米长的网线传输10Gbps的高速数据。理论上应该完美传输,结果接收端看到的却是"满屏雪花"。那一刻我突然意识到------高速数字世界里的比特,就像深夜酒吧里传话的醉汉,每个环节都可能让信息失真。

这让我想起了福尔摩斯的名言:"当你排除了所有不可能,剩下的无论多么难以置信,一定是真相。" 在信号完整性分析中,我们就是要成为数字世界的福尔摩斯,找出比特"撒谎"的真相。

今天,我要分享的就是这样一个"侦探工具箱"------用Python实现的信号完整性分析系统。它不仅能生成眼图、分析抖动,还能像侦探一样推理出系统问题的根源。

二、项目概述

该项目的核心功能如下:

  1. PRBS测试序列生成 - 数字系统的"标准试纸"

  2. 通道建模与失真模拟 - 信号旅途的"路况模拟器"

  3. 眼图生成与分析 - 信号健康的"心电图仪"

  4. 频率响应诊断 - 系统带宽的"听力测试"

  5. 误码率评估 - 通信质量的"成绩单"

三、代码详解:侦探破案的每个步骤

1.第一步:设定案发现场参数

python 复制代码
# 参数设置 - 定义"犯罪现场"的时空坐标
fs = 100e9           # 采样频率:100GHz,相当于每秒拍1000亿张照片
bit_rate = 10e9      # 比特率:10Gbps,每秒传递100亿个比特
samples_per_bit = fs/bit_rate  # 每比特10个采样点

num_bits = 10000     # 分析10000个比特,足够统计显著性

现实比喻 :想象你在观察高速公路的车流。fs是你的摄像机帧率,bit_rate是车流量,samples_per_bit是每辆车被拍到的照片数量。

2.第二步:准备测试信号 - PRBS生成器

python 复制代码
def generate_prbs(order, length_bits):
    """生成PRBS序列 - 数字系统的'标准台词'"""
    # PRBS的核心:线性反馈移位寄存器
    # 就像一个有记忆的密码生成器
    n = order  # 阶数决定序列复杂度
    register = np.ones(n, dtype=int)  # 初始化寄存器
    
    for i in range(2**n - 1):
        # 关键算法:反馈与移位
        feedback = register[-1] ^ register[-2]  # 最后两位异或
        register = np.roll(register, 1)        # 整体右移
        register[0] = feedback                  # 新位插入最左
        
    return register_to_bits(register)

深度理解

  • PRBS-7(127位周期)就像一段127个字的绕口令,包含了所有可能的发音组合

  • 选择PRBS-7的原因:足够复杂又不会太长,就像用绕口令测试播音员的嘴皮子

  • 数学原理:最大长度序列,在周期内0和1几乎各半,自相关函数接近δ函数

完整的项目源代码:

python 复制代码
"""
高速数字信号完整性分析系统 - Python版(修复版)
作者:free-elcmacom
功能:眼图生成、抖动分析、BER估计等
环境:Python 3.10, PyCharm IDE
所需库:numpy, scipy, matplotlib
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from scipy.interpolate import interp1d
import warnings
warnings.filterwarnings('ignore')

# ==================== 字体配置 ====================
# 修复字体显示问题
try:
    # 尝试使用系统可用的中文字体
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS', 'DejaVu Sans']
    plt.rcParams['axes.unicode_minus'] = True  # 解决负号显示问题
    print("字体配置成功")
except:
    print("字体配置失败,使用默认字体")

# ==================== 函数定义部分 ====================

def generate_prbs(order, length_bits):
    """
    生成PRBS序列
    :param order: PRBS阶数
    :param length_bits: 需要生成的比特数
    :return: PRBS序列
    """
    n = order
    prbs_length = 2**n - 1

    # 根据阶数选择反馈抽头
    if n == 7:
        taps = [7, 6]  # PRBS-7:x⁷ + x⁶ + 1
    elif n == 9:
        taps = [9, 5]  # PRBS-9:x⁹ + x⁵ + 1
    elif n == 11:
        taps = [11, 9]  # PRBS-11:x¹¹ + x⁹ + 1
    elif n == 15:
        taps = [15, 14]  # PRBS-15:x¹⁵ + x¹⁴ + 1
    elif n == 23:
        taps = [23, 18]  # PRBS-23:x²³ + x¹⁸ + 1
    elif n == 31:
        taps = [31, 28]  # PRBS-31:x³¹ + x²⁸ + 1
    else:
        taps = [n, n-1]  # 默认抽头

    # 初始化移位寄存器
    register = np.ones(n, dtype=int)
    prbs = np.zeros(prbs_length, dtype=int)

    # 生成序列
    for i in range(prbs_length):
        prbs[i] = register[-1]  # 输出最高位

        # 计算反馈值
        feedback = 0
        for tap in taps:
            feedback ^= register[tap-1]  # tap是从1开始计数的

        # 移位
        register = np.roll(register, 1)
        register[0] = feedback

    # 重复序列以达到所需长度
    repeats = int(np.ceil(length_bits / prbs_length))
    data = np.tile(prbs, repeats)
    return data[:length_bits]

def calculate_eye_parameters(eye_data, time_axis, bit_period):
    """
    计算眼图参数
    :param eye_data: 眼图数据矩阵,每行是一个眼图轨迹
    :param time_axis: 时间轴
    :param bit_period: 比特周期
    :return: 眼高, 眼宽, 眼幅度
    """
    # 找到比特周期中心位置
    center_idx = len(time_axis) // 2

    # 计算眼高(在最佳采样点处)
    center_samples = eye_data[:, center_idx]

    # 分离正负电平
    positive_samples = center_samples[center_samples > 0]
    negative_samples = center_samples[center_samples < 0]

    if len(positive_samples) > 0 and len(negative_samples) > 0:
        eye_height = np.min(positive_samples) - np.max(negative_samples)
    else:
        eye_height = 0

    # 简化计算眼宽(实际应基于眼图测量)
    eye_width = 0.7 * bit_period * 1e12  # ps

    # 计算眼幅度
    eye_amplitude = np.max(eye_data) - np.min(eye_data)

    return eye_height, eye_width, eye_amplitude

def plot_eye_diagram(signal_data, samples_per_bit, bit_period, fs, num_eyes=100):
    """
    绘制眼图
    :param signal_data: 输入信号
    :param samples_per_bit: 每比特采样点数
    :param bit_period: 比特周期
    :param fs: 采样频率
    :param num_eyes: 显示的眼图数量
    """
    Ts = 1/fs
    samples_per_eye = int(2 * samples_per_bit)  # 显示两个比特周期
    num_samples = len(signal_data)

    # 计算可以提取多少个眼图段
    num_segments = int(np.floor(num_samples / samples_per_bit)) - 1
    num_segments = min(num_segments, int(num_eyes * samples_per_bit))

    # 准备存储所有眼图轨迹
    eye_data = []

    # 提取每个比特段的波形
    for i in range(num_segments):
        start_idx = i * int(samples_per_bit)
        end_idx = min(start_idx + samples_per_eye, num_samples)

        if end_idx < num_samples and (end_idx - start_idx) == samples_per_eye:
            segment = signal_data[start_idx:end_idx]
            eye_data.append(segment)

    if not eye_data:
        raise ValueError("无法提取足够的眼图数据,请检查参数设置")

    eye_data = np.array(eye_data)

    # 创建时间轴(两个比特周期)
    time_axis = np.arange(samples_per_eye) * Ts * 1e12  # 转换为ps

    # 创建眼图
    fig = plt.figure(figsize=(12, 8), dpi=100)
    fig.suptitle('眼图分析', fontsize=14, fontweight='bold')

    # 主眼图
    ax_main = plt.subplot2grid((2, 3), (0, 0), colspan=2, rowspan=2)

    # 绘制所有轨迹(限制数量避免过载)
    max_traces = min(200, len(eye_data))
    for i in range(max_traces):
        ax_main.plot(time_axis, eye_data[i], 'b-', linewidth=0.1, alpha=0.1)

    # 计算眼图统计
    mean_eye = np.mean(eye_data, axis=0)
    std_eye = np.std(eye_data, axis=0)

    # 绘制平均眼图
    ax_main.plot(time_axis, mean_eye, 'r-', linewidth=2, label='平均眼图')

    # 绘制眼图模板(可根据标准调整)
    template_upper = mean_eye + 3 * std_eye
    template_lower = mean_eye - 3 * std_eye
    ax_main.plot(time_axis, template_upper, 'g--', linewidth=1.5, label='±3σ边界')
    ax_main.plot(time_axis, template_lower, 'g--', linewidth=1.5)

    ax_main.set_xlabel('时间 (ps)')
    ax_main.set_ylabel('幅度 (V)')
    ax_main.grid(True, alpha=0.3)
    ax_main.legend(loc='upper right')

    # 标记重要参数
    ax_main.axvline(bit_period * 1e12, color='k', linestyle='--', linewidth=1.5, alpha=0.7)
    ax_main.axvline(2 * bit_period * 1e12, color='k', linestyle='--', linewidth=1.5, alpha=0.7)
    ax_main.axhline(0, color='k', linestyle='-', linewidth=1, alpha=0.7)

    # 眼图参数计算
    eye_height, eye_width, eye_amplitude = calculate_eye_parameters(eye_data, time_axis, bit_period)

    # 参数显示
    ax_text = plt.subplot2grid((2, 3), (0, 2))
    ax_text.axis('off')
    text_y = 0.9
    text_params = [
        '眼图参数:',
        f'眼高: {eye_height:.3f} V',
        f'眼宽: {eye_width:.1f} ps',
        f'眼幅度: {eye_amplitude:.3f} V',
        f'轨迹数: {len(eye_data)}',
        f'比特率: {1/(bit_period*1e9):.1f} Gbps'
    ]

    for i, text in enumerate(text_params):
        if i == 0:
            ax_text.text(0.1, text_y - i*0.12, text, fontsize=12, fontweight='bold')
        else:
            ax_text.text(0.1, text_y - i*0.12, text, fontsize=10)

    # 直方图分析(眼图中心采样点分布)
    ax_hist = plt.subplot2grid((2, 3), (1, 2))
    center_idx = len(time_axis) // 2
    center_samples = eye_data[:, center_idx]

    ax_hist.hist(center_samples, bins=30, edgecolor='black', alpha=0.7)
    ax_hist.set_xlabel('幅度 (V)')
    ax_hist.set_ylabel('频次')
    ax_hist.set_title('眼图中心采样分布')
    ax_hist.grid(True, alpha=0.3)

    plt.tight_layout()
    plt.show()

    return eye_data, time_axis

def check_mask_violations(eye_data, time_axis, bit_period):
    """
    检查眼图模板违规
    :param eye_data: 眼图数据
    :param time_axis: 时间轴
    :param bit_period: 比特周期
    :return: 违规点数量
    """
    from matplotlib.path import Path

    # 定义简单眼图模板(可根据标准调整)
    ui = bit_period * 1e12  # 单位间隔(ps)

    # 模板坐标(归一化)
    mask_x_normalized = np.array([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 = np.array([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 = np.array([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 = np.max(eye_data) - np.min(eye_data)
    eye_center = np.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

    # 创建模板路径
    upper_polygon = np.column_stack([mask_x, mask_y_upper])
    lower_polygon = np.column_stack([mask_x, mask_y_lower])
    upper_path = Path(upper_polygon)
    lower_path = Path(lower_polygon)

    # 绘制模板
    fig = plt.figure(figsize=(10, 6), dpi=100)
    ax = plt.gca()

    # 绘制眼图轨迹
    max_traces = min(100, len(eye_data))
    for i in range(max_traces):
        ax.plot(time_axis, eye_data[i], 'b-', linewidth=0.1, alpha=0.1)

    # 绘制模板
    ax.fill(mask_x, mask_y_upper, 'r', alpha=0.3, edgecolor='r', linewidth=1.5)
    ax.fill(mask_x, mask_y_lower, 'r', alpha=0.3, edgecolor='r', linewidth=1.5)

    # 检查违规点
    violations = 0
    violation_points = []

    for i in range(len(eye_data)):
        for j in range(len(time_axis)):
            point_x = time_axis[j]
            point_y = eye_data[i, j]

            # 检查是否在模板内
            point = np.array([[point_x, point_y]])
            in_upper = upper_path.contains_points(point)[0]
            in_lower = lower_path.contains_points(point)[0]

            if in_upper or in_lower:
                violations += 1
                violation_points.append((point_x, point_y))

    # 标记违规点
    if violation_points:
        violation_points = np.array(violation_points)
        ax.plot(violation_points[:, 0], violation_points[:, 1], 'ro',
                markersize=6, linewidth=2, label=f'违规点 ({violations}个)')
        ax.legend()

    ax.set_xlabel('时间 (ps)')
    ax.set_ylabel('幅度 (V)')
    ax.set_title(f'眼图模板测试 - 违规点: {violations}')
    ax.grid(True, alpha=0.3)

    plt.tight_layout()
    plt.show()

    if violations > 0:
        print(f'眼图模板测试失败! 发现 {violations} 个违规点。')
    else:
        print('眼图模板测试通过!')

    return violations


# ==================== 主程序部分 ====================

def main():
    print("=" * 60)
    print("高速数字信号完整性分析系统 - Python修复版")
    print("=" * 60)

    # 1. 参数设置
    print("\n1. 参数设置...")
    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  # 介电常数

    print(f"   采样频率: {fs/1e9:.1f} GHz")
    print(f"   比特率: {bit_rate/1e9:.1f} Gbps")
    print(f"   每比特采样点数: {samples_per_bit:.1f}")

    # 2. 生成PRBS测试序列
    print("\n2. 生成PRBS测试序列...")
    prbs_data = generate_prbs(7, num_bits)
    print(f"   生成长度为 {len(prbs_data)} 的PRBS-7序列")

    # 3. 信号编码(NRZ格式)
    print("\n3. 信号编码(NRZ格式)...")
    tx_signal = 2 * prbs_data - 1  # 转换为±1V

    # 上采样到模拟波形
    print("   上采样到模拟波形...")
    tx_waveform = np.repeat(tx_signal, int(samples_per_bit))
    tx_waveform = tx_waveform[:num_bits * int(samples_per_bit)]
    print(f"   发射波形长度: {len(tx_waveform)} 个采样点")

    # 4. 通道建模(传输线效应)
    print("\n4. 通道建模...")

    # 创建带限通道模型
    channel_bandwidth = 0.7 * bit_rate  # 通道带宽
    nyquist_freq = fs/2
    cutoff_normalized = channel_bandwidth / nyquist_freq

    # 设计FIR滤波器模拟通道
    filter_order = 100
    b = signal.firwin(filter_order, cutoff_normalized, window='hamming')

    # 应用滤波器
    channel_response = signal.lfilter(b, 1.0, tx_waveform)

    # 添加传输线损耗(频率相关)
    f = np.linspace(0, fs/2, len(b))
    alpha_db = 0.2 * np.sqrt(f/1e9)  # 损耗 dB/inch
    alpha_linear = 10**(-alpha_db/20)

    # 确保维度匹配
    alpha_linear = alpha_linear[:len(b)]
    b_loss = b * alpha_linear

    # 应用损耗滤波器
    rx_signal_noiseless = signal.lfilter(b_loss, 1.0, channel_response)

    print(f"   通道带宽: {channel_bandwidth/1e9:.1f} GHz")

    # 5. 添加噪声和抖动
    print("\n5. 添加噪声和抖动...")

    # 添加高斯白噪声
    SNR_dB = 20  # 信噪比
    signal_power = np.mean(rx_signal_noiseless**2)
    noise_power = signal_power / (10**(SNR_dB/10))
    noise = np.sqrt(noise_power) * np.random.randn(len(rx_signal_noiseless))

    # 添加确定性抖动
    dj_pp = 0.05 * bit_period  # 峰峰值确定性抖动
    deterministic_jitter = dj_pp * np.sin(2 * np.pi * bit_rate/10 *
                                          np.arange(len(rx_signal_noiseless)) * Ts)

    # 添加随机抖动
    rj_rms = 0.02 * bit_period  # RMS随机抖动
    random_jitter = rj_rms * np.random.randn(len(rx_signal_noiseless))

    # 总抖动
    total_jitter = deterministic_jitter + random_jitter

    # 应用抖动到信号(通过重采样)
    t = np.arange(len(rx_signal_noiseless)) * Ts
    t_jittered = t + total_jitter

    # 插值得到带抖动的信号
    interpolator = interp1d(t, rx_signal_noiseless, kind='linear',
                           bounds_error=False, fill_value='extrapolate')
    rx_signal_jittered = interpolator(t_jittered)

    # 最终接收信号(带噪声和抖动)
    rx_signal = rx_signal_jittered + noise

    print(f"   信噪比: {SNR_dB} dB")
    print(f"   确定性抖动: {dj_pp*1e12:.1f} ps (峰峰值)")
    print(f"   随机抖动: {rj_rms*1e12:.1f} ps (RMS)")

    # 6. 生成眼图
    print("\n6. 生成眼图...")
    eye_data, time_axis = plot_eye_diagram(rx_signal, samples_per_bit, bit_period, fs, 100)

    # 7. 频率响应分析
    print("\n7. 频率响应分析...")

    fig, axes = plt.subplots(1, 3, figsize=(15, 4))
    fig.suptitle('频率响应分析', fontsize=14, fontweight='bold')

    # 计算传输函数
    w, H = signal.freqz(b_loss, worN=1024, fs=fs)

    # 通道频率响应
    axes[0].semilogx(w/1e9, 20*np.log10(np.abs(H)), 'b-', linewidth=2)
    axes[0].set_xlabel('频率 (GHz)')
    axes[0].set_ylabel('幅度 (dB)')
    axes[0].set_title('通道频率响应')
    axes[0].grid(True, alpha=0.3)

    # 插入损耗
    insertion_loss = -20*np.log10(np.abs(H))
    axes[1].plot(w/1e9, insertion_loss, 'r-', linewidth=2)
    axes[1].set_xlabel('频率 (GHz)')
    axes[1].set_ylabel('插入损耗 (dB)')
    axes[1].set_title('插入损耗 vs 频率')
    axes[1].grid(True, alpha=0.3)

    # 群延迟
    w_gd, gd = signal.group_delay((b_loss, 1.0), w=1024, fs=fs)
    axes[2].plot(w_gd/1e9, gd*1e12, 'g-', linewidth=2)  # 转换为ps
    axes[2].set_xlabel('频率 (GHz)')
    axes[2].set_ylabel('群延迟 (ps)')
    axes[2].set_title('群延迟')
    axes[2].grid(True, alpha=0.3)

    plt.tight_layout()
    plt.show()

    # 8. 误码率分析
    print("\n8. 误码率分析...")

    # 信号均衡(简单CTLE)
    f_cut = bit_rate/2
    b_eq, a_eq = signal.butter(3, f_cut/(fs/2), btype='high')
    equalized_signal = signal.lfilter(b_eq, a_eq, rx_signal)

    # 采样决策
    sampling_instants = np.arange(int(samples_per_bit/2), len(equalized_signal),
                                  int(samples_per_bit)).astype(int)
    sampled_values = equalized_signal[sampling_instants]

    # 确保长度匹配
    min_length = min(len(sampled_values), num_bits)
    sampled_values = sampled_values[:min_length]

    # 决策
    decided_bits = (sampled_values > 0).astype(int)

    # 计算误码率
    rx_bits_aligned = decided_bits[:min_length]
    prbs_aligned = prbs_data[:min_length]

    # 计算误码率(BER)
    error_count = np.sum(rx_bits_aligned != prbs_aligned)
    ber = error_count / min_length

    # 显示结果
    print("\n" + "=" * 60)
    print("信号完整性分析报告")
    print("=" * 60)
    print(f"比特率: {bit_rate/1e9:.1f} Gbps")
    print(f"采样率: {fs/1e9:.1f} GHz")
    print(f"估算BER: {ber:.2e}")
    print(f"信噪比: {SNR_dB:.1f} dB")
    print(f"随机抖动(RMS): {rj_rms*1e12:.1f} ps")
    print(f"确定性抖动(峰峰值): {dj_pp*1e12:.1f} ps")
    print(f"通道带宽: {channel_bandwidth/1e9:.1f} GHz")
    print(f"传输比特数: {min_length}")
    print(f"误码数: {error_count}")
    print("=" * 60)

    # 9. 时域波形对比
    print("\n9. 时域波形对比...")

    fig, axes = plt.subplots(3, 1, figsize=(12, 8))
    fig.suptitle('时域波形对比', fontsize=14, fontweight='bold')

    # 显示前200个比特
    bits_to_show = 200
    samples_to_show = min(bits_to_show * int(samples_per_bit), len(tx_waveform))
    time_window = np.arange(samples_to_show) * Ts * 1e9  # 转换为ns

    # 发射信号
    axes[0].plot(time_window, tx_waveform[:samples_to_show], 'b-', linewidth=1)
    axes[0].set_title('发射信号')
    axes[0].set_xlabel('时间 (ns)')
    axes[0].set_ylabel('幅度 (V)')
    axes[0].grid(True, alpha=0.3)
    axes[0].set_xlim([time_window[0], time_window[-1]])

    # 接收信号(无噪声)
    axes[1].plot(time_window, rx_signal_noiseless[:samples_to_show], 'r-', linewidth=1)
    axes[1].set_title('接收信号(无噪声)')
    axes[1].set_xlabel('时间 (ns)')
    axes[1].set_ylabel('幅度 (V)')
    axes[1].grid(True, alpha=0.3)
    axes[1].set_xlim([time_window[0], time_window[-1]])

    # 均衡后信号与采样点
    axes[2].plot(time_window, equalized_signal[:samples_to_show], 'g-', linewidth=1, label='均衡信号')

    # 绘制采样点(前几个比特)
    num_sampled_bits = min(bits_to_show, len(sampling_instants))
    sampling_times = sampling_instants[:num_sampled_bits] * Ts * 1e9
    sampling_values = sampled_values[:num_sampled_bits]

    # 修复stem函数调用(移除了use_line_collection参数)
    axes[2].stem(sampling_times, sampling_values, linefmt='r-', markerfmt='ro', basefmt=' ', label='采样点')
    axes[2].set_title('均衡后信号与采样点')
    axes[2].set_xlabel('时间 (ns)')
    axes[2].set_ylabel('幅度 (V)')
    axes[2].grid(True, alpha=0.3)
    axes[2].set_xlim([time_window[0], time_window[-1]])
    axes[2].legend(loc='best')

    plt.tight_layout()
    plt.show()

    # 10. 眼图模板测试(可选)
    print("\n10. 眼图模板测试(可选)...")
    run_mask_test = input("是否运行眼图模板测试?(y/n): ").lower().strip()

    if run_mask_test == 'y':
        violations = check_mask_violations(eye_data, time_axis, bit_period)

    print("\n" + "=" * 60)
    print("信号完整性分析完成!")
    print("=" * 60)

    # 保存结果到文件
    print("\n保存分析结果到文件...")
    try:
        with open('signal_integrity_report.txt', 'w', encoding='utf-8') as f:
            f.write("=" * 60 + "\n")
            f.write("信号完整性分析报告\n")
            f.write("=" * 60 + "\n")
            f.write(f"比特率: {bit_rate/1e9:.1f} Gbps\n")
            f.write(f"采样率: {fs/1e9:.1f} GHz\n")
            f.write(f"估算BER: {ber:.2e}\n")
            f.write(f"信噪比: {SNR_dB:.1f} dB\n")
            f.write(f"随机抖动(RMS): {rj_rms*1e12:.1f} ps\n")
            f.write(f"确定性抖动(峰峰值): {dj_pp*1e12:.1f} ps\n")
            f.write(f"通道带宽: {channel_bandwidth/1e9:.1f} GHz\n")
            f.write(f"传输比特数: {min_length}\n")
            f.write(f"误码数: {error_count}\n")
            f.write("=" * 60 + "\n")
        print("报告已保存到 signal_integrity_report.txt")
    except Exception as e:
        print(f"保存报告时出错: {e}")

    return ber, error_count, min_length


if __name__ == "__main__":
    # 显示项目信息
    print("\n欢迎使用高速数字信号完整性分析系统")
    print("版本: Python 3.10")
    print("开发环境: PyCharm")
    print("\n系统将执行以下步骤:")
    print("1. 参数设置")
    print("2. 生成PRBS测试序列")
    print("3. 信号编码")
    print("4. 通道建模")
    print("5. 添加噪声和抖动")
    print("6. 生成眼图")
    print("7. 频率响应分析")
    print("8. 误码率分析")
    print("9. 时域波形对比")
    print("10. 眼图模板测试(可选)")

    # 运行主程序
    input("\n按Enter键开始分析...")
    ber, error_count, min_length = main()

    # 添加调试信息
    print("\n" + "=" * 60)
    print("调试信息:")
    print("=" * 60)
    print(f"原始误码率: {ber}")
    print(f"误码数/总比特数: {error_count}/{min_length}")

    # 如果误码率过高,提供调整建议
    if ber > 0.1:
        print("\n" + "=" * 60)
        print("警告: 误码率过高!")
        print("建议调整以下参数:")
        print("1. 增加信噪比 (SNR_dB)")
        print("2. 减少抖动参数 (dj_pp, rj_rms)")
        print("3. 增加通道带宽")
        print("4. 使用更复杂的均衡器")

        print("=" * 60)

        # 提供快速修正代码
        print("\n快速修正建议:")
        print("在参数设置部分尝试以下值:")
        print("SNR_dB = 30  # 增加信噪比")
        print("dj_pp = 0.02 * bit_period  # 减少确定性抖动")
        print("rj_rms = 0.01 * bit_period  # 减少随机抖动")
        print("channel_bandwidth = 0.8 * bit_rate  # 增加带宽")

最终得到的信号完整性的分析报告文件显示的内容:

相关推荐
嫂子的姐夫39 分钟前
03-多进程
爬虫·python·多进程
AI弟41 分钟前
大语言模型进阶(一)之大语言模型基础
人工智能·python·深度学习·机器学习·语言模型·自然语言处理
小毅&Nora41 分钟前
【后端】【JAVA】协程:从虚拟线程到协程编程的全面解析
java·开发语言
坚持就完事了42 分钟前
__name__和__main__到底是啥?
python
A charmer43 分钟前
内存泄漏、死锁:定位排查工具+解决方案(C/C++ 实战指南)
c语言·开发语言·c++
没事多睡觉66644 分钟前
JavaScript 中 this 指向教程
开发语言·前端·javascript
wjs20241 小时前
HTML 基础
开发语言
Aerelin1 小时前
scrapy的介绍与使用
前端·爬虫·python·scrapy·js
pilaf19901 小时前
Rust练习题
开发语言·后端·rust