QuantiaMagica - ADC行为级仿真器

## 核心特性

[1]

#### 事件驱动架构

像Minecraft插件一样，监听ADC转换的每个阶段，轻松实现非理想效应建模

[2]

#### 极简API

3行代码完成仿真，用户代码量极少，支持超快速调用

[3]

#### 专业分析

内置ENOB、SNR、SFDR、THD、INL、DNL计算和IEEE JSSC风格绘图

[4]

#### 高度可扩展

支持SAR ADC、Pipeline ADC，易于添加新架构和自定义信号

## Python 新手入门

写给完全没接触过Python的你

别担心！跟着下面的步骤，10分钟内你就能运行第一个ADC仿真。

### 第一步：安装 Python

1. 下载Python
   访问 python.org，下载最新版本（推荐3.10以上）
2. 安装时勾选 "Add Python to PATH"
   这一步非常重要！勾选后才能在命令行使用Python
3. 验证安装
   打开命令行（Windows: Win+R 输入 cmd），输入：

       python --version

   看到版本号就说明安装成功了

### 第二步：安装 QuantiaMagica

    # 在命令行中执行以下命令

    # 方法1：进入项目目录安装（推荐）
    cd QuantiaMagica
    pip install -e .

    # 方法2：只安装依赖
    pip install numpy matplotlib

### 第三步：创建你的第一个脚本

用任意文本编辑器（记事本、VS Code、PyCharm都可以）创建文件 `my_first_adc.py`：

    # my_first_adc.py - 我的第一个ADC仿真

    from quantiamagica import SARADC

    # 创建一个10位SAR ADC
    adc = SARADC(bits=10, vref=1.0)

    # 运行仿真
    adc.sim()

    # 显示结果
    print(f"ENOB: {adc.enob():.2f} bits")

    # 画图
    adc.plot()

### 第四步：运行脚本

    # 在命令行中
    python my_first_adc.py

恭喜！

你已经完成了第一个ADC仿真！继续阅读下面的内容学习更多用法。

### Python基础语法速查（本API所需）

以下是使用QuantiaMagica所需的所有Python语法，10分钟即可掌握：

#### 1. 变量和数据类型

    # 变量赋值：直接写名字 = 值
    bits = 12           # 整数 int
    vref = 1.0          # 小数 float
    name = "SAR-ADC"    # 字符串 str
    enabled = True      # 布尔值 True/False

    # 科学计数法（ADC仿真常用）
    fs = 1e6            # 1×10⁶ = 1000000 (1MHz)
    noise = 0.5e-3      # 0.5×10⁻³ = 0.0005 (0.5mV)
    fin = 10e3          # 10×10³ = 10000 (10kHz)

    # 运算符
    a = 10 + 3     # 加法 = 13
    b = 10 - 3     # 减法 = 7
    c = 10 * 3     # 乘法 = 30
    d = 10 / 3     # 除法 = 3.333...
    e = 10 // 3    # 整除 = 3
    f = 10 % 3     # 取余 = 1
    g = 2 ** 10    # 幂运算 = 1024

#### 2. 列表和字典

    # 列表 list：用方括号，可索引
    coeffs = [0.5, 0.3, 0.2]    # 创建列表
    first = coeffs[0]           # 索引从0开始，= 0.5
    coeffs.append(0.1)          # 追加元素
    length = len(coeffs)        # 长度 = 4

    # 字典 dict：键值对，用花括号
    params = {'c1': 0.5, 'c2': 0.3, 'amplitude': 0.4}
    c1 = params['c1']           # 取值 = 0.5
    params['c3'] = 0.2          # 添加新键值

#### 3. 导入模块

    # 从模块导入类/函数
    from quantiamagica import SARADC              # 导入一个
    from quantiamagica import SARADC, Signal     # 导入多个
    from quantiamagica import *                   # 导入所有（不推荐）

    # 导入整个模块（需要前缀访问）
    import numpy as np                            # np是别名
    noise = np.random.normal(0, 0.001)           # 使用np.xxx访问

    # 常用导入（本API需要）
    import numpy as np
    from quantiamagica import SARADC, PipelineADC, SigmaDeltaADC
    from quantiamagica import SamplingEvent, ComparatorEvent, QuantizerEvent
    from quantiamagica.optim import GeneticOptimizer, Gene

#### 4. 创建对象和调用方法

    # 创建对象：类名(参数)
    adc = SARADC(bits=12, vref=1.0)   # 命名参数
    adc = SARADC(12, 1.0)              # 位置参数
    adc = SARADC(12)                   # 只传必要参数

    # 调用方法：对象.方法名()
    adc.sim()                         # 无参数
    adc.sim(fin=10e3)                 # 有参数
    adc.sim(n_samples=4096, fs=1e6)  # 多个参数

    # 获取返回值
    result = adc.sim()                # 保存返回对象
    enob = adc.enob()                 # 保存返回数字

    # 链式调用
    adc.sim().report()                # 仿真完直接报告

    # 访问属性
    bits = adc.bits                   # 读取属性（无括号）

#### 5. 函数定义

    # 基本函数
    def add(a, b):
        return a + b

    result = add(3, 5)  # 调用函数，result = 8

    # 带默认参数
    def greet(name="World"):
        print(f"Hello, {name}!")

    greet()           # Hello, World!
    greet("ADC")      # Hello, ADC!

    # 适应度函数示例（遗传算法用）
    def fitness(params):
        # params是字典，如 {'c1': 0.5, 'c2': 0.3}
        c1 = params['c1']
        c2 = params['c2']
        # ... 计算ENOB ...
        return enob  # 返回适应度值

#### 6. 装饰器（事件系统核心）

    # 装饰器：@xxx 放在函数定义上面
    # 这是QuantiaMagica事件系统的核心！

    from quantiamagica import SARADC, SamplingEvent

    adc = SARADC(12)

    @adc.on(SamplingEvent)           # ← 装饰器：监听采样事件
    def add_noise(event):           # ← 事件处理函数，参数是event
        event.voltage += 0.001       # ← 修改event的属性

    # 装饰器的作用：当ADC采样时，自动调用add_noise函数
    # 你不需要手动调用add_noise()，只需要运行adc.sim()

    adc.sim()  # add_noise会在每次采样时被自动调用

#### 7. 条件判断和循环

    # if-elif-else
    if enob > 10:
        print("优秀")
    elif enob > 8:
        print("良好")
    else:
        print("需改进")

    # for循环
    for i in range(5):        # i = 0, 1, 2, 3, 4
        print(i)

    for c in [0.1, 0.2, 0.3]:  # 遍历列表
        print(c)

    # 列表推导式（创建列表的简洁写法）
    squares = [x**2 for x in range(5)]  # [0, 1, 4, 9, 16]
    c_list = [params[f'c{i+1}'] for i in range(5)]  # 提取c1-c5

#### 8. 打印输出（f-string格式化）

    # print() 打印到控制台
    print("Hello")                      # 普通字符串
    print(bits)                         # 打印变量
    print("bits =", bits)               # 多个值用逗号

    # f-string格式化（推荐）
    print(f"ENOB: {enob}")              # {}内放变量
    print(f"ENOB: {enob:.2f} bits")    # :.2f 保留2位小数
    print(f"SNR: {snr:.1f} dB")         # :.1f 保留1位小数
    print(f"fs: {fs:.2e} Hz")           # :.2e 科学计数法
    print(f"提升: {improvement:+.2f}")  # :+ 显示正负号

#### 9. NumPy基础（信号处理必备）

    import numpy as np

    # 创建数组
    arr = np.array([1, 2, 3])          # 从列表创建
    zeros = np.zeros(10)               # 10个0
    ones = np.ones(10)                 # 10个1
    t = np.arange(1024)                # [0, 1, 2, ..., 1023]
    t = np.arange(0, 1, 0.001)        # 0到1，步长0.001
    t = np.linspace(0, 1, 1000)       # 0到1，共1000个点

    # 时间轴生成（ADC仿真常用）
    n_samples = 4096
    fs = 1e6
    t = np.arange(n_samples) / fs      # 时间轴（秒）

    # 生成正弦波
    fin = 10e3                         # 信号频率10kHz
    amplitude = 0.4                    # 振幅
    offset = 0.5                       # 直流偏置
    signal = offset + amplitude * np.sin(2 * np.pi * fin * t)

    # 生成随机噪声
    noise = np.random.normal(0, 0.001)         # 单个随机数
    noise = np.random.normal(0, 0.001, 1024)  # 1024个随机数

    # 数学函数
    y = np.sin(x)                      # 正弦
    y = np.cos(x)                      # 余弦
    y = np.abs(x)                      # 绝对值
    y = np.sqrt(x)                     # 平方根
    y = np.log10(x)                    # log10
    y = np.clip(x, 0, 1)               # 裁剪到[0,1]

    # 统计函数
    m = np.mean(arr)                   # 平均值
    s = np.std(arr)                    # 标准差
    mx = np.max(arr)                   # 最大值
    mn = np.min(arr)                   # 最小值

#### 10. try-except异常处理

    # 捕获错误，防止程序崩溃
    try:
        enob = evaluate_sd_adc(params)
        if enob <= 0 or np.isnan(enob):
            return -1000  # 返回惩罚值
        return enob
    except:
        return -1000  # 出错也返回惩罚值

#### 11. 常见错误解决

错误 | 原因 | 解决
--- | --- | ---
`ModuleNotFoundError` | 模块未安装 | `pip install -e .`
`IndentationError` | 缩进不对 | 用4个空格缩进
`NameError: xxx not defined` | 变量未定义 | 检查拼写或先赋值
`TypeError: missing argument` | 缺少参数 | 查看API文档补全参数
`IndexError: list index out of range` | 索引越界 | 检查列表长度
`KeyError: 'xxx'` | 字典键不存在 | 检查键名拼写

### 完整模板：复制即用

模板说明

下面是一个完整的ADC仿真模板，包含所有常用功能。复制后修改参数即可运行。

    """
    QuantiaMagica ADC仿真模板
    ========================
    复制此文件，修改参数即可运行

    使用前请先安装：
        cd QuantiaMagica
        pip install -e .
    """

    # ==================== 导入 ====================
    import numpy as np
    from quantiamagica import SARADC, SamplingEvent, ComparatorEvent

    # ==================== 参数设置 ====================
    BITS = 12              # ADC位数
    VREF = 1.0             # 参考电压 (V)
    FS = 1e6               # 采样率 (Hz)
    FIN = 10e3             # 信号频率 (Hz)
    N_SAMPLES = 4096       # 采样点数
    AMPLITUDE = 0.48       # 信号幅度 (V)
    OFFSET = 0.5           # 直流偏置 (V)

    # 非理想效应参数
    THERMAL_NOISE = 0.5e-3     # 热噪声 (V RMS)
    COMPARATOR_OFFSET = 1e-3   # 比较器失调 (V)

    # ==================== 创建ADC ====================
    adc = SARADC(bits=BITS, vref=VREF)

    # ==================== 添加非理想效应（可选） ====================
    @adc.on(SamplingEvent)
    def add_thermal_noise(event):
        """采样时添加热噪声"""
        event.voltage += np.random.normal(0, THERMAL_NOISE)

    @adc.on(ComparatorEvent)
    def add_comparator_offset(event):
        """比较器失调"""
        event.offset = COMPARATOR_OFFSET

    # ==================== 运行仿真 ====================
    print("运行仿真...")
    result = adc.sim(
        n_samples=N_SAMPLES,
        fs=FS,
        fin=FIN,
        amplitude=AMPLITUDE,
        offset=OFFSET
    )

    # ==================== 查看结果 ====================
    print(f"\n===== 仿真结果 =====")
    print(f"ENOB: {adc.enob():.2f} bits")
    print(f"SNR:  {adc.snr():.1f} dB")
    print(f"SFDR: {adc.sfdr():.1f} dB")
    print(f"THD:  {adc.thd():.1f} dB")

    # ==================== 可视化 ====================
    # 完整报告（推荐）
    adc.report()

    # 或者单独查看
    # adc.plot()           # 时域图
    # adc.spectrum()       # 频谱图
    # adc.report('static') # INL/DNL

    # ==================== 保存数据（可选） ====================
    # result.save("output.npz")           # NumPy格式
    # result.save("output.csv", format="csv")  # CSV格式

## 快速开始

### 最简代码（3行）

    from quantiamagica import SARADC

    adc = SARADC(bits=12, vref=1.0)  # 创建12位ADC
    adc.sim(fin=10e3)                   # 仿真10kHz正弦波
    adc.plot()                           # 画图

### 添加非理想效应（事件监听） - 核心功能

    # =============================================================
    # 事件驱动是QuantiaMagica的核心！
    # 通过监听ADC转换过程中的各个事件，可以轻松添加非理想效应
    # =============================================================

    from quantiamagica import SARADC, SamplingEvent, ComparatorEvent
    import numpy as np

    # 第1步：创建ADC实例
    adc = SARADC(bits=12, vref=1.0)

    # 第2步：用 @adc.on() 装饰器监听事件
    # 当ADC采样时，这个函数会被自动调用
    @adc.on(SamplingEvent)
    def add_thermal_noise(event):
        # event.voltage 是当前采样的电压值
        # 我们给它加上高斯噪声来模拟热噪声
        noise = np.random.normal(0, 0.0005)  # 0.5mV RMS噪声
        event.voltage += noise

    # 第3步：监听比较器事件，添加比较器失调
    @adc.on(ComparatorEvent)
    def add_comparator_offset(event):
        # event.offset 是比较器失调电压
        event.offset = 0.001  # 1mV失调
        # event.noise_sigma 是比较器噪声
        event.noise_sigma = 0.0002  # 0.2mV噪声

    # 第4步：运行仿真
    adc.sim(n_samples=4096, fs=1e6, fin=10e3)

    # 第5步：查看结果
    print(f"带非理想效应的ENOB: {adc.enob():.2f} bits")
    print(f"SNR: {adc.snr():.1f} dB")

    # 画图看效果
    adc.spectrum()

### 获取所有指标

    from quantiamagica import SARADC
    from quantiamagica.analysis import Analyzer

    adc = SARADC(bits=12)
    result = adc.sim()

    analyzer = Analyzer(result)
    print(analyzer.summary())  # 打印所有指标

### 使用Signal类生成各种信号

    from quantiamagica import SARADC, Signal

    adc = SARADC(bits=12)

    # 正弦波
    sig = Signal.sine(n=1024, freq=10e3)

    # 方波
    sig = Signal.square(n=1024, freq=1e3)

    # 三角波
    sig = Signal.triangle(n=1024, freq=1e3)

    # 扫频信号
    sig = Signal.chirp(n=2048, f_start=1e3, f_end=100e3)

    # 双音信号（IMD测试）
    sig = Signal.two_tone(f1=10e3, f2=11e3)

    # 从文件导入
    sig = Signal.from_file("my_data.csv")

    # 用于仿真
    adc.sim(sig)

## API 参考

### ADC 类型

#### SARADC - 逐次逼近型ADC

导入: `from quantiamagica import SARADC`

参数 | 类型 | 默认值 | 说明
--- | --- | --- | ---
bits | int | 10 | 分辨率位数
vref | float | 1.0 | 参考电压上限 (V)
vmin | float | 0.0 | 参考电压下限 (V)
cap_unit | float | 1.0 | 单位电容 (fF)
name | str | "SAR-ADC" | ADC名称

专用方法:

方法 | 说明
--- | ---
`set_radix(radix)` | 设置非二进制基数 (如1.85用于冗余SAR)
`set_capacitor_mismatch(sigma)` | 设置电容失配标准差
`code_to_voltage(code)` | 将输出码转换回电压

#### Pipeline - ADC级联链类 (独立于ADConverter)

导入: `from quantiamagica import Pipeline`

架构说明：Pipeline是独立的类（不继承ADConverter），用于将多个ADC（SAR/Sigma-Delta）串联成高精度流水线结构。

    输入V → [Stage1 ADC] → 残差×gain → [Stage2 ADC] → 残差×gain → [Stage3 ADC] → 合并输出码

参数 | 类型 | 默认值 | 说明
--- | --- | --- | ---
stages | List[ADConverter] | 必填 | ADC实例列表 (SARADC/SigmaDeltaADC)
gains | List[float] | 自动(2^bits) | 级间增益列表，长度=len(stages)-1
vref | float | 首级ADC的vref | 参考电压
name | str | "Pipeline" | Pipeline名称

属性:

属性 | 类型 | 说明
--- | --- | ---
`bits` | int | 总位数 = sum(各级bits)
`num_stages` | int | 级数
`lsb` | float | 最小分辨电压

方法:

方法 | 说明
--- | ---
`sim(n_samples, fs, fin, ...)` | 运行仿真
`enob()` | 计算有效位数
`snr(), sfdr(), thd()` | 性能指标
`spectrum(show=True)` | 频谱分析与绘图
`plot()` | 完整仿真结果绘图
`inl(plot=True), dnl(plot=True)` | INL/DNL分析
`report()` | 打印性能报告
`get_stage_info()` | 获取各级配置信息

使用示例:

    # 3×8-bit SAR → 24-bit Pipeline
    stages = [SARADC(bits=8) for _ in range(3)]
    pipeline = Pipeline(stages, gains=[256, 256])

    # 也支持Sigma-Delta ADC
    sd_stages = [SigmaDeltaADC(order=1, bits=1, osr=16) for _ in range(2)]
    sd_pipeline = Pipeline(sd_stages, gains=[16])

### ADConverter 基类方法 (所有ADC通用)

以下方法适用于 SARADC（Pipeline类有独立实现）

#### 仿真方法

方法 | 参数 | 说明
--- | --- | ---
`sim()` | input_voltage, n_samples, fs, signal, fin, amplitude, offset | 运行ADC仿真，返回SimulationResult
`sim_auto()` | fs, n_samples, verbose | 自动优化：DE算法+CUDA/CPU极限并发，自动检测GPU加速
`convert(voltage)` | voltage: float或array | 转换单个或多个电压值

#### 性能指标方法

方法 | 返回值 | 说明
--- | --- | ---
`enob()` | float | 有效位数 (bits)
`snr()` | float | 信噪比 (dB)
`sfdr()` | float | 无杂散动态范围 (dB)
`thd()` | float | 总谐波失真 (dB)
`sinad()` | float | 信号与噪声加失真比 (dB)
`inl()` | ndarray | 积分非线性 (LSB)
`dnl()` | ndarray | 微分非线性 (LSB)

#### 可视化方法

方法 | 参数 | 说明
--- | --- | ---
`plot()` | save, show, dpi | 绘制时域/数字输出/误差/直方图
`spectrum()` | show, window, save | 绘制频谱图，返回(freqs, power_db, metrics)
`report(what)` | what, save, show, columns | 推荐! 统一报告API (见下表)

#### report() 方法详解 (推荐使用)

简洁灵活的分析报告API:

    # 方式1: 链式调用 (仿真+报告一行完成)
    adc.sim().report()                    # 完整报告

    # 方式2: 分开调用 (仿真一次，多种报告)
    adc.sim()                             # 先仿真
    adc.report()                          # 完整报告
    adc.report('spectrum')               # 只看频谱图
    adc.report('metrics')                # 只打印数字
    adc.report(save='fig.pdf')           # 保存PDF

##### 报告类型详解 (what参数)

类型 | 说明 | 包含内容 | 使用场景
--- | --- | --- | ---
`'all'` | 完整报告 (默认) | 时域图 + 频谱图 + 数字输出图 | 日常分析、论文插图
`'spectrum'` | 频谱图 | FFT频谱 + ENOB/SNR/SFDR标注 | 查看噪声分布、谐波失真
`'time'` | 时域图 | 输入信号 vs 重建信号对比 | 检查采样是否正确
`'static'` | 静态特性 | INL曲线 + DNL曲线 | 分析非线性失真
`'metrics'` | 仅指标 (不画图) | 控制台打印 ENOB/SNR/SFDR/THD | 快速查看性能数字

##### 其他参数

参数 | 类型 | 说明 | 示例
--- | --- | --- | ---
save | str | 保存图像到文件 | `save='my_adc.pdf'`
show | bool | 是否弹出图像窗口 (默认True) | `show=False`
columns | int | 图像宽度: 1=单栏(3.5英寸), 2=双栏(7.16英寸) | `columns=2`

小白提示

不知道用什么？直接用 `adc.sim().report()` 就够了！它会显示所有你需要的信息。

#### 辅助函数 (从quantiamagica导入)

函数 | 说明 | 使用场景
--- | --- | ---
`plot_spectrum(codes, fs)` | 一键绘制频谱图 | 快速查看任意信号的频谱
`plot_comparison(data_list, fs, labels)` | 对比绘图 | 比较多个ADC性能
`compute_inband_snr(codes, bits, fs, fin, bw)` | 计算带内SNR | 过采样/Sigma-Delta系统
`auto_time_unit(time_array)` | 自动选择时间单位 | 绘图时自适应ns/μs/ms/s
`auto_freq_unit(freq_array)` | 自动选择频率单位 | 绘图时自适应Hz/kHz/MHz
`apply_jssc_style()` | 应用JSSC绘图风格 | 论文级图像

##### 辅助函数代码示例

    # ========== 示例1: 一键绘制频谱 ==========
    from quantiamagica import SARADC, plot_spectrum

    adc = SARADC(bits=12)
    result = adc.sim(n_samples=4096)

    # 一行代码画频谱！自动计算SNR/ENOB并标注
    plot_spectrum(result.output_codes, fs=1e6, title="我的ADC频谱")

    # ========== 示例2: 对比两个ADC ==========
    from quantiamagica import SARADC, plot_comparison

    # 创建两个ADC
    adc1 = SARADC(bits=8)
    adc2 = SARADC(bits=12)

    # 分别仿真
    r1 = adc1.sim(n_samples=4096)
    r2 = adc2.sim(n_samples=4096)

    # 一行代码对比两个频谱！
    plot_comparison(
        [r1.output_codes, r2.output_codes],  # 数据列表
        fs=1e6,                              # 采样率
        labels=['8-bit', '12-bit'],         # 标签
        save='comparison.png'               # 保存图片
    )

    # ========== 示例3: 计算带内SNR (Sigma-Delta/过采样) ==========
    from quantiamagica import compute_inband_snr

    # 假设你有过采样的ADC输出码
    codes = ...  # 你的数据
    snr, enob = compute_inband_snr(
        codes,
        bits=4,           # 量化器位数
        fs=1e6,           # 采样率 1MHz
        signal_freq=1e3,  # 信号频率 1kHz
        bandwidth=10e3    # 只计算10kHz带宽内的噪声
    )
    print(f"带内SNR: {snr:.1f}dB, ENOB: {enob:.2f}bits")

#### 事件系统方法

方法 | 说明
--- | ---
`on(EventType, priority)` | 装饰器，注册事件处理函数
`fire(event)` | 触发事件
`register(EventType, callback)` | 编程式注册事件处理
`unregister(EventType, callback)` | 移除事件处理函数

### SAR ADC 事件

导入: `from quantiamagica import SamplingEvent, ComparatorEvent, ...`

#### ConversionStartEvent

转换开始时触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
timestamp | float | 否 | 仿真时间
sample_index | int | 否 | 当前采样索引
input_voltage | float | 是 | 输入电压

#### SamplingEvent (可取消)

采样阶段触发，用于添加采样噪声、失调等

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
voltage | float | 是 | 采样电压 (修改此值添加噪声)
sampling_capacitance | float | 是 | 采样电容 (fF)
sample_index | int | 否 | 当前采样索引

#### CapacitorSwitchEvent (可取消)

电容切换时触发，用于模拟电容失配

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
bit_index | int | 否 | 当前位索引 (MSB=0)
capacitance | float | 否 | 理想电容值
capacitance_actual | float | 是 | 实际电容值
weight | float | 是 | 位权重
charge_injection | float | 是 | 电荷注入 (V)
settling_error | float | 是 | 建立误差

#### ComparatorEvent (可取消)

比较器判决时触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
input_voltage | float | 否 | 比较器输入
threshold | float | 是 | 判决阈值
offset | float | 是 | 比较器失调 (V)
noise_sigma | float | 是 | 比较器噪声标准差 (V)
decision | int | 是 | 判决结果 (0或1)
metastable | bool | 是 | 是否在亚稳态区

#### BitDecisionEvent (可取消)

每位决定后触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
bit_index | int | 否 | 位索引
bit_value | int | 是 | 位值 (可翻转)
dac_voltage | float | 否 | 当前DAC电压

#### OutputCodeEvent

输出码就绪时触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
code | int | 是 | 输出码
input_voltage | float | 否 | 原始输入电压

#### ConversionEndEvent

转换结束时触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
code | int | 否 | 最终输出码
conversion_time | float | 否 | 转换耗时

### Pipeline ADC 事件

导入: `from quantiamagica import Pipeline, SARADC, StageEvent, ResidueEvent, InterstageGainEvent`

#### StageEvent

进入新的流水线级时触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
stage_index | int | 否 | 级索引 (0-indexed)
stage_adc | ADConverter | 否 | 该级使用的子ADC实例
input_voltage | float | 否 | 级输入电压
sample_index | int | 否 | 全局采样索引

#### ResidueEvent (可取消)

计算残差电压时触发

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
stage_index | int | 否 | 级索引
input_voltage | float | 否 | 级输入电压
dac_voltage | float | 否 | DAC输出电压
residue | float | 是 | 残差电压 (可注入误差)
ideal_residue | float | 否 | 理想残差

#### InterstageGainEvent (可取消)

级间放大时触发，用于模拟运放非理想特性

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
stage_index | int | 否 | 级索引
input_voltage | float | 否 | 放大器输入 (残差电压)
ideal_gain | float | 否 | 理想增益 (通常为2^stage_bits)
actual_gain | float | 是 | 实际增益 (模拟有限增益)
offset | float | 是 | 放大器失调 (V)
noise_sigma | float | 是 | 放大器噪声标准差 (V)
output_voltage | float | 否 | 放大输出电压 (事件后计算)
bandwidth | float | 是 | 放大器带宽 (Hz)
settling_error | float | 是 | 不完全建立误差

### Sigma-Delta ADC

导入: `from quantiamagica import SigmaDeltaADC, QuantizerEvent`

#### SigmaDeltaADC 类

简洁灵活的Sigma-Delta调制器，内置1阶/2阶CIFB实现，通过QuantizerEvent实现任意拓扑

参数 | 默认值 | 说明
--- | --- | ---
order | 1 | 调制器阶数 (1或2)
bits | 1 | 量化器位数
osr | 64 | 过采样率
vref | 1.0 | 参考电压

#### QuantizerEvent (可取消) - 唯一事件

每个时钟周期触发，提供完整信息实现任意拓扑

属性 | 类型 | 可修改 | 说明
--- | --- | --- | ---
input_signal | float | 否 | 当前输入 x[n] ([-1,1])
prev_output | float | 否 | 前一输出 y[n-1]
integrator_states | List | 否 | 各级积分器状态（只读）
quantizer_input | float | 是 | 量化器输入（修改此值实现自定义拓扑）
output | float | 是 | 量化输出 ([-1,1])
output_code | int | 是 | 数字码
offset | float | 是 | 比较器偏移
noise_sigma | float | 是 | 比较器噪声

#### 使用示例

    from quantiamagica import SigmaDeltaADC, QuantizerEvent
    import numpy as np

    # 1阶1-bit SD，OSR=64
    sd = SigmaDeltaADC(order=1, bits=1, osr=64)

    # 通过QuantizerEvent添加非理想效应
    @sd.on(QuantizerEvent)
    def add_nonidealities(event):
        # 积分器泄漏：修改量化器输入
        event.quantizer_input *= 0.999
        # 比较器噪声
        event.noise_sigma = 0.01

    # 生成输入信号（amplitude由用户控制，推荐0.3-0.45）
    t = np.arange(8192) / 1e6
    signal = 0.5 + 0.4 * np.sin(2 * np.pi * 1e3 * t)

    # 仿真
    sd.sim(signal, fs=1e6)
    print(f"ENOB: {sd.enob():.2f}")

    # 自定义拓扑示例：完全自定义2阶调制器
    my_u1, my_u2 = 0.0, 0.0

    @sd.on(QuantizerEvent)
    def custom_2nd_order(event):
        global my_u1, my_u2
        x, y_prev = event.input_signal, event.prev_output
        my_u1 = my_u1 + x - y_prev
        my_u2 = my_u2 + my_u1 - 2*y_prev
        event.quantizer_input = my_u2  # 覆盖默认

### 事件优先级 (EventPriority)

导入: `from quantiamagica import EventPriority`

优先级 | 值 | 说明
--- | --- | ---
LOWEST | 0 | 最先执行，可被后续处理器覆盖
LOW | 1 | 低优先级
NORMAL | 2 | 默认优先级
HIGH | 3 | 高优先级
HIGHEST | 4 | 最高优先级，最后修改机会
MONITOR | 5 | 只读监控，不应修改事件

### Signal 信号类

导入: `from quantiamagica import Signal` 或 `from quantiamagica.signals import Signal`

#### 基本信号

方法 | 参数 | 说明
--- | --- | ---
`Signal.sine()` | n, fs, freq, amplitude, offset, phase, coherent | 正弦波
`Signal.cosine()` | 同上 | 余弦波
`Signal.square()` | n, fs, freq, amplitude, offset, duty | 方波
`Signal.triangle()` | n, fs, freq, amplitude, offset | 三角波
`Signal.sawtooth()` | n, fs, freq, amplitude, offset | 锯齿波

#### 测试信号

方法 | 说明
--- | ---
`Signal.ramp()` | 斜坡信号 (INL/DNL测试)
`Signal.step()` | 阶跃信号
`Signal.pulse()` | 脉冲信号

#### 多频信号

方法 | 说明
--- | ---
`Signal.multitone()` | 多音信号
`Signal.two_tone()` | 双音信号 (IMD测试)

#### 调制信号

方法 | 说明
--- | ---
`Signal.chirp()` | 扫频信号
`Signal.am()` | 调幅信号
`Signal.fm()` | 调频信号

#### 噪声信号

方法 | 说明
--- | ---
`Signal.noise_gaussian()` | 高斯白噪声
`Signal.noise_uniform()` | 均匀分布噪声

#### 导入/导出

方法 | 说明
--- | ---
`Signal.from_file(path, fs)` | 从CSV/NPZ文件导入
`Signal.from_array(data, fs)` | 从NumPy数组创建
`signal.save(path)` | 保存到文件

#### 信号处理方法

方法 | 说明
--- | ---
`signal.add_noise(sigma)` | 添加高斯噪声
`signal.add_offset(offset)` | 添加直流偏置
`signal.scale(factor)` | 缩放振幅
`signal.clip(vmin, vmax)` | 裁剪到范围
`signal.normalize()` | 归一化到[0,1]

#### 信号属性

属性 | 说明
--- | ---
`signal.data` | 电压数据数组
`signal.fs` | 采样率
`signal.n_samples` | 采样点数
`signal.vpp` | 峰峰值电压
`signal.vrms` | RMS电压
`signal.mean` | 平均值

### 遗传算法优化库 (quantiamagica.optim)

高度抽象的遗传算法优化库，支持CUDA/CPU并行计算，可用于优化任意ADC参数。自动斜率收敛，无需手动设置迭代次数。

#### Gene - 基因定义

导入: `from quantiamagica.optim import Gene`

参数 | 类型 | 说明
--- | --- | ---
name | str | 参数名称
low | float | 下界
high | float | 上界
dtype | str | 'float', 'int', 'choice', 'bool'
choices | list | 离散选择列表 (仅dtype='choice'时)
log_scale | bool | 是否使用对数尺度

#### GeneticOptimizer - 遗传算法优化器

导入: `from quantiamagica.optim import GeneticOptimizer`

参数 | 类型 | 说明
--- | --- | ---
genes | List[Gene] | 基因定义列表
fitness_fn | Callable | 适应度函数 (接受dict返回float)
maximize | bool | 是否最大化 (默认True)

run() 方法参数:

参数 | 默认值 | 说明
--- | --- | ---
population_size | 50 | 种群大小
max_generations | 200 | 最大迭代代数（自动收敛通常不会到达）
slope_window | 5 | 斜率计算窗口
slope_threshold | 0.001 | 收敛斜率阈值
verbose | True | 显示进度
seed | None | 随机种子

#### OptimizationResult - 优化结果

属性 | 类型 | 说明
--- | --- | ---
best_params | Dict | 最佳参数
best_fitness | float | 最佳适应度
history | List[float] | 每代最佳适应度历史
generations | int | 实际迭代代数
converged | bool | 是否收敛

#### SDCoeffOptimizer - SD ADC系数优化器

导入: `from quantiamagica.optim import SDCoeffOptimizer`

参数 | 默认值 | 说明
--- | --- | ---
order | 2 | 调制器阶数
bits | 1 | 量化器位数
osr | 64 | 过采样率
fs | 1e6 | 采样频率

注意: SAR/Pipeline ADC使用通用GeneticOptimizer进行高度自定义优化。

优化器特性

- 自动斜率收敛 - 无需设置迭代次数，适应度斜率平滑时自动停止
- CUDA自动检测 - 有GPU时自动加速
- 并行评估 - 多线程评估种群
- 高度抽象 - 支持任意ADC、任意参数、任意适应度函数

## 完整示例

### 示例1：NS-SAR（噪声整形SAR）配合过采样

NS-SAR原理

噪声整形将量化噪声推向高频，配合过采样(OSR)可在信号带宽内获得更高分辨率。
噪声传递函数: NTF = (1 - z⁻¹)，一阶整形可提升约 0.5×log₂(OSR) + 1.5 bits ENOB。

    from quantiamagica import SARADC, SamplingEvent, OutputCodeEvent, EventPriority
    import numpy as np

    # 参数设置
    BITS = 8
    FS = 1e6          # 采样率 1MHz
    OSR = 64          # 过采样率
    SIGNAL_BW = FS / (2 * OSR)  # 信号带宽 ≈ 7.8kHz

    # 创建NS-SAR插件类
    class NoiseShapingSAR:
        def __init__(self, feedback_coeff=1.0):
            self.feedback_coeff = feedback_coeff
            self.prev_residue = 0.0
            self.sampled_voltage = 0.0

        def attach(self, adc):
            @adc.on(SamplingEvent, priority=EventPriority.HIGH)
            def apply_feedback(event):
                # 加入上次的量化残差
                event.voltage += self.feedback_coeff * self.prev_residue
                self.sampled_voltage = event.voltage

            @adc.on(OutputCodeEvent, priority=EventPriority.HIGH)
            def capture_residue(event):
                # 残差 = 采样电压 - DAC输出
                reconstructed = adc.code_to_voltage(event.code)
                self.prev_residue = self.sampled_voltage - reconstructed

    # 使用
    adc = SARADC(bits=BITS, vref=1.0)
    ns_plugin = NoiseShapingSAR(feedback_coeff=1.0)
    ns_plugin.attach(adc)

    adc.sim(n_samples=16384, fs=FS, fin=1e3)
    print(f"NS-SAR 带内ENOB大幅提升!")
    # 运行 examples/03_ns_sar.py 查看完整对比

### 示例2：Pipeline ADC带级间增益误差

    from quantiamagica import Pipeline, SARADC, InterstageGainEvent

    # 创建3个8-bit SAR ADC串联成24-bit Pipeline
    stages = [SARADC(bits=8) for _ in range(3)]
    pipeline = Pipeline(stages=stages, interstage_gains=[256, 256])

    @pipeline.on(InterstageGainEvent)
    def gain_error(event):
        # 模拟1000倍运放有限增益带来的误差
        opamp_gain = 1000
        event.actual_gain = event.ideal_gain * (1 - 1/opamp_gain)
        event.offset = 0.5e-3  # 0.5mV失调

    pipeline.sim(n_samples=65536)
    pipeline.spectrum()
    print(f"ENOB: {pipeline.enob():.2f}")  # 理想~23.99, 带误差~17.9

### 示例3：统一报告API（推荐）

    from quantiamagica import SARADC

    adc = SARADC(bits=12)

    # 仿真一次
    adc.sim()

    # 然后可以多次调用report()查看不同报告 (不会重复仿真)
    adc.report()                          # 完整报告
    adc.report('spectrum')               # 仅频谱
    adc.report('metrics')                # 仅打印指标
    adc.report(save='fig.pdf')           # 保存PDF

    # 可选参数：
    # what: 'all'|'spectrum'|'time'|'static'|'metrics'
    # columns: 1(单栏3.5") 或 2(双栏7.16")

### 示例4：自动优化测试参数 (sim_auto)

sim_auto 原理

差分进化算法(DE) + 极限并发 + 自适应参数：

- GPU检测：自动检测CUDA，GPU可用时种群128
- CPU并发：4x CPU核心数并行计算
- 快速收敛：通常2-4代即可收敛
- ADC自适应：
  - SAR/Pipeline: 幅度99.8%满量程，n_samples=2^bits
  - Sigma-Delta: 幅度根据阶数自动缩小(避免震荡)，n_samples=OSR*256向上取2的幂

GPU加速安装

要启用CUDA GPU加速，需安装PyTorch CUDA版本：

    pip install torch --index-url https://download.pytorch.org/whl/cu121

若安装到自定义路径，需设置环境变量：

    $env:PYTHONPATH = "D:\Python\Lib\site-packages"  # PowerShell
    set PYTHONPATH=D:\Python\Lib\site-packages           # CMD

支持NVIDIA显卡(RTX 20/30/40系列)。

    from quantiamagica import SARADC

    adc = SARADC(bits=12)

    # 一行代码 - 自动优化！
    result = adc.sim_auto(fs=1e6)  # 只需指定fs

    # 返回值包含最优参数
    print(f"最佳fin: {result['best_fin']:.2f} Hz")
    print(f"最佳幅度: {result['best_amplitude']:.4f} V")
    print(f"最佳ENOB: {result['best_enob']:.4f} bits")
    print(f"收敛代数: {result['generations']}")
    print(f"收敛原因: {result['reason']}")

    # 结果已保存，可直接画图
    adc.report()

    # 适用于所有ADC类型
    from quantiamagica import PipelineADC, SigmaDeltaADC
    PipelineADC(12).sim_auto(fs=1e6)
    SigmaDeltaADC(order=2, bits=1, osr=64).sim_auto(fs=1e6)

### 示例5：Sigma-Delta ADC（自定义复杂拓扑）

    # =============================================================
    # Sigma-Delta ADC: 通过QuantizerEvent实现任意复杂拓扑
    # 演示：自定义2阶CIFB差分方程
    # =============================================================

    from quantiamagica import SigmaDeltaADC, QuantizerEvent
    import numpy as np

    # 参数
    OSR, FS, N = 64, 1e6, 64 * 2048
    FIN = 13 * FS / N
    t = np.arange(N) / FS
    signal = 0.5 + 0.4 * np.sin(2 * np.pi * FIN * t)  # 80%幅度

    # =============== 自定义2阶CIFB拓扑 ===============
    # 差分方程:
    #   u1[n] = u1[n-1] + x[n] - y[n-1]
    #   u2[n] = u2[n-1] + u1[n] - 2*y[n-1]
    #   v[n] = u2[n]  (量化器输入)
    # NTF = (1-z^-1)^2

    state = [0.0, 0.0]  # [u1, u2] 积分器状态

    sd = SigmaDeltaADC(order=1, bits=1, osr=OSR)

    @sd.on(QuantizerEvent)
    def custom_2nd_order_cifb(event):
        x = event.input_signal   # 当前输入
        y = event.prev_output    # 前一输出 (反馈)

        # 实现2阶CIFB差分方程
        state[0] = state[0] + x - y           # 第一级积分器
        state[1] = state[1] + state[0] - 2*y  # 第二级积分器

        # 覆盖量化器输入 (关键!)
        event.quantizer_input = state[1]

    sd.sim(signal, fs=FS)
    sd._result.metadata['fin'] = FIN
    print(f"自定义2阶ENOB: {sd.enob():.2f} bits")  # ~11.67 bits

    # =============== 1-bit 3阶Sigma-Delta ===============
    # 1-bit 3阶需要: 缩放积分器(c=0.3) + 小输入幅度
    u3 = [0.0, 0.0, 0.0]
    c = 0.3  # 积分器缩放系数

    sd3 = SigmaDeltaADC(order=1, bits=1, osr=OSR)

    @sd3.on(QuantizerEvent)
    def third_order_1bit(event):
        x, y = event.input_signal, event.prev_output
        u3[0] = u3[0] + c * (x - y)
        u3[1] = u3[1] + c * (u3[0] - 2*y)
        u3[2] = u3[2] + c * (u3[1] - y)
        event.quantizer_input = u3[2]

    signal_3rd = 0.5 + 0.2 * np.sin(2 * np.pi * FIN * t)
    sd3.sim(signal_3rd, fs=FS)
    sd3._result.metadata['fin'] = FIN
    print(f"3阶1-bit ENOB: {sd3.enob():.2f} bits")  # ~12.7 bits

### 示例4：遗传算法优化Sigma-Delta系数

为什么需要优化Sigma-Delta系数？

Sigma-Delta调制器的性能取决于积分器增益(c1, c2)、反馈系数(a1, a2)和输入幅度(amplitude)。 不同的系数组合会影响：

- 稳定性 - 错误的系数导致振荡(ENOB≤0)
- ENOB - 好的系数可以提升1-2 bits
- 动态范围 - 幅度太大会过载，太小会降低SNR

    import numpy as np
    from quantiamagica import SigmaDeltaADC, QuantizerEvent
    from quantiamagica.optim import GeneticOptimizer, Gene

    # ===================== Step 1: 定义仿真参数 =====================
    OSR = 64                        # 过采样率
    FS = 1e6                        # 采样频率 1MHz
    N_SAMPLES = OSR * 128           # 采样点数
    FIN = 13 * FS / N_SAMPLES       # 相干采样频率

    # ===================== Step 2: 定义要优化的基因 =====================
    # 每个Gene定义一个参数的搜索范围
    genes = [
        Gene('c1', 0.1, 0.8, 'float'),       # 第1级积分器增益
        Gene('c2', 0.1, 0.8, 'float'),       # 第2级积分器增益
        Gene('a1', 0.5, 2.5, 'float'),       # 第1级反馈系数
        Gene('a2', 0.5, 3.5, 'float'),       # 第2级反馈系数
        Gene('amplitude', 0.15, 0.4, 'float'),  # 输入正弦波幅度
    ]

    # ===================== Step 3: 定义评估函数 =====================
    # 这个函数接收一组参数，返回ENOB
    def evaluate_sd_adc(params):
        """创建2阶CIFB Sigma-Delta并评估ENOB"""
        c1, c2 = params['c1'], params['c2']
        a1, a2 = params['a1'], params['a2']
        amplitude = params['amplitude']

        # 创建基础1阶SD ADC（我们通过事件扩展为2阶）
        sd = SigmaDeltaADC(order=1, bits=1, osr=OSR)
        state = [0.0, 0.0]  # 两个积分器的状态

        # 定义2阶CIFB拓扑
        @sd.on(QuantizerEvent)
        def second_order_cifb(event):
            x = event.input_signal      # 输入信号
            y = event.prev_output       # 量化器输出反馈 (+1/-1)
            # CIFB结构: 两级积分器 + 反馈
            state[0] = state[0] + c1 * (x - a1 * y)  # 第1级
            state[1] = state[1] + c2 * (state[0] - a2 * y)  # 第2级
            event.quantizer_input = state[1]  # 输出到量化器

        # 生成输入信号
        t = np.arange(N_SAMPLES) / FS
        signal = 0.5 + amplitude * np.sin(2 * np.pi * FIN * t)

        # 仿真并计算ENOB
        sd.sim(signal, fs=FS)
        sd._result.metadata['fin'] = FIN
        return sd.enob()

    # ===================== Step 4: 定义适应度函数 =====================
    # 遗传算法最大化此函数
    def fitness(params):
        try:
            enob = evaluate_sd_adc(params)
            if enob <= 0 or np.isnan(enob) or enob > 30:
                return -1000  # 振荡或异常，给予惩罚
            # 目标：最大化ENOB，同时奖励较大的输入幅度
            return enob * 10 + params['amplitude'] * 5
        except:
            return -1000

    # ===================== Step 5: 运行优化 =====================
    optimizer = GeneticOptimizer(genes, fitness, maximize=True)
    result = optimizer.run(population_size=40)  # 自动收敛，无需设置代数

    # ===================== Step 6: 获取优化后的系数 =====================
    print("优化后的系数:")
    print(f"  c1 = {result.best_params['c1']:.4f}")  # 积分器1增益
    print(f"  c2 = {result.best_params['c2']:.4f}")  # 积分器2增益
    print(f"  a1 = {result.best_params['a1']:.4f}")  # 反馈系数1
    print(f"  a2 = {result.best_params['a2']:.4f}")  # 反馈系数2
    print(f"  amplitude = {result.best_params['amplitude']:.4f}")

    # 验证优化结果
    optimized_enob = evaluate_sd_adc(result.best_params)
    print(f"\n优化后ENOB: {optimized_enob:.2f} bits")

    # ===================== 对比：默认系数 vs 优化系数 =====================
    default_params = {'c1': 0.5, 'c2': 0.5, 'a1': 1.0, 'a2': 2.0, 'amplitude': 0.3}
    default_enob = evaluate_sd_adc(default_params)
    print(f"默认系数ENOB: {default_enob:.2f} bits")
    print(f"提升: +{optimized_enob - default_enob:.2f} bits")

result对象包含的信息

属性 | 说明 | 示例
--- | --- | ---
`result.best_params` | 优化后的参数字典 | `{'c1': 0.6018, 'c2': 0.6467, ...}`
`result.best_fitness` | 最佳适应度值 | `121.84`
`result.generations` | 实际迭代代数 | `13`
`result.converged` | 是否收敛 | `True`
`result.history` | 每代最佳适应度 | `[80.5, 95.2, ...]`

#### 快捷方式：SDCoeffOptimizer

如果只需优化标准SD ADC系数，可以使用封装好的优化器：

    from quantiamagica.optim import SDCoeffOptimizer

    # 一行创建 + 一行优化
    sd_opt = SDCoeffOptimizer(order=2, bits=1, osr=64, fs=1e6)
    result = sd_opt.optimize()

    # 打印优化报告
    print(result.summary())

    # 获取优化后的系数
    print(result.best_params)       # 所有参数
    print(result.best_params['c1']) # 单个参数
    print(result.best_enob)         # 优化后的ENOB
    print(result.baseline_enob)     # 优化前的ENOB
    print(result.improvement)       # 提升了多少bits

### 示例5：五阶Sigma-Delta极致优化

高阶SD ADC优化挑战

5阶SD ADC有11个待优化参数，搜索空间巨大。默认系数往往直接振荡(ENOB<0)， 遗传算法可以找到稳定且高性能的系数组合。

    from quantiamagica import SigmaDeltaADC, QuantizerEvent
    from quantiamagica.optim import GeneticOptimizer, Gene
    import numpy as np

    OSR, FS = 64, 1e6
    N_SAMPLES = OSR * 256
    FIN = 13 * FS / N_SAMPLES

    # 定义5阶SD ADC的11个基因
    genes = [
        # 积分器增益 (越往后越小以保持稳定)
        Gene('c1', 0.1, 0.5, 'float'),
        Gene('c2', 0.08, 0.4, 'float'),
        Gene('c3', 0.05, 0.3, 'float'),
        Gene('c4', 0.03, 0.2, 'float'),
        Gene('c5', 0.02, 0.15, 'float'),
        # 反馈系数
        Gene('a1', 0.8, 3.0, 'float'),
        Gene('a2', 0.5, 2.5, 'float'),
        Gene('a3', 0.3, 2.0, 'float'),
        Gene('a4', 0.2, 1.5, 'float'),
        Gene('a5', 0.1, 1.0, 'float'),
        Gene('amplitude', 0.08, 0.25, 'float'),
    ]

    def evaluate_5th_order(params):
        c = [params[f'c{i+1}'] for i in range(5)]
        a = [params[f'a{i+1}'] for i in range(5)]

        sd = SigmaDeltaADC(order=1, bits=1, osr=OSR)
        state = [0.0] * 5

        @sd.on(QuantizerEvent)
        def fifth_order(event):
            x, y = event.input_signal, event.prev_output
            state[0] = state[0] + c[0] * (x - a[0] * y)
            for i in range(1, 5):
                state[i] = state[i] + c[i] * (state[i-1] - a[i] * y)
            event.quantizer_input = state[4]

        t = np.arange(N_SAMPLES) / FS
        signal = 0.5 + params['amplitude'] * np.sin(2*np.pi*FIN*t)
        sd.sim(signal, fs=FS)
        sd._result.metadata['fin'] = FIN
        return sd.enob()

    def fitness(params):
        enob = evaluate_5th_order(params)
        return enob if enob > 0 else -1000

    optimizer = GeneticOptimizer(genes, fitness, maximize=True)
    result = optimizer.run(population_size=80)

    print(f"优化后ENOB: {result.best_fitness:.2f} bits")
    print(f"系数: {result.best_params}")

优化结果 (实测)

默认系数: 振荡 (ENOB=-3.55) → 优化后: 16.19 bits
收敛代数: 24代，进度条显示斜率收敛过程

## 常见问题

#### Q: 为什么导入报错 ModuleNotFoundError?

确保你已经安装了QuantiaMagica。在项目目录下运行 `pip install -e .`

#### Q: 画图时中文显示为方块怎么办?

这是matplotlib字体问题。可以设置中文字体：

    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 黑体

#### Q: 如何保存仿真数据?

    result = adc.sim()
    result.save("data.npz")       # NumPy格式
    result.save("data.csv", format="csv")  # CSV格式

#### Q: 如何从CSV文件导入自定义信号?

    from quantiamagica import Signal

    # CSV文件格式：每行一个电压值
    sig = Signal.from_file("my_signal.csv", fs=1e6)
    adc.sim(sig)

## 练习题

通过以下练习题逐步掌握QuantiaMagica的使用。点击"查看答案"可以看到参考解答。

1 入门 Hello ADC - 第一个仿真

目标：创建一个8位SAR ADC，运行仿真并打印ENOB值。

要求：

- ADC位数：8位
- 参考电压：1.0V（默认）
- 打印格式：`ENOB: X.XX bits`

提示：使用 `SARADC(bits=8)` 创建ADC，`adc.sim()` 运行仿真，`adc.enob()` 获取ENOB。

    from quantiamagica import SARADC

    # 创建8位SAR ADC
    adc = SARADC(bits=8)

    # 运行仿真
    adc.sim()

    # 打印ENOB
    print(f"ENOB: {adc.enob():.2f} bits")

预期输出：`ENOB: 7.xx bits`（理想8位ADC的ENOB接近8）

2 入门 查看更多指标

目标：创建12位ADC，仿真后打印SNR、SFDR、THD三个指标。

要求：

- ADC位数：12位
- 采样点数：4096
- 分别打印SNR、SFDR、THD，单位为dB

提示：使用 `adc.snr()`、`adc.sfdr()`、`adc.thd()` 获取各指标。

    from quantiamagica import SARADC

    adc = SARADC(bits=12)
    adc.sim(n_samples=4096)

    print(f"SNR:  {adc.snr():.1f} dB")
    print(f"SFDR: {adc.sfdr():.1f} dB")
    print(f"THD:  {adc.thd():.1f} dB")

3 入门 绘制频谱图

目标：创建10位ADC，使用50kHz输入信号仿真，绘制频谱图。

要求：

- ADC位数：10位
- 输入频率：50kHz
- 采样率：1MHz
- 显示频谱图

提示：使用 `adc.sim(fin=50e3, fs=1e6)` 设置参数，`adc.spectrum()` 绘制频谱。

    from quantiamagica import SARADC

    adc = SARADC(bits=10)
    adc.sim(fin=50e3, fs=1e6, n_samples=4096)
    adc.spectrum()

说明：频谱图中可以看到50kHz处的基波和量化噪声底。

4 进阶 完整事件处理 - 多事件监听

目标：同时使用SamplingEvent、CapacitorSwitchEvent、ComparatorEvent三种事件，模拟真实ADC的多种非理想效应。

要求：

- SamplingEvent: 基于kT/C公式计算热噪声 (C=1000fF)
- CapacitorSwitchEvent: 添加0.5%电容失配
- ComparatorEvent: 添加0.5mV失调和0.1mV噪声
- 对比理想ADC和非理想ADC的ENOB

提示：kT/C噪声公式: `noise_sigma = sqrt(kT/C)`，其中kT = 1.38e-23 * 300。电容失配用 `event.capacitance_actual = event.capacitance * (1 + mismatch)`。

    from quantiamagica import (
        SARADC,
        SamplingEvent,
        CapacitorSwitchEvent,
        ComparatorEvent,
    )
    import numpy as np

    # ========== 理想ADC ==========
    ideal_adc = SARADC(bits=10, vref=1.0, name="Ideal")
    ideal_adc.sim(n_samples=1024, fs=1e6, fin=10e3)

    # ========== 非理想ADC ==========
    real_adc = SARADC(bits=10, vref=1.0, name="Realistic")

    # 事件1: 采样时添加kT/C热噪声
    @real_adc.on(SamplingEvent)
    def add_thermal_noise(event):
        kT = 1.38e-23 * 300  # Boltzmann * Temperature
        C = 1000e-15          # 1000fF = 1pF
        noise_sigma = np.sqrt(kT / C)
        event.voltage += np.random.normal(0, noise_sigma)

    # 事件2: 电容切换时添加失配
    @real_adc.on(CapacitorSwitchEvent)
    def add_cap_mismatch(event):
        mismatch = np.random.normal(0, 0.005)  # 0.5% mismatch
        event.capacitance_actual = event.capacitance * (1 + mismatch)

    # 事件3: 比较器非理想效应
    @real_adc.on(ComparatorEvent)
    def add_comparator_effects(event):
        event.offset = 0.5e-3       # 0.5mV失调
        event.noise_sigma = 0.1e-3  # 0.1mV噪声

    real_adc.sim(n_samples=1024, fs=1e6, fin=10e3)

    # ========== 对比结果 ==========
    print(f"理想ADC:   ENOB={ideal_adc.enob():.2f}, SNR={ideal_adc.snr():.1f}dB")
    print(f"非理想ADC: ENOB={real_adc.enob():.2f}, SNR={real_adc.snr():.1f}dB")

说明：这展示了事件驱动的核心：每个事件对应ADC转换过程中的一个物理步骤，可以在该步骤注入非理想效应。

5 进阶 事件优先级与监控模式

目标：使用EventPriority控制事件处理顺序，使用MONITOR优先级记录转换结果。

要求：

- 使用HIGH优先级添加采样噪声（先执行）
- 使用NORMAL优先级添加比较器效应（后执行）
- 使用MONITOR优先级记录前5个采样的输出码（只读，不修改）

提示：装饰器可以指定优先级：`@adc.on(Event, priority=EventPriority.HIGH)`。MONITOR优先级的处理器不应修改事件。

    from quantiamagica import (
        SARADC,
        SamplingEvent,
        ComparatorEvent,
        OutputCodeEvent,
        EventPriority,
    )
    import numpy as np

    adc = SARADC(bits=10, vref=1.0, name="Priority-Demo")

    # HIGH优先级：最先执行
    @adc.on(SamplingEvent, priority=EventPriority.HIGH)
    def add_noise_first(event):
        """采样噪声，优先执行"""
        kT = 1.38e-23 * 300
        C = event.sampling_capacitance * 1e-15
        noise_sigma = np.sqrt(kT / C)
        event.voltage += np.random.normal(0, noise_sigma)

    # NORMAL优先级：默认顺序
    @adc.on(ComparatorEvent)
    def comparator_effects(event):
        """比较器效应"""
        event.offset = 0.5e-3
        event.noise_sigma = 0.1e-3

    # MONITOR优先级：只读监控，最后执行
    @adc.on(OutputCodeEvent, priority=EventPriority.MONITOR)
    def log_output(event):
        """记录转换结果（只读）"""
        if event.source._sample_index < 5:
            print(f"Sample {event.source._sample_index}: "
                  f"V={event.input_voltage:.4f}V -> Code={event.code}")

    print("前5个采样的转换记录：")
    adc.sim(n_samples=1024, fs=1e6, fin=10e3)
    print(f"\nENOB: {adc.enob():.2f} bits")

优先级顺序：HIGHEST > HIGH > NORMAL > LOW > LOWEST > MONITOR

6 进阶 Pipeline: 3×8-bit SAR串联成24-bit

目标：使用新的Pipeline类（不继承ADConverter）将3个8-bit SAR ADC串联成24-bit高精度Pipeline，并用InterstageGainEvent添加非理想效应。

Pipeline架构说明：

    输入V → [Stage1: 8-bit SAR] → 残差×256 → [Stage2: 8-bit SAR] → 残差×256 → [Stage3: 8-bit SAR] → 输出
                    ↓                              ↓                              ↓
                 code1 (MSB 8位)               code2 (中间8位)                code3 (LSB 8位)
                                        ↓
                            最终24位码 = code1<<16 | code2<<8 | code3

要求：

- 创建3个8-bit SARADC实例
- 使用Pipeline类串联，级间增益=256 (2^8)
- 理想Pipeline应达到~24-bit ENOB（使用65536采样点）
- 添加InterstageGainEvent模拟0.1%增益误差+0.5mV失调
- 对比理想与非理想Pipeline的ENOB损失

提示：使用`Pipeline([s1,s2,s3], gains=[256,256])`创建24-bit流水线。增益误差=1-1/opamp_gain。

    from quantiamagica import Pipeline, SARADC, InterstageGainEvent

    # ========== 创建3个8-bit SAR ADC ==========
    stage1 = SARADC(bits=8, vref=1.0, name="SAR-Stage1")
    stage2 = SARADC(bits=8, vref=1.0, name="SAR-Stage2")
    stage3 = SARADC(bits=8, vref=1.0, name="SAR-Stage3")

    # ========== 理想Pipeline (24-bit) ==========
    ideal_pipe = Pipeline(
        stages=[stage1, stage2, stage3],
        gains=[256.0, 256.0],  # 级间增益=2^8
        name="24-bit-Ideal"
    )
    ideal_pipe.sim(n_samples=65536, fs=1e6, fin=10e3)

    # ========== 带增益误差的Pipeline ==========
    s1_err = SARADC(bits=8, vref=1.0, name="SAR-Stage1")
    s2_err = SARADC(bits=8, vref=1.0, name="SAR-Stage2")
    s3_err = SARADC(bits=8, vref=1.0, name="SAR-Stage3")

    real_pipe = Pipeline(
        stages=[s1_err, s2_err, s3_err],
        gains=[256.0, 256.0],
        name="24-bit-GainError"
    )

    @real_pipe.on(InterstageGainEvent)
    def add_gain_error(event):
        """模拟有限运放增益导致的非理想效应"""
        opamp_gain = 1000  # 运放增益
        gain_error = 1 - 1/opamp_gain  # ~0.1%误差
        event.actual_gain = event.ideal_gain * gain_error
        event.offset = 0.5e-3       # 0.5mV失调
        event.noise_sigma = 0.1e-3  # 0.1mV噪声

    real_pipe.sim(n_samples=65536, fs=1e6, fin=10e3)

    # ========== 对比结果 ==========
    print("3×8-bit SAR → 24-bit Pipeline 分析")
    print("=" * 50)
    print(f"理想Pipeline:   ENOB={ideal_pipe.enob():.2f} bits, SNR={ideal_pipe.snr():.1f}dB")
    print(f"带增益误差:     ENOB={real_pipe.enob():.2f} bits, SNR={real_pipe.snr():.1f}dB")
    print(f"ENOB损失:       {ideal_pipe.enob() - real_pipe.enob():.2f} bits")

预期结果：理想Pipeline ENOB≈23.9 bits（接近24-bit理论值），带增益误差后ENOB会有所下降。

7 挑战 非理想效应插件类封装

目标：创建一个可复用的RealisticSARPlugin类，封装多种非理想效应，可一键attach到任意ADC。

要求：

- 封装电容失配(0.5%)、热噪声(500fF)、比较器失调(0.5mV)、比较器噪声(0.2mV)
- 插件类包含`attach(adc)`方法
- 对比使用插件前后的ENOB

提示：在`attach`方法内部定义事件处理函数，使用`self`访问插件参数。热噪声电压 = sqrt(kT/C)。

    from quantiamagica import (
        SARADC,
        SamplingEvent,
        CapacitorSwitchEvent,
        ComparatorEvent,
        EventPriority,
    )
    import numpy as np

    class RealisticSARPlugin:
        """可复用的SAR ADC非理想效应插件"""

        def __init__(self,
                     cap_mismatch_sigma=0.005,    # 0.5%电容失配
                     comparator_offset=0.5e-3,   # 0.5mV失调
                     comparator_noise=0.2e-3,    # 0.2mV噪声
                     sampling_cap_fF=500.0):     # 500fF采样电容
            self.cap_mismatch_sigma = cap_mismatch_sigma
            self.comparator_offset = comparator_offset
            self.comparator_noise = comparator_noise
            self.sampling_cap_fF = sampling_cap_fF
            self.cap_mismatches = None

        def attach(self, adc):
            """将所有非理想效应附加到ADC"""
            # 预生成固定的电容失配值
            self.cap_mismatches = 1 + np.random.normal(
                0, self.cap_mismatch_sigma, adc.bits
            )

            # 计算热噪声电压
            kT = 1.38e-23 * 300
            C = self.sampling_cap_fF * 1e-15
            self.thermal_noise_v = np.sqrt(kT / C)

            # 注册事件处理器
            @adc.on(SamplingEvent, priority=EventPriority.HIGH)
            def add_sampling_noise(event):
                event.voltage += np.random.normal(0, self.thermal_noise_v)

            @adc.on(CapacitorSwitchEvent)
            def add_cap_mismatch(event):
                event.capacitance_actual = (
                    event.capacitance * self.cap_mismatches[event.bit_index]
                )

            @adc.on(ComparatorEvent)
            def add_comparator_effects(event):
                event.offset = self.comparator_offset
                event.noise_sigma = self.comparator_noise

    # ========== 使用插件 ==========
    print("1. 理想ADC")
    ideal = SARADC(bits=12, vref=1.0)
    ideal.sim(n_samples=2048, fs=1e6, fin=10e3)
    print(f"   ENOB: {ideal.enob():.2f} bits")

    print("\n2. 使用插件的非理想ADC")
    real = SARADC(bits=12, vref=1.0)
    plugin = RealisticSARPlugin()
    plugin.attach(real)
    real.sim(n_samples=2048, fs=1e6, fin=10e3)
    print(f"   ENOB: {real.enob():.2f} bits")
    print(f"   热噪声: {plugin.thermal_noise_v*1e6:.2f} uV rms")

说明：插件模式可以复用，只需`plugin.attach(adc)`即可给任意ADC添加相同的非理想效应。

8 挑战 Sigma-Delta ADC

目标：创建2阶1位Sigma-Delta ADC，OSR=64，计算带内ENOB。

要求：

- 阶数：2
- 量化器位数：1位
- 过采样率：64
- 采样率：1MHz，信号频率：1kHz
- 打印ENOB

提示：使用 `SigmaDeltaADC(order=2, bits=1, osr=64)`。带内ENOB会比SAR ADC高很多。

    from quantiamagica import SigmaDeltaADC
    import numpy as np

    sd = SigmaDeltaADC(order=2, bits=1, osr=64)

    # 生成输入信号
    fs = 1e6
    fin = 1e3
    n_samples = 8192
    t = np.arange(n_samples) / fs
    signal = 0.5 + 0.4 * np.sin(2 * np.pi * fin * t)

    sd.sim(signal, fs=fs)
    print(f"Sigma-Delta ENOB: {sd.enob():.2f} bits")

说明：2阶SD ADC的带内ENOB可达10+bits，远高于1位量化器本身。

9 挑战 遗传算法优化SD系数

目标：使用SDCoeffOptimizer优化2阶SD ADC的系数，对比优化前后的ENOB。

要求：

- 阶数：2，量化位数：1
- OSR：64，采样率：1MHz
- 打印优化前后的ENOB和提升值

提示：使用 `SDCoeffOptimizer`，调用 `optimize()` 方法，结果的 `summary()` 方法会打印完整报告。

    from quantiamagica.optim import SDCoeffOptimizer

    # 创建优化器
    optimizer = SDCoeffOptimizer(
        order=2,
        bits=1,
        osr=64,
        fs=1e6
    )

    # 运行优化
    result = optimizer.optimize()

    # 打印结果
    print(result.summary())
    print(f"\n优化前ENOB: {result.baseline_enob:.2f} bits")
    print(f"优化后ENOB: {result.best_enob:.2f} bits")
    print(f"提升: +{result.improvement:.2f} bits")

10 压轴 五阶Sigma-Delta ADC系数优化 - 极致性能

目标：使用遗传算法优化5阶Sigma-Delta ADC的11个参数（5个积分器增益c1-c5、5个反馈系数a1-a5、1个输入幅度），实现16-20 bits的极致ENOB。

五阶CIFB结构说明：

    输入x → [积分器1] → [积分器2] → [积分器3] → [积分器4] → [积分器5] → [量化器] → 输出y
               ↑ c1        ↑ c2        ↑ c3        ↑ c4        ↑ c5
               └─a1·y──────┴─a2·y──────┴─a3·y──────┴─a4·y──────┴─a5·y (分布式反馈)

    状态更新方程：
      state[0] = state[0] + c1 * (x - a1 * y)           // 第1级
      state[i] = state[i] + c[i] * (state[i-1] - a[i] * y)  // 第2-5级
      quantizer_input = state[4]                        // 输出到量化器

要求：

- 定义11个Gene：c1-c5（积分器增益）、a1-a5（反馈系数）、amplitude（输入幅度）
- 使用QuantizerEvent实现5阶CIFB拓扑
- 编写evaluate函数评估ENOB，fitness函数处理异常
- 使用大种群(300)优化11维参数空间
- 对比默认系数与优化后的ENOB提升

参数范围参考：

参数 | 范围 | 说明
--- | --- | ---
c1-c5 | 0.01~0.6（递减） | 积分器增益，高阶需较小值保稳定
a1-a5 | 0.05~4.0（递减） | 反馈系数
amplitude | 0.03~0.2 | 高阶SD需小幅度避免过载

提示：5阶SD极易振荡，默认系数可能ENOB<0。使用`try-except`捕获异常返回惩罚值-1000。用`QuantizerEvent`的`event.input_signal`、`event.prev_output`、`event.quantizer_input`实现状态更新。

    from quantiamagica import SigmaDeltaADC, QuantizerEvent
    from quantiamagica.optim import GeneticOptimizer, Gene
    import numpy as np

    # ===================== 仿真参数 =====================
    OSR = 64
    BITS = 1
    FS = 1e6
    N_SAMPLES = OSR * 512
    FIN = 13 * FS / N_SAMPLES  # 相干采样

    # ===================== 定义11个基因 =====================
    genes = [
        # 积分器增益（递减范围）
        Gene('c1', 0.05, 0.6, 'float'),
        Gene('c2', 0.04, 0.5, 'float'),
        Gene('c3', 0.03, 0.4, 'float'),
        Gene('c4', 0.02, 0.3, 'float'),
        Gene('c5', 0.01, 0.2, 'float'),
        # 反馈系数
        Gene('a1', 0.5, 4.0, 'float'),
        Gene('a2', 0.3, 3.5, 'float'),
        Gene('a3', 0.2, 3.0, 'float'),
        Gene('a4', 0.1, 2.5, 'float'),
        Gene('a5', 0.05, 2.0, 'float'),
        # 输入幅度
        Gene('amplitude', 0.03, 0.2, 'float'),
    ]

    # ===================== 评估函数 =====================
    def evaluate_5th_order_sd(params):
        """创建并评估5阶SD ADC"""
        c = [params[f'c{i+1}'] for i in range(5)]
        a = [params[f'a{i+1}'] for i in range(5)]
        amplitude = params['amplitude']

        sd = SigmaDeltaADC(order=1, bits=BITS, osr=OSR)
        state = [0.0] * 5  # 5个积分器状态

        @sd.on(QuantizerEvent)
        def fifth_order_cifb(event):
            """5阶CIFB结构"""
            x = event.input_signal
            y = event.prev_output

            # 5阶级联积分器 + 分布式反馈
            state[0] = state[0] + c[0] * (x - a[0] * y)
            for i in range(1, 5):
                state[i] = state[i] + c[i] * (state[i-1] - a[i] * y)

            event.quantizer_input = state[4]  # 输出到量化器

        # 生成输入信号
        t = np.arange(N_SAMPLES) / FS
        signal = 0.5 + amplitude * np.sin(2 * np.pi * FIN * t)

        sd.sim(signal, fs=FS)
        sd._result.metadata['fin'] = FIN
        return sd.enob()

    # ===================== 适应度函数 =====================
    def fitness(params):
        try:
            enob = evaluate_5th_order_sd(params)
            if enob <= 0 or np.isnan(enob) or enob > 35:
                return -1000  # 振荡或异常，给惩罚
            return enob
        except:
            return -1000

    # ===================== 基准测试 =====================
    baseline_params = {
        'c1': 0.25, 'c2': 0.18, 'c3': 0.12, 'c4': 0.08, 'c5': 0.05,
        'a1': 2.0, 'a2': 1.5, 'a3': 1.0, 'a4': 0.6, 'a5': 0.3,
        'amplitude': 0.1
    }
    baseline_enob = evaluate_5th_order_sd(baseline_params)
    print(f"默认系数 ENOB: {baseline_enob:.2f} bits")

    # ===================== 运行优化 =====================
    print("开始优化11维参数空间...")
    optimizer = GeneticOptimizer(genes, fitness, maximize=True)
    result = optimizer.run(
        population_size=300,      # 大种群探索高维空间
        max_generations=500,
        mutation_rate=0.18,
        elite_ratio=0.10,
        seed=2024
    )

    # ===================== 输出结果 =====================
    best_enob = evaluate_5th_order_sd(result.best_params)
    print(f"\n优化后 ENOB: {best_enob:.2f} bits")
    print(f"提升: +{best_enob - baseline_enob:.2f} bits")

    print(f"\n优化后系数:")
    print(f"  积分器: c1={result.best_params['c1']:.4f}, c2={result.best_params['c2']:.4f}, "
          f"c3={result.best_params['c3']:.4f}, c4={result.best_params['c4']:.4f}, c5={result.best_params['c5']:.4f}")
    print(f"  反馈:   a1={result.best_params['a1']:.4f}, a2={result.best_params['a2']:.4f}, "
          f"a3={result.best_params['a3']:.4f}, a4={result.best_params['a4']:.4f}, a5={result.best_params['a5']:.4f}")
    print(f"  幅度:   amplitude={result.best_params['amplitude']:.4f}")

说明：5阶SD ADC有11个待优化参数，搜索空间巨大。默认系数往往直接振荡(ENOB<0)，遗传算法可以找到稳定且高性能的系数组合，达到16-20 bits的极致ENOB。