QuantiaMagica

强大的ADC行为级事件驱动仿真器,像Minecraft Bukkit API一样简单易用

立即开始 Python入门

核心特性

[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

参数类型默认值说明
bitsint10分辨率位数
vreffloat1.0参考电压上限 (V)
vminfloat0.0参考电压下限 (V)
cap_unitfloat1.0单位电容 (fF)
namestr"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] → 合并输出码
参数类型默认值说明
stagesList[ADConverter]必填ADC实例列表 (SARADC/SigmaDeltaADC)
gainsList[float]自动(2^bits)级间增益列表,长度=len(stages)-1
vreffloat首级ADC的vref参考电压
namestr"Pipeline"Pipeline名称

属性:

属性类型说明
bitsint总位数 = sum(各级bits)
num_stagesint级数
lsbfloat最小分辨电压

方法:

方法说明
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 快速查看性能数字
其他参数
参数类型说明示例
savestr保存图像到文件save='my_adc.pdf'
showbool是否弹出图像窗口 (默认True)show=False
columnsint图像宽度: 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

转换开始时触发

属性类型可修改说明
timestampfloat仿真时间
sample_indexint当前采样索引
input_voltagefloat输入电压

SamplingEvent (可取消)

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

属性类型可修改说明
voltagefloat采样电压 (修改此值添加噪声)
sampling_capacitancefloat采样电容 (fF)
sample_indexint当前采样索引

CapacitorSwitchEvent (可取消)

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

属性类型可修改说明
bit_indexint当前位索引 (MSB=0)
capacitancefloat理想电容值
capacitance_actualfloat实际电容值
weightfloat位权重
charge_injectionfloat电荷注入 (V)
settling_errorfloat建立误差

ComparatorEvent (可取消)

比较器判决时触发

属性类型可修改说明
input_voltagefloat比较器输入
thresholdfloat判决阈值
offsetfloat比较器失调 (V)
noise_sigmafloat比较器噪声标准差 (V)
decisionint判决结果 (0或1)
metastablebool是否在亚稳态区

BitDecisionEvent (可取消)

每位决定后触发

属性类型可修改说明
bit_indexint位索引
bit_valueint位值 (可翻转)
dac_voltagefloat当前DAC电压

OutputCodeEvent

输出码就绪时触发

属性类型可修改说明
codeint输出码
input_voltagefloat原始输入电压

ConversionEndEvent

转换结束时触发

属性类型可修改说明
codeint最终输出码
conversion_timefloat转换耗时

Pipeline ADC 事件

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

StageEvent

进入新的流水线级时触发

属性类型可修改说明
stage_indexint级索引 (0-indexed)
stage_adcADConverter该级使用的子ADC实例
input_voltagefloat级输入电压
sample_indexint全局采样索引

ResidueEvent (可取消)

计算残差电压时触发

属性类型可修改说明
stage_indexint级索引
input_voltagefloat级输入电压
dac_voltagefloatDAC输出电压
residuefloat残差电压 (可注入误差)
ideal_residuefloat理想残差

InterstageGainEvent (可取消)

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

属性类型可修改说明
stage_indexint级索引
input_voltagefloat放大器输入 (残差电压)
ideal_gainfloat理想增益 (通常为2^stage_bits)
actual_gainfloat实际增益 (模拟有限增益)
offsetfloat放大器失调 (V)
noise_sigmafloat放大器噪声标准差 (V)
output_voltagefloat放大输出电压 (事件后计算)
bandwidthfloat放大器带宽 (Hz)
settling_errorfloat不完全建立误差

Sigma-Delta ADC

导入: from quantiamagica import SigmaDeltaADC, QuantizerEvent

SigmaDeltaADC 类

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

参数默认值说明
order1调制器阶数 (1或2)
bits1量化器位数
osr64过采样率
vref1.0参考电压

QuantizerEvent (可取消) - 唯一事件

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

属性类型可修改说明
input_signalfloat当前输入 x[n] ([-1,1])
prev_outputfloat前一输出 y[n-1]
integrator_statesList各级积分器状态(只读)
quantizer_inputfloat量化器输入(修改此值实现自定义拓扑)
outputfloat量化输出 ([-1,1])
output_codeint数字码
offsetfloat比较器偏移
noise_sigmafloat比较器噪声

使用示例

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

优先级说明
LOWEST0最先执行,可被后续处理器覆盖
LOW1低优先级
NORMAL2默认优先级
HIGH3高优先级
HIGHEST4最高优先级,最后修改机会
MONITOR5只读监控,不应修改事件

Signal 信号类

导入: from quantiamagica import Signalfrom 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.vrmsRMS电压
signal.mean平均值

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

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

Gene - 基因定义

导入: from quantiamagica.optim import Gene

参数类型说明
namestr参数名称
lowfloat下界
highfloat上界
dtypestr'float', 'int', 'choice', 'bool'
choiceslist离散选择列表 (仅dtype='choice'时)
log_scalebool是否使用对数尺度

GeneticOptimizer - 遗传算法优化器

导入: from quantiamagica.optim import GeneticOptimizer

参数类型说明
genesList[Gene]基因定义列表
fitness_fnCallable适应度函数 (接受dict返回float)
maximizebool是否最大化 (默认True)

run() 方法参数:

参数默认值说明
population_size50种群大小
max_generations200最大迭代代数(自动收敛通常不会到达)
slope_window5斜率计算窗口
slope_threshold0.001收敛斜率阈值
verboseTrue显示进度
seedNone随机种子

OptimizationResult - 优化结果

属性类型说明
best_paramsDict最佳参数
best_fitnessfloat最佳适应度
historyList[float]每代最佳适应度历史
generationsint实际迭代代数
convergedbool是否收敛

SDCoeffOptimizer - SD ADC系数优化器

导入: from quantiamagica.optim import SDCoeffOptimizer

参数默认值说明
order2调制器阶数
bits1量化器位数
osr64过采样率
fs1e6采样频率

注意: 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-c50.01~0.6(递减)积分器增益,高阶需较小值保稳定
a1-a50.05~4.0(递减)反馈系数
amplitude0.03~0.2高阶SD需小幅度避免过载
提示:5阶SD极易振荡,默认系数可能ENOB<0。使用try-except捕获异常返回惩罚值-1000。用QuantizerEventevent.input_signalevent.prev_outputevent.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。