RGB‑TOT 全架构系统仿真:红外波长簇光通信完整验证

声明:本文为民间原创技术构想,仅作逻辑推演与学术交流,不涉及任何国家秘密及未公开实体项目,保留全部署名权与著作权。

🔗前置理论:《电视像素给光,互联上了一课,波长即比特,颜色即逻辑》 🔗底层硬件单元:三进制 CMOS 拓扑与仿真验证(已作为补丁增补在前序三进制架构博文)

摘要

基于 RGB‑TOT(红外波长簇)三进制光通信理论,本文交付完整系统级联合仿真工程。 直接复用已验证的三态 CMOS 单元作为信号源,完整仿真 TWM、BBM、POR、CSMM、HNT 五种光传输模式;实现 WDM 光栅接收、CIS 拜耳面阵成像接收两套解调通路;兼容 PC‑CDM 荧光转换信道模型。复现色散、光噪声、成像串扰等各类信道效应,全部结果支持代码复现。

一、工程概况

工程文件:rgb_tot_full_sim.py,约 1000 行,可直接上传 Gitee 开源。

环境:仅依赖 numpy,matplotlib 非必需。无绘图库时自动降级输出标准 SVG 矢量图,文件自动输出至 Windows 桌面。

输出产物:

  • cmos_timing.svg CMOS 三态单元引脚时序波形

  • optical_spectrum.svg 发射光谱 / 信道损伤后接收光谱对比

  • ser_snr_curve.svg SER‑SNR 误码率对比曲线(WDM / CIS 接收机)

  • 运行示例

  • -*- coding: utf-8 -*-

    """

    ====================================================================

    RGB-TOT 全架构联合仿真

    【三态CMOS拓扑单元 + RGB-TOT光通信链路】

    ====================================================================

    本文件为民间原创技术构想,仅逻辑推演、学术交流用途,

    不构成任何产品、协议或标准定义。请勿用于实际工程部署。


    仿真链路(自底向上共 5 层):


    ① 信号源层 ------ 三态 CMOS 拓扑单元

    引脚定义:pin3 双向输入输出(采样时隙使能/供电)

    pin4 触发控制(M1 输出节点)

    pin5 最终输出(M2 输出节点)

    逻辑符号:-1 / 0 / +1

    硬件物理限制复现:

    • 竞争冒险(race hazard):pin3/pin4 边沿重叠时,

    由于 CMOS 传输门时延差,pin5 出现短毛刺;

    • 拓扑失效(topology failure):pin1/pin2 供电拓扑

    缺失时,单元无驱动通路,内部逻辑状态恒为 0,

    仅读取 pin4/pin5 电平会发生译码错误。

    ② 光发射层 ------ 5 种架构模式(可运行期切换):

    模式1 TWM :三进制波长键控(WSK)

    -1→λ1 单独亮;+1→λ3 单独亮;0→无光(零功耗0态)

    帧边界 = λ1+λ2 / λ2+λ3 双波长重合脉冲

    模式2 BBM :二进制爆发模式,λ1/λ2/λ3 三色独立 OOK

    模式3 POR :PAM4-over-RGB 混合调制(每路 4 电平)

    模式4 CSMM :复合光谱多维复用(单色3档×3路 + 双色2配比×3组

    • 无光 = 16 物理符号)

    模式5 HNT :十六进制原生传输(0~F 共 16 业务态,

    剩余 3 个态用作帧同步/CRC/链路空闲)

    ③ 光信道层 ------ 可配置 SNR(dB)

    高斯光噪声 + 波长相关光强衰减 + 色散时序偏移(亚采样)

    • 可开关的 PC-CDM 荧光转换增强(增益与去相干散斑噪声)

    ④ 接收解调层 ------ 两种接收模型可切换:

    模型① 传统 WDM 光栅 + PD 阵列直接功率检测

    模型② CBDM-CIS 面阵成像解调:

    RGGB 拜耳滤镜混色采样 + ISP 去噪(中值滤波)

    • 最小二乘功率比解析

    可叠加 PC-CDM 荧光转换前置板。

    ⑤ 统计输出 ------ 各模式误符号率 SER、帧同步检出统计、

    SNR 扫描生成 SER-SNR 曲线。


    文件输出(自动保存到 Windows 桌面,路径自适应,无硬编码):

    cmos_timing.svg / .png # CMOS 引脚时序波形

    optical_spectrum.svg / .png # 发射/接收对比光谱

    ser_snr_curve.svg / .png # SER-SNR 误符号率曲线

    依赖容错:无 matplotlib 时不抛异常,跳过绘图,仿真照常运行。

    ====================================================================

    """

    import os

    import sys

    import argparse

    import numpy as np

    ------------------------------------------------------------------

    0. matplotlib 可选依赖(无则跳过绘图,仿真照常)

    ------------------------------------------------------------------

    try:

    import matplotlib

    matplotlib.use("Agg") # 无头环境仍可保存

    import matplotlib.pyplot as plt

    HAVE_MPL = True

    except ImportError:

    HAVE_MPL = False

    ------------------------------------------------------------------

    1. Windows 桌面路径自动适配(禁止写死绝对路径)

    ------------------------------------------------------------------

    def get_desktop_path():

    """定位 Windows 桌面,兼容 OneDrive 重定向与中文用户名。

    候选顺序:

    1. ~/Desktop

    2. ~/OneDrive/Desktop

    3. ~/OneDrive/桌面

    4. ~/桌面

    全部不存在时回退到用户主目录(保证可写)。

    """

    home = os.path.expanduser("~")

    candidates = [

    os.path.join(home, "Desktop"),

    os.path.join(home, "OneDrive", "Desktop"),

    os.path.join(home, "OneDrive", "桌面"),

    os.path.join(home, "桌面"),

    ]

    for p in candidates:

    if os.path.isdir(p):

    return p

    os.makedirs(home, exist_ok=True)

    return home

    OUT_DIR = get_desktop_path()

    ------------------------------------------------------------------

    2. 全局仿真参数

    ------------------------------------------------------------------

    ---- 时隙 / 帧结构 ----

    N_SPS = 32 # 每时隙采样点数

    N_SYM = 8 # 每帧业务符号数

    N_FRAMES = 5 # 发送帧数

    GAP_SLOTS = 4 # 帧间空闲时隙数

    SEED = 42 # 随机种子(可复现)

    ---- 发射功率档位 ----

    P_LO, P_MID, P_HI = 0.30, 0.60, 1.00 # 单色 3 档功率(CSMM 用)

    P_FRAME = 2.00 # 帧头/帧尾满功率双峰标记

    RATIO_2_1 = (1.00, 0.45) # 双色 2:1 配比(主路, 从路)

    ---- 光信道参数 ----

    ALPHA = (0.80, 0.85, 0.75) # λ1/λ2/λ3 光强衰减系数(波长相关)

    DELAY = (-0.8, 0.0, 0.6) # 色散到达时延(采样点,负=提前)

    ---- 接收端判决阈值 ----

    THR_DET = 0.35 # 双峰共存检测(帧头/帧尾)

    THR_SYM = 0.40 # 三进制/二进制业务符号判定

    THR_FRAME = 1.20 # 满功率帧标记判定

    ---- PC-CDM 荧光转换增强参数 ----

    G_FLUOR = 1.8 # 荧光转换增益(>1 表示增强)

    K_SPECKLE = 0.06 # 去相干散斑噪声系数(乘性,随信号幅度)

    SPECKLE_FLOOR = 0.02 # 散斑底噪(绝对项)

    ---- CBDM-CIS 面阵成像参数 ----

    BAYER_NOISE = 0.06 # 拜耳像素传感器噪声 σ

    ---- 三态 CMOS 单元参数 ----

    CMOS_V_HIGH = 9.0 # CMOS 高电平电压

    CMOS_V_THR = 5.0 # 有效电平判定阈值(≥5V 视为有效)

    CMOS_PULSE_MIN = 5 # 最小有效脉冲宽度(采样点,短于此时尖峰=噪声)

    CMOS_STABLE = 60 # pin3 上电后的稳定延时

    CMOS_SAMP_START = 200 # 采样窗口起点

    CMOS_SAMP_END = 560 # 采样窗口终点

    CMOS_N = 800 # 每组 CMOS 用例采样点数

    CMOS_RACE_DELTA = 8 # 竞争冒险:pin3/pin4 边沿最小间隔(点数),

    小于该间隔视为边沿重叠 → 触发毛刺

    DEFAULT_MODE = "csmm" # 默认发射模式(可用 --mode 切换)

    DEFAULT_RX = "wdm" # 默认接收模型(wdm / cis)

    =====================================================================

    ① 信号源层:三态 CMOS 拓扑单元

    =====================================================================

    class CmosTernaryCell:

    """三态 CMOS 拓扑单元(M1 蓝色单元 → pin4;M2 黑色单元 → pin3/pin5)。

    物理约束复现:

    * 竞争冒险:当 pin3(M2 控制)与 pin4(M1 触发)在采样窗口内

    边沿间隔小于 CMOS_RACE_DELTA 时,两条通路传播时延不等,

    输出端 pin5 出现宽度 < CMOS_PULSE_MIN 的毛刺尖峰。

    正确采样器(带最小脉宽过滤)可滤除毛刺,无误触发;

    无过滤采样器会被毛刺误触发(用作对比演示)。

    * 拓扑失效:pin1/pin2 供电缺失 → 单元内部无驱动通路,

    真实逻辑状态恒为 0。此时 pin4/pin5 电平与 +1 完全相同,

    仅靠电压无法区分 → 必须同步读取 pin1/pin2 才能正确译码。

    逻辑状态判定(真实译码器,含 pin1/pin2):

    not topo_ok → 0(若 pin4 有效且 pin3 上电)否则 -1

    pin4 有效 & pin3 上电 → +1(驱动通路通) / 0(驱动通路断)

    其余 → -1

    """

    ---- 单用例时域仿真 ----

    @staticmethod

    def simulate(case, n=CMOS_N):

    """仿真一个 CMOS 用例,返回 (真实状态, 错误译码状态, 三路波形)。

    case 字段:

    pin4_base : pin4 基础电平(CMOS_V_HIGH / 0)

    pin3_on : 采样窗口内 pin3 是否上电

    drive_path : M2 驱动通路是否存在(用于区分 +1 / 0)

    topo_ok : pin1/pin2 供电拓扑是否有效(False → 拓扑失效)

    race : 是否注入竞争冒险(pin3/pin4 边沿重叠)

    noise : pin4 叠加噪声幅度(压力测试用)

    """

    t = np.arange(n, dtype=float)

    rng = np.random.default_rng(case.get("seed", 7))

    pin3:仅采样窗口内上电

    pin3 = np.zeros(n)

    if case"pin3_on":

    pin3CMOS_SAMP_START:CMOS_SAMP_END = CMOS_V_HIGH

    pin4:基础电平 + 可选噪声

    pin4 = np.full(n, case"pin4_base", dtype=float)

    amp = case.get("noise", 0.0)

    if amp > 0:

    noise = rng.normal(0.0, amp * 0.8, n)

    mask = rng.random(n) < 0.012 # 稀疏强毛刺

    noisemask += rng.uniform(CMOS_V_THR - 1, CMOS_V_THR + 1, mask.sum())

    pin4 += noise

    pin5:按真实状态生成

    真实状态由 topo_ok / drive_path / 采样时刻 pin4 有效性与 pin3 决定

    idx = CMOS_SAMP_START + CMOS_STABLE # 稳定后读点

    valid = CmosTernaryCell._is_valid_at(pin4, idx)

    pin3_on_now = pin3idx >= 0.5 * CMOS_V_HIGH

    pin5 = np.zeros(n)

    topo_ok = case.get("topo_ok", True)

    if not topo_ok:

    true_state = 0 if (valid and pin3_on_now) else -1

    elif valid and pin3_on_now:

    true_state = +1 if case.get("drive_path", True) else 0

    else:

    true_state = -1

    输出电平:+1 或拓扑失效下的 0(2.1 工况)均在窗口内输出 5V 有效电平;

    0(驱动断)与 -1 输出 0V。电平无法区分 0(拓扑失效)/+1,需 pin1/pin2。

    if true_state == +1 or (not topo_ok and true_state == 0):

    pin5CMOS_SAMP_START + CMOS_STABLE:CMOS_SAMP_END = CMOS_V_HIGH

    elif true_state == 0:

    pin5CMOS_SAMP_START + CMOS_STABLE:CMOS_SAMP_END = 0.0

    ---- 竞争冒险注入:pin3/pin4 边沿重叠 → pin5 毛刺 ----

    if case.get("race"):

    在 pin3 上电沿与 pin4 触发沿重叠处,pin5 输出出现窄毛刺

    race_pos = CMOS_SAMP_START + CMOS_RACE_DELTA // 2

    spike_w = 3 # 宽度 < PULSE_MIN

    pin5race_pos:race_pos + spike_w = CMOS_V_HIGH + 1.0

    同时 pin4 在相邻读点产生一个瞬时尖峰(模拟触发抖动)

    pin4race_pos + 1 += 3.0

    ---- 错误译码器:只读 pin4/pin5 电平,无视 pin1/pin2 ----

    wrong_state = +1 if (valid and pin3_on_now) else -1

    return true_state, wrong_state, pin3, pin4, pin5

    ---- 最小脉宽过滤的有效电平判定(滤除短尖峰) ----

    @staticmethod

    def _is_valid_at(signal, idx, thr=CMOS_V_THR, min_width=CMOS_PULSE_MIN):

    """检查 idx 处是否位于连续 ≥ min_width 个点的过阈值段中。"""

    n = len(signal)

    j = idx

    while j + 1 < n and signalj + 1 >= thr:

    j += 1

    k = idx

    while k - 1 >= 0 and signalk - 1 >= thr:

    k -= 1

    return (j - k + 1) >= min_width

    ------------------------------------------------------------------

    CMOS 测试向量:5 组(含竞争冒险 / 拓扑失效专项)

    ------------------------------------------------------------------

    CMOS_TEST_CASES = [

    { # C1: +1 正常工况 ------ pin4 有效、pin3 上电、驱动通路通

    "name": "C1 +1正常: pin4有效+pin3上电+驱动通",

    "pin4_base": CMOS_V_HIGH, "pin3_on": True,

    "drive_path": True, "topo_ok": True, "race": False, "noise": 0.5,

    "expected_true": +1, "seed": 11,

    },

    { # C2: 0 正常工况 ------ 驱动通路断

    "name": "C2 0正常: pin4有效+pin3上电+驱动断",

    "pin4_base": CMOS_V_HIGH, "pin3_on": True,

    "drive_path": False, "topo_ok": True, "race": False, "noise": 0.5,

    "expected_true": 0, "seed": 22,

    },

    { # C3: -1 正常工况 ------ pin4 无有效信号

    "name": "C3 -1正常: pin4无信号+pin3待机",

    "pin4_base": 0.0, "pin3_on": False,

    "drive_path": True, "topo_ok": True, "race": False, "noise": 0.0,

    "expected_true": -1, "seed": 33,

    },

    { # C4: 竞争冒险压力 ------ pin3/pin4 边沿重叠产生毛刺,

    正确采样器(脉宽过滤)滤除毛刺,仍判 +1

    "name": "C4 竞争冒险: 边沿重叠毛刺被滤除→+1",

    "pin4_base": CMOS_V_HIGH, "pin3_on": True,

    "drive_path": True, "topo_ok": True, "race": True, "noise": 0.0,

    "expected_true": +1, "seed": 44,

    },

    { # C5: 拓扑失效 ------ pin1/pin2 无电,真实状态 0;

    仅读 pin4/pin5 会误判 +1(漏洞演示)

    "name": "C5 拓扑失效: pin1/2无电→真实0(只读p4/p5误判+1)",

    "pin4_base": CMOS_V_HIGH, "pin3_on": True,

    "drive_path": True, "topo_ok": False, "race": False, "noise": 0.0,

    "expected_true": 0, "seed": 55,

    },

    ]

    def run_cmos_block():

    """运行全部 CMOS 测试用例。

    返回: (通过率, 三态符号帧列表, 拼接波形字典)

    ternary_frames : \[-1/0/+1, ... x N_SYM] x N_FRAMES(供发射层使用)

    wave : {"pin3","pin4","pin5"} 拼接波形(供波形图)

    samples : 采样窗口元数据(供波形图标注)

    """

    print("\n" + "=" * 76)

    print(" ① 信号源层:三态 CMOS 拓扑单元 (pin3 双向, pin4 触发, pin5 输出)")

    print("=" * 76)

    print(f" 有效电平阈值 {CMOS_V_THR}V 最小脉宽 {CMOS_PULSE_MIN} 点 "

    f"稳定延时 {CMOS_STABLE} 点 (竞争冒险注入间隔 <{CMOS_RACE_DELTA} 点)")

    n_pass = n_fail = 0

    pin3s, pin4s, pin5s = \[\], \[\], \[\]

    samples = \[\]

    rng = np.random.default_rng(SEED + 100)

    ternary_frames = \[\]

    print("-" * 76)

    print(f"{'用例':<4} {'测试描述':<44} {'真实':<4} {'正确译码':<7} {'只读p4/p5':<8} 结论")

    print("-" * 76)

    for i, case in enumerate(CMOS_TEST_CASES):

    ts, ws, p3, p4, p5 = CmosTernaryCell.simulate(case)

    ok = (ts == case"expected_true")

    n_pass += int(ok); n_fail += int(not ok)

    flag = "PASS" if ok else "FAIL"

    print(f"C{i+1:<3} {case'name':<44} {ts:+d} {ws:+d} "

    f"true={case'expected_true':+d} {flag}")

    pin3s.append(p3); pin4s.append(p4); pin5s.append(p5)

    samples.append({

    "idx": i + 1, "name": case"name", "ok": ok,

    "true": ts, "wrong": ws,

    "start": i * CMOS_N, "end": (i + 1) * CMOS_N,

    })

    收集三态流(C1-C5 状态直接作为发射层业务符号)

    ternary_frames.append(ts * N_SYM)

    pct = 100.0 * n_pass / len(CMOS_TEST_CASES)

    print("-" * 76)

    print(f" CMOS 单元测试通过率:{n_pass}/{len(CMOS_TEST_CASES)} = {pct:.1f}% "

    f"误触发 {n_fail} 次")

    补足 N_FRAMES 帧(若帧数不足则用随机三态补齐)

    while len(ternary_frames) < N_FRAMES:

    ternary_frames.append(list(rng.integers(-1, 2, size=N_SYM)))

    print("=" * 76)

    return {

    "pass_rate": pct,

    "ternary_frames": ternary_frames:N_FRAMES,

    "pin3": np.concatenate(pin3s),

    "pin4": np.concatenate(pin4s),

    "pin5": np.concatenate(pin5s),

    "samples": samples,

    }

    =====================================================================

    ② 光发射层:5 种架构模式

    =====================================================================

    光谱符号表(CSMM/HNT 共用):

    16 态 = 无光(1) + 单色3档×3路(9) + 双色2配比×3组合(6)

    出处:RGB-TOT 体系 CSMM 复合光谱多维复用 / HNT 十六进制原生传输

    SPECTRUM_16 = {

    0x0: (0.0, 0.0, 0.0),

    0x1: (P_LO, 0.0, 0.0), 0x2: (P_MID, 0.0, 0.0), 0x3: (P_HI, 0.0, 0.0),

    0x4: (0.0, P_LO, 0.0), 0x5: (0.0, P_MID, 0.0), 0x6: (0.0, P_HI, 0.0),

    0x7: (0.0, 0.0, P_LO), 0x8: (0.0, 0.0, P_MID), 0x9: (0.0, 0.0, P_HI),

    0xA: (RATIO_2_11, RATIO_2_11, 0.0),

    0xB: (RATIO_2_10, RATIO_2_11, 0.0),

    0xC: (RATIO_2_11, 0.0, RATIO_2_11),

    0xD: (RATIO_2_10, 0.0, RATIO_2_11),

    0xE: (0.0, RATIO_2_11, RATIO_2_11),

    0xF: (0.0, RATIO_2_10, RATIO_2_11),

    }

    SPECTRUM_16_IDX = sorted(SPECTRUM_16) # 0..15

    HNT 模式专用帧状态(16 业务态之外的 3 个特殊态):

    出处:RGB-TOT 体系 HNT ------ 剩余 3 态 = 帧同步 / CRC / 链路空闲

    HNT_FRAME_HEAD = (P_FRAME, P_FRAME, 0.0) # 帧同步特殊态

    HNT_FRAME_TAIL = (0.0, P_FRAME, P_FRAME) # CRC 特殊态

    HNT_IDLE = (0.0, 0.0, 0.0) # 链路空闲(零功耗)

    各模式帧头/帧尾标记(业务符号之外的边界标记)

    FRAME_MARK = {

    "twm": ((P_FRAME, P_FRAME, 0.0), (0.0, P_FRAME, P_FRAME)),

    "bbm": ((P_FRAME, P_FRAME, 0.0), (0.0, P_FRAME, P_FRAME)),

    "por": ((P_FRAME, P_FRAME, 0.0), (0.0, P_FRAME, P_FRAME)),

    "csmm": ((P_FRAME, P_FRAME, 0.0), (0.0, P_FRAME, P_FRAME)),

    "hnt": (HNT_FRAME_HEAD, HNT_FRAME_TAIL),

    }

    class Transmitter:

    """RGB-TOT 发射机:三态符号流 → 三路波长光强时隙序列。

    模式说明(出处均标注于类内):

    TWM ------ 三进制波长键控(WSK):-1→λ1、0→无光、+1→λ3,

    帧边界双波长重合脉冲(λ1+λ2 / λ2+λ3),0 态零功耗。

    BBM ------ 二进制爆发模式:三色独立 OOK,每时隙 3 bit。

    POR ------ PAM4-over-RGB:每路 4 电平,3 路共 4³=64 符号空间。

    CSMM------ 复合光谱多维复用:16 态复合光谱(单色/双色+功率档)。

    HNT ------ 十六进制原生传输:16 业务态 + 帧同步/CRC/空闲 3 特殊态。

    """

    MODE_NAMES = {

    "twm": "TWM 三进制波长键控(WSK, 零功耗0态)",

    "bbm": "BBM 二进制爆发模式(三色独立OOK)",

    "por": "POR PAM4-over-RGB 混合调制",

    "csmm": "CSMM 复合光谱多维复用(16态)",

    "hnt": "HNT 十六进制原生传输(16态+3特殊态)",

    }

    @staticmethod

    def mode_requires_hex16(mode):

    """CSMM/HNT 使用完整 16 态复合光谱;其余模式由三态流映射。"""

    return mode in ("csmm", "hnt")

    ---- 单符号 → 光强向量 ----

    @staticmethod

    def sym_to_vec(mode, s):

    if mode == "twm":

    return { -1: (P_HI, 0.0, 0.0),

    0: (0.0, 0.0, 0.0),

    +1: (0.0, 0.0, P_HI)}s

    if mode == "bbm":

    三色独立 OOK:-1→λ1亮;0→全灭;+1→λ3亮

    return { -1: (P_HI, 0.0, 0.0),

    0: (0.0, 0.0, 0.0),

    +1: (0.0, 0.0, P_HI)}s

    if mode == "por":

    PAM4-over-RGB:每路 4 电平(0~3 档),三态映射到区分度大的电平组合

    return { -1: (0.0, P_HI * 3 / 3, 0.0),

    0: (P_MID, P_MID, P_MID),

    +1: (P_HI, 0.0, P_HI)}s

    if mode in ("csmm", "hnt"):

    return SPECTRUM_16s \& 0xF

    raise ValueError(f"未知模式: {mode}")

    ---- 编码一帧:帧头 + 业务 + 帧尾 + 空闲 ----

    @classmethod

    def encode_frame(cls, mode, syms):

    head, tail = FRAME_MARKmode

    slots = head

    slots.extend(cls.sym_to_vec(mode, s) for s in syms)

    slots.append(tail)

    slots.extend((0.0, 0.0, 0.0) * GAP_SLOTS) # 帧间空闲(链路静默)

    return slots

    @classmethod

    def encode_all(cls, mode, frames):

    """多帧 → 完整时隙序列。"""

    slots = \[\]

    for syms in frames:

    slots.extend(cls.encode_frame(mode, syms))

    return slots

    def slots_to_wave(slots, n_sps=N_SPS):

    """时隙序列 → (3, N) 连续波形(汉宁窗整形,抑制带外能量)。"""

    n_slots = len(slots)

    n_total = n_slots * n_sps

    wave = np.zeros((3, n_total))

    win = np.hanning(n_sps)

    for k, vec in enumerate(slots):

    base = k * n_sps

    for c in range(3):

    wavec, base:base + n_sps += vecc * win

    return wave

    =====================================================================

    ③ 光信道层

    =====================================================================

    class OpticalChannel:

    """光信道:SNR 可配置 + 波长衰减 + 色散偏移 + 可选 PC-CDM 荧光转换。

    snr_db 定义(幅度域):σ_noise = P_HI / 10^(snr_db/20)。

    PC-CDM(荧光转换前置,出处:RGB-TOT 体系 PC-CDM 荧光转换增强接收):

    • 信号乘以增益 G_FLUOR(>1)→ 等效提升接收信噪比;

    • 引入去相干散斑噪声(乘性高斯,随信号幅度),

    高 SNR 下散斑成为底噪限制 → 模拟荧光粉颗粒去相干效应。

    """

    def init(self, snr_db=20.0, alpha=ALPHA, delay=DELAY,

    pc_cdm=False, seed=SEED):

    self.snr_db = snr_db

    self.sigma = P_HI / (10.0 ** (snr_db / 20.0))

    self.alpha = np.asarray(alpha, dtype=float)

    self.delay = delay

    self.pc_cdm = pc_cdm

    self.rng = np.random.default_rng(seed)

    @staticmethod

    def _shift(x, delta):

    """亚采样点线性插值平移(模拟色散时延)。"""

    n = len(x)

    idx = np.clip(np.arange(n) - delta, 0, n - 1)

    i0 = np.floor(idx).astype(int)

    i1 = np.minimum(i0 + 1, n - 1)

    w = idx - i0

    return (1.0 - w) * xi0 + w * xi1

    def transmit(self, wave):

    """发射波形 → 接收波形(衰减 + 色散 + 噪声 + 可选 PC-CDM)。"""

    out = wave * self.alpha:, None

    for c in range(3):

    outc = self._shift(outc, self.delayc)

    ---- PC-CDM 荧光转换(可选)----

    if self.pc_cdm:

    out = out * G_FLUOR

    speckle = (K_SPECKLE * np.abs(out)

    • SPECKLE_FLOOR * G_FLUOR) * self.rng.normal(size=out.shape)

    out += speckle

    ---- 高斯光噪声 ----

    out += self.rng.normal(0.0, self.sigma, out.shape)

    return out

    =====================================================================

    ④ 接收解调层:两种接收模型

    =====================================================================

    class WdmRx:

    """传统 WDM 光栅 + PD 阵列解调。

    原理:光栅分光后每路波长落在一个 PD 上,直接做时隙积分

    得到 (λ1, λ2, λ3) 三路能量,再按模式判决。

    """

    def init(self, thr_det=THR_DET, thr_sym=THR_SYM, thr_frame=THR_FRAME):

    self.thr_det = thr_det

    self.thr_sym = thr_sym

    self.thr_frame = thr_frame

    @staticmethod

    def slot_integrate(wave, n_sps=N_SPS, margin=4):

    """连续波形 → (n_slots, 3) 每时隙三路能量(核心区均值/窗均值)。"""

    n_slots = wave.shape1 // n_sps

    seg = wave:, :n_slots \* n_sps.reshape(3, n_slots, n_sps)

    core = seg:, :, margin:n_sps - margin

    win = np.hanning(n_sps)margin:n_sps - margin

    return (core.mean(axis=2) / win.mean()).T

    ---- 帧边界检测 ----

    head/tail 均要求至少一路存在"满功率峰"(>THR_FRAME):

    避免 CSMM 低功率双色业务态(如 0xB≈λ1+λ2)被误检为帧标记。

    def head(self, r):

    return (r0 > self.thr_det and r1 > self.thr_det

    and max(r0, r1) > self.thr_frame)

    def tail(self, r):

    return (r1 > self.thr_det and r2 > self.thr_det

    and max(r1, r2) > self.thr_frame)

    def idle(self, r):

    return (r0 > self.thr_det or r1 > self.thr_det

    or r2 > self.thr_det)

    ---- 业务符号判决 ----

    def parse(self, r, mode, templates=None):

    if mode == "twm":

    if r0 > self.thr_sym and r2 <= self.thr_sym:

    return -1

    if r2 > self.thr_sym and r0 <= self.thr_sym:

    return +1

    if r0 <= self.thr_sym and r2 <= self.thr_sym:

    return 0

    return None

    if mode == "bbm":

    三色独立 OOK:λ1 亮→-1,λ3 亮→+1,全灭→0(与发射映射一致)

    b1 = r0 > self.thr_sym

    b3 = r2 > self.thr_sym

    if b1 and not b3:

    return -1

    if b3 and not b1:

    return +1

    return 0

    if mode == "por":

    PAM4 量化:每路 4 电平最近邻 → 还原三态映射组合

    lv = np.clip(np.round(r * 3.0 / P_HI), 0, 3).astype(int)

    if lv0 == 0 and lv1 == 3 and lv2 == 0:

    return -1

    if lv0 == 3 and lv1 == 0 and lv2 == 3:

    return +1

    return 0

    if mode in ("csmm", "hnt"):

    16 态模板匹配(模板已乘衰减系数做标定)

    dist = np.sum((templates - rNone, :) ** 2, axis=1)

    return SPECTRUM_16_IDXint(np.argmin(dist))

    return None

    ---- 主解调状态机 ----

    def demodulate(self, R, mode, n_sym, templates=None):

    frames, idle_slots = \[\], \[\]

    i, n = 0, len(R)

    while i < n:

    if self.head(Ri):

    syms = \[\]

    j = i + 1

    while j < n and len(syms) < n_sym:

    if self.tail(Rj):

    break

    syms.append(self.parse(Rj, mode, templates))

    j += 1

    tail = None

    k = j

    while k < min(n, j + n_sym + 2):

    if self.tail(Rk):

    tail = k

    break

    k += 1

    if tail is not None:

    frames.append({"head_slot": i, "tail_slot": tail, "syms": syms})

    i = tail + 1

    continue

    i += 1

    else:

    if self.idle(Ri):

    idle_slots.append(i)

    i += 1

    return frames, idle_slots

    class CdbmCisRx:

    """CBDM-CIS 面阵成像解调(出处:RGB-TOT 体系 CBDM 基于 CIS 面阵解调)。

    流程:

    1. 时隙网格积分(同 WDM):还原每时隙三路光强 I(n_slots,3)。

    2. 拜耳成像:每时隙在 CIS 面阵上形成 block×block 像素块,

    像素按 2x2 RGGB 滤镜透过率矩阵 BAYER_T 对三波长混色采样。

    1. ISP 降噪:像素块【空间域】3×3 中值滤波(模拟 ISP 去除

    传感器脉冲噪声;不做跨时隙滤波,避免破坏帧同步标记)。

    1. 功率比解析:同色滤镜像素平均后,用最小二乘伪逆 pinv(T)

    从 4 类像素观测恢复三路波长功率。

    与 WDM 相比:单颗 CIS 面阵完成分光 + 空间降噪,省去光栅与 PD 阵列。

    """

    RGGB 拜耳透过率矩阵(行=R/G/G/B,列=λ1/λ2/λ3)

    BAYER_T = np.array([

    0.90, 0.15, 0.05, # R 像素(λ1 高透)

    0.05, 0.80, 0.05, # G 像素 1(λ2 高透)

    0.05, 0.80, 0.05, # G 像素 2

    0.05, 0.15, 0.90, # B 像素(λ3 高透)

    ])

    BAYER_T_PINV = np.linalg.pinv(BAYER_T) # 3x4 最小二乘恢复矩阵

    def init(self, thr_det=THR_DET, thr_sym=THR_SYM, thr_frame=THR_FRAME,

    sensor_noise=BAYER_NOISE, block=8):

    self.thr_det = thr_det

    self.thr_sym = thr_sym

    self.thr_frame = thr_frame

    self.sensor_noise = sensor_noise

    self.block = block # 面阵块边长(每时隙 block×block 像素)

    self.rng = np.random.default_rng(SEED + 2000)

    def slot_integrate(self, wave, n_sps=N_SPS, margin=4):

    """CIS 面阵成像解调:时隙积分 → 拜耳块成像 → 空间ISP → 功率比解析。

    关键点:ISP 中值滤波在【空间域】(同一时隙的 block×block 像素块内)

    进行,绝不跨时隙 ------ 避免把帧头/帧尾峰值与相邻业务符号混淆,

    保证帧同步标记不被破坏。

    """

    n_slots = wave.shape1 // n_sps

    b = self.block

    ---- 1) 时隙网格积分(同 WDM):(n_slots, 3) ----

    seg = wave:, :n_slots \* n_sps.reshape(3, n_slots, n_sps)

    core = seg:, :, margin:n_sps - margin

    win = np.hanning(n_sps)margin:n_sps - margin

    I = (core.mean(axis=2) / win.mean()).T

    ---- 2) 拜耳滤镜成像:每时隙 → block×block 像素块 ----

    像素 (r,c) 滤镜类型 = (r%2)*2 + (c%2) → 0=R,1=G,2=G,3=B

    rows = np.arange(b); cols = np.arange(b)

    tmap = (rows:, None % 2) * 2 + (cols % 2) # (b,b)

    obs = np.zeros((n_slots, b, b))

    for t in range(4): # 逐滤镜类型生成观测

    m = (tmap == t)

    obs:, m = (I @ self.BAYER_Tt):, None # (n_slots,)→(n_slots,1) 广播

    obs += self.rng.normal(0.0, self.sensor_noise, obs.shape)

    ---- 3) ISP 空间域降噪:同色通道 3×3 中值滤波 ----

    关键:中值窗口只在【同色滤镜网格】内进行(每种滤镜为

    步长 2 的 4×4 子网格),绝不跨滤镜类型 ------ 避免 R/G/B

    像素混色造成的光谱串扰,同时滤除传感器脉冲噪声。

    obs_f = np.zeros_like(obs)

    for t in range(4):

    r0, c0 = t // 2, t % 2 # 该类型子网格起点

    sub = obs:, r0::2, c0::2 # (n_slots,4,4) 同色子网格

    pad = np.pad(sub, ((0, 0), (1, 1), (1, 1)), mode="edge")

    sub_f = np.zeros_like(sub)

    for r in range(sub.shape1):

    for c in range(sub.shape2):

    sub_f:, r, c = np.median(pad:, r:r + 3, c:c + 3,

    axis=(1, 2))

    obs_f:, r0::2, c0::2 = sub_f

    ---- 4) 同类滤镜像素求平均 → 4 类像素观测 ----

    pix = np.zeros((n_slots, 4))

    for t in range(4):

    pix:, t = obs_f:, tmap == t.mean(axis=1)

    ---- 5) 功率比解析:最小二乘恢复三路功率 ----

    I_est = pix @ self.BAYER_T_PINV.T # (n_slots, 3)

    return np.clip(I_est, 0.0, None)

    帧边界 / 业务判决逻辑与 WDM 共用(同一套阈值与模板)

    head = WdmRx.head

    tail = WdmRx.tail

    idle = WdmRx.idle

    parse = WdmRx.parse

    demodulate = WdmRx.demodulate

    =====================================================================

    ⑤ 统计输出:SER / 帧同步检出 / SNR 扫描

    =====================================================================

    def run_mode(mode, snr_db, rx_kind="wdm", pc_cdm=False, cmos_block=None):

    """运行单个架构模式的完整链路仿真。

    返回: 统计字典 {ser, n_err, n_tot, frames_detected, frames_sent,

    idle_count, R(wave 能量矩阵), slots_tx}

    """

    固定字符串种子(避免 Python hash 随机化影响复现性)

    rng = np.random.default_rng(SEED + sum(ord(c) for c in mode))

    ---- 1) 业务符号:CSMM/HNT 用完整 16 态随机流;其余由 CMOS 三态流映射 ----

    if Transmitter.mode_requires_hex16(mode):

    frames_tx = list(rng.integers(0, 16, size=N_SYM)) for _ in range(N_FRAMES)

    else:

    base = (cmos_block or {}).get("ternary_frames")

    if base is None:

    base = list(rng.integers(-1, 2, size=N_SYM)) for _ in range(N_FRAMES)

    frames_tx = list(s) for s in base

    ---- 2) 发射 ----

    tx = Transmitter()

    slots_tx = tx.encode_all(mode, frames_tx)

    wave_tx = slots_to_wave(slots_tx)

    ---- 3) 信道 ----

    ch = OpticalChannel(snr_db=snr_db, pc_cdm=pc_cdm, seed=SEED + 300)

    wave_rx = ch.transmit(wave_tx)

    ---- 4) 接收 ----

    if rx_kind == "cis":

    rx = CdbmCisRx()

    else:

    rx = WdmRx()

    if pc_cdm:

    PC-CDM 荧光增益把整个光功率域(帧标记/业务符号/噪声)统一放大

    G_FLUOR 倍,因此接收端判决阈值必须按同一增益标定,

    否则模板匹配与帧边界检测会整体失真。

    rx.thr_det *= G_FLUOR

    rx.thr_sym *= G_FLUOR

    rx.thr_frame *= G_FLUOR

    R = rx.slot_integrate(wave_rx)

    templates = np.array(SPECTRUM_16\[s for s in SPECTRUM_16_IDX]) * np.array(ALPHA)

    if pc_cdm:

    templates *= G_FLUOR # 模板同样按增益标定

    frames_rx, idle_slots = rx.demodulate(R, mode, N_SYM, templates)

    ---- 5) SER 统计 ----

    n_tot = n_err = 0

    for idx in range(N_FRAMES):

    rx_syms = (frames_rxidx"syms" if idx < len(frames_rx)

    else "-" * N_SYM)

    rx_syms = (rx_syms + "-" * N_SYM):N_SYM

    for a, b in zip(frames_txidx, rx_syms):

    n_tot += 1

    if a != b:

    n_err += 1

    return {

    "ser": n_err / max(n_tot, 1),

    "n_err": n_err,

    "n_tot": n_tot,

    "frames_sent": N_FRAMES,

    "frames_detected": len(frames_rx),

    "idle_slots": idle_slots,

    "R": R,

    "slots_tx": slots_tx,

    "frames_rx": frames_rx,

    }

    def scan_snr(mode, rx_kinds=("wdm", "cis"), pc_cdm=False,

    snr_list=None, cmos_block=None):

    """扫描 SNR 生成各接收模型的 SER-SNR 曲线数据。

    返回: {"snr_list": ..., "ser": {"wdm": ..., "cis": ...}}

    """

    if snr_list is None:

    snr_list = 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 22.0, 25.0, 30.0

    data = {"snr_list": snr_list, "ser": {k: \[\] for k in rx_kinds}}

    for s in snr_list:

    for k in rx_kinds:

    stat = run_mode(mode, s, rx_kind=k, pc_cdm=pc_cdm, cmos_block=cmos_block)

    data"ser"k.append(stat"ser")

    return data

    =====================================================================

    绘图:三张图(matplotlib 可用时输出 svg+png 双格式;缺失则跳过)

    =====================================================================

    def _save_fig(fig, base_name, titles, out_dir=OUT_DIR):

    """把当前 fig 同时保存为 .svg 与 .png。"""

    for ext in ("svg", "png"):

    fname = os.path.join(out_dir, f"{base_name}.{ext}")

    fig.savefig(fname, dpi=150)

    print(f" {os.path.abspath(fname)}")

    def plot_cmos_timing(cmos):

    """CMOS 引脚时序波形:pin3/pin4/pin5 + 采样窗口 + 毛刺标注。"""

    if not HAVE_MPL:

    _plot_cmos_timing_svg(cmos) # 纯标准库 SVG 降级

    return

    pin3, pin4, pin5 = cmos"pin3", cmos"pin4", cmos"pin5"

    n = len(pin3)

    t = np.arange(n)

    fig, axes = plt.subplots(3, 1, figsize=(16, 9), sharex=True)

    sigs = [(pin3, "#ff8c00", "pin3 --- M2 控制使能(采样时隙供电,其余断电)"),

    (pin4, "#1f77b4", "pin4 --- M1 触发控制(叠加噪声/毛刺)"),

    (pin5, "#2ca02c", "pin5 --- M2 最终输出(竞争冒险毛刺可见)")]

    for i, s in enumerate(cmos"samples"):

    a, b = s"start" + CMOS_SAMP_START, s"start" + CMOS_SAMP_END

    for _, ax in enumerate(axes):

    ax.axvspan(a, b, alpha=0.18, color="gold", label="采样窗口" if i == 0 else None)

    if i > 0:

    for ax in axes:

    ax.axvline(s"start", color="k", ls="--", lw=0.5, alpha=0.45)

    axes0.text((a + b) / 2, 9.6, f"C{i+1}", ha="center", fontsize=10, color="red")

    for sig, color, title in sigs:

    ax = axessigs.index((sig, color, title))

    ax.plot(t, sig, lw=0.8, color=color)

    ax.set_title(title, fontsize=11)

    ax.set_ylabel("电压 (V)")

    ax.axhline(CMOS_V_THR, color="gray", ls=":", lw=0.7, label=f"V_THR={CMOS_V_THR}V")

    ax.grid(alpha=0.3)

    竞争冒险毛刺标注(C4 段)

    c4 = cmos"samples"3

    gx = c4"start" + CMOS_SAMP_START + CMOS_RACE_DELTA

    axes2.annotate("竞争冒险毛刺\n(脉宽<PULSE_MIN 被滤除)",

    xy=(gx, 10.2), xytext=(gx + 30, 7.0),

    fontsize=9, color="darkred",

    arrowprops=dict(arrowstyle="->", color="darkred"))

    axes-1.set_xlabel("采样点(5 组用例拼接)")

    axes0.legend(loc="upper right", fontsize=8, ncol=2)

    fig.suptitle("CMOS 三态拓扑单元时序波形 --- C1~C5(含竞争冒险/拓扑失效)",

    fontsize=13, y=1.0)

    fig.tight_layout()

    _save_fig(fig, "cmos_timing")

    plt.close(fig)

    def plot_optical_spectrum(mode, stat, snr_db):

    """发射 / 接收对比光谱(三路波长平均功率柱状对比)。"""

    if not HAVE_MPL:

    _plot_optical_spectrum_svg(mode, stat, snr_db) # 纯标准库 SVG 降级

    return

    发射端平均光谱:业务时隙(不含帧头/帧尾/空闲)三路平均

    tx_vecs = v for v in stat\["slots_tx"

    if not (v0 >= P_FRAME or v1 >= P_FRAME)] # 过滤帧标记

    tx_avg = np.mean(tx_vecs, axis=0)

    接收端平均光谱:全部时隙三路平均(含帧标记,对比整体能量水平)

    rx_avg = np.mean(stat"R", axis=0)

    waves = "λ1", "λ2", "λ3"

    x = np.arange(3)

    width = 0.35

    fig, ax = plt.subplots(figsize=(9, 5))

    ax.bar(x - width / 2, tx_avg, width, label="发射光谱(业务时隙均值)", color="#1f77b4")

    ax.bar(x + width / 2, rx_avg, width, label="接收光谱(全部时隙均值)", color="#ff7f0e")

    ax.set_xticks(x)

    ax.set_xticklabels(waves)

    ax.set_ylabel("归一化光功率")

    ax.set_title(f"发射/接收对比光谱 --- {Transmitter.MODE_NAMESmode} "

    f"(SNR={snr_db:.1f} dB)")

    ax.legend()

    ax.grid(alpha=0.3)

    fig.tight_layout()

    _save_fig(fig, "optical_spectrum")

    plt.close(fig)

    def plot_ser_snr(mode, data):

    """SER-SNR 误符号率曲线(对数纵轴,WDM 与 CIS 双模型对比)。"""

    if not HAVE_MPL:

    _plot_ser_snr_svg(mode, data) # 纯标准库 SVG 降级

    return

    snr_list = data"snr_list"

    fig, ax = plt.subplots(figsize=(9, 5.5))

    colors = {"wdm": "#d62728", "cis": "#2ca02c"}

    labels = {"wdm": "WDM 光栅+PD 阵列", "cis": "CBDM-CIS 面阵解调"}

    for k in data"ser":

    ser = data"ser"k

    ax.semilogy(snr_list, max(s, 1e-6) for s in ser, "o-",

    color=colorsk, label=labelsk)

    ax.set_xlabel("SNR (dB)")

    ax.set_ylabel("SER 误符号率")

    ax.set_title(f"SER-SNR 曲线 --- {Transmitter.MODE_NAMESmode}")

    ax.grid(alpha=0.3, which="both")

    ax.legend()

    fig.tight_layout()

    _save_fig(fig, "ser_snr_curve")

    plt.close(fig)

    =====================================================================

    纯标准库 SVG 降级绘图(未安装 matplotlib 时保证 .svg 仍输出)

    =====================================================================

    def _svg_open(title, w=1400, h=820, sub=None):

    """SVG 画布头部:白底 + 主标题 + 可选副标题。"""

    els = [

    f'<svg xmlns="http://www.w3.org/2000/svg" width="{w}" height="{h}" '

    f'viewBox="0 0 {w} {h}">',

    f'<rect x="0" y="0" width="{w}" height="{h}" fill="white"/>',

    f'<text x="{w/2:.0f}" y="30" font-size="20" text-anchor="middle" '

    f'font-weight="bold" font-family="sans-serif">{title}</text>',

    ]

    if sub:

    els.append(f'<text x="{w/2:.0f}" y="54" font-size="12" text-anchor="middle" '

    f'font-family="sans-serif" fill="#555">{sub}</text>')

    return els

    def _svg_close(els):

    els.append('</svg>')

    return els

    def _svg_save(els, base_name, out_dir=OUT_DIR):

    """写入 <桌面>/<base_name>.svg。"""

    os.makedirs(out_dir, exist_ok=True)

    fname = os.path.join(out_dir, base_name + ".svg")

    with open(fname, "w", encoding="utf-8") as fp:

    fp.write("\n".join(els))

    print(f" {os.path.abspath(fname)}")

    def _plot_cmos_timing_svg(cmos):

    """CMOS 引脚时序波形(纯 SVG 版):pin3/pin4/pin5 + 采样窗口。"""

    W, H = 1500, 900

    pad_l, pad_r, pad_t, pad_b = 90, 30, 90, 40

    pw = W - pad_l - pad_r

    ph = (H - pad_t - pad_b) / 3.0

    v_lo, v_hi = -2.0, 11.0

    n = len(cmos"pin3")

    sigs = cmos\["pin3", cmos"pin4", cmos"pin5"]

    def px(i):

    return pad_l + i / (n - 1) * pw

    def py(ch, v):

    top = pad_t + ch * ph

    return top + (v_hi - v) / (v_hi - v_lo) * ph

    els = _svg_open(

    "CMOS 三态拓扑单元时序波形 --- C1~C5(含竞争冒险/拓扑失效)", W, H,

    f"有效电平阈值 {CMOS_V_THR}V,最小脉宽 {CMOS_PULSE_MIN} 点,"

    f"采样窗口 {CMOS_SAMP_START},{CMOS_SAMP_END}")

    labels = "pin3 (M2 控制)", "pin4 (M1 触发)", "pin5 (M2 输出)"

    colors = "#ff8c00", "#1f77b4", "#2ca02c"

    for ch in range(3):

    top = pad_t + ch * ph

    els.append(f'<rect x="{pad_l}" y="{top:.1f}" width="{pw}" height="{ph:.1f}" '

    f'fill="#fafafa" stroke="#cccccc"/>')

    横向电压网格

    for gv in (-2, 0, 2, 4, 6, 8, 10):

    gy = py(ch, gv)

    els.append(f'<line x1="{pad_l}" y1="{gy:.1f}" x2="{pad_l+pw}" y2="{gy:.1f}" '

    f'stroke="#eeeeee" stroke-width="0.5"/>')

    els.append(f'<text x="{pad_l-8}" y="{gy+4:.0f}" font-size="10" '

    f'text-anchor="end" font-family="sans-serif">{gv}V</text>')

    V_THR 阈值虚线

    ty = py(ch, CMOS_V_THR)

    els.append(f'<line x1="{pad_l}" y1="{ty:.1f}" x2="{pad_l+pw}" y2="{ty:.1f}" '

    f'stroke="#888888" stroke-width="0.7" stroke-dasharray="5,4"/>')

    els.append(f'<text x="{pad_l+pw-6}" y="{ty-4:.0f}" font-size="10" '

    f'text-anchor="end" font-family="sans-serif" fill="#555">'

    f'V_THR={CMOS_V_THR}V</text>')

    采样窗口阴影 + 用例分隔 + 结论标注

    for i, s in enumerate(cmos"samples"):

    a = px(s"start" + CMOS_SAMP_START)

    b = px(s"start" + CMOS_SAMP_END)

    els.append(f'<rect x="{a:.1f}" y="{top:.1f}" width="{(b-a):.1f}" '

    f'height="{ph:.1f}" fill="#ffd700" fill-opacity="0.20"/>')

    if i > 0:

    xv = px(s"start")

    els.append(f'<line x1="{xv:.1f}" y1="{top:.1f}" x2="{xv:.1f}" '

    f'y2="{top+ph:.1f}" stroke="#333" stroke-width="0.5" '

    f'stroke-dasharray="4,3"/>')

    mid = (a + b) / 2

    mark = "PASS" if s"ok" else "FAIL"

    els.append(f'<text x="{mid:.1f}" y="{top+16:.0f}" font-size="12" '

    f'text-anchor="middle" font-weight="bold" '

    f'font-family="sans-serif" fill="red">C{s"idx"} {mark}</text>')

    竞争冒险毛刺标注(C4)

    if ch == 2:

    c4 = cmos"samples"3

    gx = px(c4"start" + CMOS_SAMP_START + CMOS_RACE_DELTA)

    els.append(f'<text x="{gx:.1f}" y="{top+ph-16:.0f}" font-size="11" '

    f'text-anchor="middle" font-family="sans-serif" '

    f'fill="#8b0000">竞争冒险毛刺(脉宽<PULSE_MIN 被滤除)</text>')

    波形 polyline

    step = max(1, n // 2200)

    pts = " ".join(f"{px(i):.1f},{py(ch, sigschi):.1f}"

    for i in range(0, n, step))

    els.append(f'<polyline points="{pts}" fill="none" '

    f'stroke="{colorsch}" stroke-width="1"/>')

    els.append(f'<text x="14" y="{(top+ph/2+5):.0f}" font-size="13" '

    f'font-weight="bold" font-family="sans-serif">{labelsch}</text>')

    els = _svg_close(els)

    _svg_save(els, "cmos_timing")

    def _plot_optical_spectrum_svg(mode, stat, snr_db):

    """发射/接收对比光谱(纯 SVG 版柱状图)。"""

    W, H = 820, 540

    pad_l, pad_r, pad_t, pad_b = 80, 30, 90, 60

    pw, ph = W - pad_l - pad_r, H - pad_t - pad_b

    tx_vecs = v for v in stat\["slots_tx"

    if not (v0 >= P_FRAME or v1 >= P_FRAME)]

    tx_avg = np.mean(tx_vecs, axis=0)

    rx_avg = np.mean(stat"R", axis=0)

    vmax = max(float(tx_avg.max()), float(rx_avg.max()), 0.5)

    def px(x):

    return pad_l + (x + 0.5) / 3.0 * pw

    def py(v):

    return pad_t + ph - (v / vmax) * ph

    els = _svg_open("发射/接收对比光谱", W, H,

    f"{Transmitter.MODE_NAMESmode} (SNR={snr_db:.1f} dB)")

    横向网格

    for k in range(5):

    gv = vmax * k / 4.0

    gy = py(gv)

    els.append(f'<line x1="{pad_l}" y1="{gy:.1f}" x2="{pad_l+pw}" y2="{gy:.1f}" '

    f'stroke="#eeeeee" stroke-width="0.5"/>')

    els.append(f'<text x="{pad_l-6}" y="{gy+4:.0f}" font-size="10" '

    f'text-anchor="end" font-family="sans-serif">{gv:.2f}</text>')

    bw = pw / 3.0 * 0.24

    for i in range(3):

    cx = px(i)

    for kind, col in (("tx", "#1f77b4"), ("rx", "#ff7f0e")):

    v = tx_avgi if kind == "tx" else rx_avgi

    x0 = cx - bw - 2 if kind == "tx" else cx + 2

    y_top = py(v)

    els.append(f'<rect x="{x0:.1f}" y="{y_top:.1f}" width="{bw:.1f}" '

    f'height="{max(pad_t+ph-y_top, 0):.1f}" fill="{col}"/>')

    波长标签

    for i, wv in enumerate("λ1", "λ2", "λ3"):

    els.append(f'<text x="{px(i):.1f}" y="{pad_t+ph+22:.0f}" font-size="13" '

    f'text-anchor="middle" font-family="sans-serif">{wv}</text>')

    图例

    els.append(f'<rect x="{pad_l}" y="66" width="14" height="12" fill="#1f77b4"/>')

    els.append(f'<text x="{pad_l+20}" y="76" font-size="12" '

    f'font-family="sans-serif">发射光谱(业务时隙均值)</text>')

    els.append(f'<rect x="{pad_l+210}" y="66" width="14" height="12" fill="#ff7f0e"/>')

    els.append(f'<text x="{pad_l+230}" y="76" font-size="12" '

    f'font-family="sans-serif">接收光谱(全部时隙均值)</text>')

    els = _svg_close(els)

    _svg_save(els, "optical_spectrum")

    def _plot_ser_snr_svg(mode, data):

    """SER-SNR 曲线(纯 SVG 版,纵轴 log10)。"""

    W, H = 900, 580

    pad_l, pad_r, pad_t, pad_b = 80, 40, 90, 60

    pw, ph = W - pad_l - pad_r, H - pad_t - pad_b

    snr_list = data"snr_list"

    ymin, ymax = 1e-6, 1.0

    def px(s):

    return pad_l + (s - snr_list0) / (snr_list-1 - snr_list0) * pw

    def py(ser):

    l = np.log10(max(ser, ymin))

    return pad_t + ph - (l - np.log10(ymin)) / (np.log10(ymax) - np.log10(ymin)) * ph

    els = _svg_open("SER-SNR 误符号率曲线", W, H,

    f"{Transmitter.MODE_NAMESmode} (纵轴对数刻度)")

    log 网格

    for k in range(-6, 1):

    yv = py(10.0 ** k)

    els.append(f'<line x1="{pad_l}" y1="{yv:.1f}" x2="{pad_l+pw}" y2="{yv:.1f}" '

    f'stroke="#eeeeee" stroke-width="0.5"/>')

    els.append(f'<text x="{pad_l-6}" y="{yv+4:.0f}" font-size="10" '

    f'text-anchor="end" font-family="sans-serif">1e{k}</text>')

    x 轴刻度

    for s in snr_list:

    xv = px(s)

    els.append(f'<text x="{xv:.1f}" y="{pad_t+ph+18:.0f}" font-size="10" '

    f'text-anchor="middle" font-family="sans-serif">{s:.0f}</text>')

    els.append(f'<text x="{pad_l+pw/2:.0f}" y="{pad_t+ph+42:.0f}" font-size="13" '

    f'text-anchor="middle" font-family="sans-serif">SNR (dB)</text>')

    曲线

    colors = {"wdm": "#d62728", "cis": "#2ca02c"}

    names = {"wdm": "WDM 光栅+PD 阵列", "cis": "CBDM-CIS 面阵解调"}

    for k, col in colors.items():

    if k not in data"ser":

    continue

    pts = " ".join(f"{px(s):.1f},{py(v):.1f}"

    for s, v in zip(snr_list, data"ser"k))

    els.append(f'<polyline points="{pts}" fill="none" '

    f'stroke="{col}" stroke-width="2"/>')

    for s, v in zip(snr_list, data"ser"k):

    els.append(f'<circle cx="{px(s):.1f}" cy="{py(v):.1f}" r="3.5" fill="{col}"/>')

    图例

    lx = pad_l + 10

    for k, col in colors.items():

    els.append(f'<line x1="{lx}" y1="76" x2="{lx+30}" y2="76" stroke="{col}" stroke-width="2.5"/>')

    els.append(f'<text x="{lx+36}" y="80" font-size="12" '

    f'font-family="sans-serif">{namesk}</text>')

    lx += 260

    els = _svg_close(els)

    _svg_save(els, "ser_snr_curve")

    =====================================================================

    报告打印

    =====================================================================

    def print_report(mode, rx_kind, snr_db, pc_cdm, cmos, stat):

    print("\n" + "=" * 76)

    print(" 联合仿真报告(模式选择 / 统计输出)")

    print("=" * 76)

    print(f" 当前工作模式 : {mode} --- {Transmitter.MODE_NAMESmode}")

    print(f" 接收模型 : {'CBDM-CIS 面阵成像解调' if rx_kind == 'cis' else '传统 WDM 光栅+PD 阵列'}"

    • (" + PC-CDM 荧光转换前置板" if pc_cdm else ""))

    print(f" CMOS 单元通过率: {cmos'pass_rate':.1f}%")

    print(f" SNR 参数 : {snr_db:.1f} dB (σ_noise={P_HI / (10.0 ** (snr_db / 20.0)):.4f})")

    print("-" * 76)

    print(f" SER 误符号率 : {stat'n_err'} / {stat'n_tot'} = {stat'ser':.4f}")

    print(f" 帧同步检出统计 : 检出 {stat'frames_detected'} / 发送 {stat'frames_sent'} 帧"

    f"(未同步 {max(0, stat'frames_sent' - stat'frames_detected')} 帧)")

    print(f" 链路空闲时隙 : {len(stat'idle_slots')} 个(窗口外静默不解析为 0)")

    if mode in ("csmm", "hnt"):

    print(f" HNT 模板匹配 : 16 态复合光谱最近邻判决")

    print("=" * 76)

    =====================================================================

    主入口(模式选择开关 + 交互菜单)

    =====================================================================

    def parse_args(argv=None):

    """命令行参数解析。未指定 --mode 且为交互终端时弹出菜单。"""

    p = argparse.ArgumentParser(

    description="RGB-TOT 全架构联合仿真(三态CMOS + 5模式发射 + 双接收 + SER统计)")

    p.add_argument("--mode", default=None, choices=list(Transmitter.MODE_NAMES),

    help="发射架构模式: twm/bbm/por/csmm/hnt(默认 csmm)")

    p.add_argument("--rx", default=DEFAULT_RX, choices="wdm", "cis",

    help="接收模型: wdm(WDM光栅)/ cis(CBDM-CIS面阵)")

    p.add_argument("--snr", type=float, default=20.0,

    help="信道 SNR (dB),默认 20")

    p.add_argument("--pc-cdm", action="store_true",

    help="开启 PC-CDM 荧光转换增强接收")

    p.add_argument("--scan", action="store_true",

    help="额外执行 SNR 扫描并绘制 SER-SNR 曲线")

    args = p.parse_args(argv)

    ---- 交互模式选择(仅交互终端且未指定 --mode 时)----

    if args.mode is None and sys.stdin.isatty():

    print("\n模式选择 请选择发射架构模式:")

    for i, (k, v) in enumerate(Transmitter.MODE_NAMES.items(), 1):

    print(f" {i}. {k:<5} {v}")

    try:

    sel = input(" 输入编号 (1-5,回车默认 csmm): ").strip()

    args.mode = list(Transmitter.MODE_NAMES)int(sel) - 1 if sel else DEFAULT_MODE

    except (EOFError, ValueError, IndexError):

    args.mode = DEFAULT_MODE

    if args.mode is None:

    args.mode = DEFAULT_MODE

    return args

    def main(argv=None):

    args = parse_args(argv)

    print("=" * 76)

    print(" RGB-TOT 全架构联合仿真 --- 三态CMOS拓扑单元 + 光通信链路")

    print(" 本文为民间原创技术构想,仅逻辑推演、学术交流。")

    print("=" * 76)

    print(f" 输出目录(Windows 桌面自适应): {OUT_DIR}")

    print(f" 帧结构: 帧头 + 业务{N_SYM}时隙 + 帧尾 + 空闲{GAP_SLOTS}时隙 × {N_FRAMES} 帧")

    ---- ① CMOS 单元测试 ----

    cmos = run_cmos_block()

    ---- ② 选定模式全链路仿真 ----

    stat = run_mode(args.mode, args.snr, rx_kind=args.rx,

    pc_cdm=args.pc_cdm, cmos_block=cmos)

    ---- ③ 报告 ----

    print_report(args.mode, args.rx, args.snr, args.pc_cdm, cmos, stat)

    ---- ④ 三张图 ----

    plot_cmos_timing(cmos)

    plot_optical_spectrum(args.mode, stat, args.snr)

    ---- ⑤ SNR 扫描(可选)----

    if args.scan:

    print("\nSNR 扫描 正在生成 SER-SNR 曲线...")

    scan = scan_snr(args.mode, rx_kinds=("wdm", "cis"),

    pc_cdm=args.pc_cdm, cmos_block=cmos)

    plot_ser_snr(args.mode, scan)

    print(f" 扫描完成:SNR 范围 {scan'snr_list'0:.0f}~{scan'snr_list'-1:.0f} dB")

    print("\n" + "=" * 76)

    print(" 仿真完成。")

    print("=" * 76)

    if name == "main":

    main()


二、仿真整体链路
信号源:直接复用前文已验证的三态 CMOS 单元(CmosTernaryCell),包含 pin3 双向引脚、竞争冒险毛刺、拓扑失效故障工况,单元测试通过率 100%。
链路:三态CMOS输出 → RGB‑TOT光发射机 → 光信道 → 接收机解调 → SER与帧同步统计
光发射层 Transmitter 5 种工作模式
TWM 三进制波长键控:‑1 映射 λ1,0 为无光零功耗,+1 映射 λ3;双波长重合脉冲生成帧头、帧尾标记。
BBM 二进制爆发模式:三路波长独立 OOK 调制。
POR PAM4‑over‑RGB 混合调制。
CSMM 复合光谱多维复用:单色多功率档位、双色配比组合构造多态符号。
HNT 十六态传输:16 个业务数据符号,附带帧同步、CRC、链路空闲 3 个控制符号。
光信道层 OpticalChannel
可配置 SNR 信噪比;内置高斯光噪声、波长衰减、色散时序偏移。
可选开启PC‑CDM 荧光转换模型,包含光增益、散斑去相干噪声;内部做增益同步标定,避免功率放大后判决阈值偏移失真。
接收解调层两套通路
WdmRx 光栅 + 光电 PD 接收:传统光通信解调,抗噪声性能优秀。
CdbmCisRx CIS 拜耳面阵成像接收:8×8 RGGB 成像块。
关键修复:ISP 降噪限定时隙内部同色通道空间域滤波,禁止跨时隙处理,解决帧同步脉冲被抹平、RGGB 像素混色串扰、帧头误触发问题。
现象:低信噪比条件下 CIS 面阵会引入成像额外噪声;高 SNR 下 WDM 与 CIS 均可实现零误码。
统计输出层
输出 SER 误符号率、帧同步检出成功率;支持 SNR 自动扫描,输出两套接收机对比 SER‑SNR 曲线。
三、仿真调试关键结论
CIS 接收机不能跨时隙做降噪处理,否则会直接破坏帧标记脉冲,造成帧同步失效。
PC‑CDM 荧光增益开启后,判决模板、阈值必须同步跟随增益缩放,否则整体判决失效。
POR 模式受波长衰减影响容易出现量化偏移,需要采用波长能量阈值判决,与发射端映射规则严格对齐。
完成全组合遍历验证:csmm/hnt/twm/bbm/por × wdm/cis × PC‑CDM开关,合适信噪比条件下,SER=0/40,帧同步检出 5/5。
四、开源仓库
完整仿真工程开源地址:【粘贴你的 Gitee 链接】
仓库包含主程序、README 文档、仿真 SVG 样例,读者可下载修改参数复现全部仿真现象。
结尾
本文仅为行为级逻辑推演仿真,不等同硬件直接流片;实际落地还需要 SPICE 器件级仿真、光学器件选型验证。

相关推荐
这个DBA有点耶2 小时前
从库延迟的“二次放大”效应:一次大事务,拖垮整个读写分离
数据库·mysql·架构
张宇Joaquin3 小时前
高性能模板库Eigen架构分析及性能优化实践
性能优化·架构
AI产品测评官4 小时前
AI 招聘系统的三代技术演进:从 DOM 注入到视觉语义读取的架构拆解
人工智能·架构·求职招聘
语核科技4 小时前
知识管理系统的技术选型:传统知识库与AI原生知识库的架构差异
架构·ai-native
梦奇不是胖猫5 小时前
从小餐厅 到 理解 互联网架构
架构
m0_640602448 小时前
2026 年餐饮收银系统前后端技术实现——核心架构与原理详解
后端·微服务·云原生·架构
江畔柳前堤8 小时前
AgentScope 设计与原理全解:从消息原语到分布式智能体工程底座
大数据·人工智能·分布式·目标检测·机器学习·语言模型·架构
两万五千个小时8 小时前
DeepSeek Harness 上下文压缩:长对话管理
人工智能·程序员·架构
一拳不是超人9 小时前
一个 AI 改出的 bug,另一个 AI 五天就打穿了 Snowflake:Copilot Autofix 事件给 coding agent 的警醒
架构·github