声明:本文为民间原创技术构想,仅作逻辑推演与学术交流,不涉及任何国家秘密及未公开实体项目,保留全部署名权与著作权。
🔗前置理论:《电视像素给光,互联上了一课,波长即比特,颜色即逻辑》 🔗底层硬件单元:三进制 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.svgCMOS 三态单元引脚时序波形 -
optical_spectrum.svg发射光谱 / 信道损伤后接收光谱对比 -
ser_snr_curve.svgSER‑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 重定向与中文用户名。
候选顺序:
-
~/Desktop
-
~/OneDrive/Desktop
-
~/OneDrive/桌面
-
~/桌面
全部不存在时回退到用户主目录(保证可写)。
"""
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 面阵解调)。
流程:
-
时隙网格积分(同 WDM):还原每时隙三路光强 I(n_slots,3)。
-
拜耳成像:每时隙在 CIS 面阵上形成 block×block 像素块,
像素按 2x2 RGGB 滤镜透过率矩阵 BAYER_T 对三波长混色采样。
- ISP 降噪:像素块【空间域】3×3 中值滤波(模拟 ISP 去除
传感器脉冲噪声;不做跨时隙滤波,避免破坏帧同步标记)。
- 功率比解析:同色滤镜像素平均后,用最小二乘伪逆 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 器件级仿真、光学器件选型验证。
-
自本声明添加之日起,本文采用 CC BY-NC-SA 4.0 国际知识共享协议 许可。
-
本文创作已完成TSA时间授时固化,用于固定理论首创时间。