2、基础知识:掌握功耗、能量、功率、周期数、时钟频率、电压、电流等基本概念及其单位

TinyML 设备的功耗评估,本质上是对“电能在时间轴上的流动与消耗”进行量化分析。在 Cortex-M 微控制器上,我们通过测量或估算电流与电压,结合程序执行所消耗的时钟周期数,最终换算出能量与平均功耗。这一章将系统梳理这些物理量的定义、单位、换算关系,以及它们在嵌入式系统语境下的特殊含义。只有把这些基础概念彻底厘清,后续的周期数统计、功耗建模和电池寿命估算才有坚实的数学与物理基础。

电气域 时间/执行域 能量域 电压 U (V) 电流 I (A) 功率 P (W) P = U × I 周期数 N 频率 f (Hz) 时间 t (s) t = N / f 能量 E (J) E = P × t 平均功耗 P̄ = E / t 测量 换算 核心换算链路 E = U × I × (N / f) 能量 = 电压 × 电流 × 周期数 / 频率 P̄ = U × I × (N / f) / t 平均功耗 = 能量 / 总时间 E[mAh] = I × t 电池容量 = 电流 × 时间 注:实际测量中需区分动态电流、静态电流与唤醒电流,并考虑电压随负载的跌落

上图展示了 TinyML 功耗评估中三个核心域之间的逻辑关系:电气域(电压、电流、功率)、时间/执行域(周期数、频率、时间)以及能量域(能量、平均功耗)。在实际工程中,我们通常从测量电压和电流入手,结合程序运行时的周期数统计,最终换算出一次推理或一轮传感采集所消耗的能量。下面逐一展开这些概念。

2.1 核心概念定义与单位

2.1.1 电压、电流与功率

电压(U)是驱动电荷定向移动的“压力”,单位是伏特(V)。在 Cortex-M 系统中,典型工作电压为 1.8V、2.5V 或 3.3V。电压并非恒定不变——当芯片从睡眠模式切换到运行模式时,内部 LDO 或 DC-DC 的输出会有毫伏级的跌落,这在高精度功耗测量中不可忽略。

电流(I)是单位时间内通过导体横截面的电荷量,单位是安培(A)。在嵌入式系统中,电流范围跨度极大:睡眠模式可能只有 1µA,而射频发射或 Flash 写入时可达 10mA 甚至更高。TinyML 推理时,CPU 全速运行、内存频繁访问,电流通常处于毫安级。

功率(P)表示单位时间内做功的速率,单位是瓦特(W)。对于直流电路,瞬时功率为 P = U × I。但实际芯片的电流并非恒定,而是随时间变化的曲线,因此我们更关心平均功率和峰值功率。峰值功率决定了电源和去耦电容的设计,平均功率则决定了电池寿命。

物理量符号单位典型值范围(Cortex-M)测量/获取方式
电压UV(伏特)1.8V ~ 3.6V万用表、示波器、PMIC 寄存器
电流IA(安培)1µA ~ 100mA电流探头、串联采样电阻、专用功耗分析仪
功率PW(瓦特)3µW ~ 300mWP = U × I 计算
能量EJ(焦耳)µJ ~ mJ 级E = P × t 或积分
周期数Ncycle(周期)数千 ~ 数千万DWT->CYCCNT、调试器、周期计数器
时钟频率fHz(赫兹)1MHz ~ 400MHzRCC 寄存器、示波器测量
时间ts(秒)µs ~ s 级t = N / f 或定时器

2.1.2 周期数与时钟频率

周期数(N)是指 CPU 执行一段代码所消耗的时钟周期个数。Cortex-M 内核的每条指令都需要若干个时钟周期,例如简单的 ADD 指令可能需要 1 个周期,而除法指令可能需要 5-10 个周期。对于 TinyML 推理,一次卷积操作可能包含数百万次乘加运算,对应的周期数可能达到数百万甚至上千万。

时钟频率(f)是 CPU 每秒执行的时钟周期数,单位是 Hz。Cortex-M 系列常见频率从几十 MHz(如 STM32L0 的 32MHz)到几百 MHz(如 Cortex-M7 的 400MHz)。频率越高,单位时间内执行的指令越多,但功耗也越高——因为 CMOS 电路的动态功耗与频率成正比。

两者的关系通过时间桥接:执行时间 t = N / f。例如,一个推理任务需要 2,000,000 个周期,在 100MHz 下耗时 20ms;若将频率提升到 200MHz,则耗时缩短为 10ms,但功耗可能增加 60%-80%。这就是 TinyML 中经典的“频率-功耗-时间”三角权衡。

2.1.3 能量与功耗的区别

能量(E)是做功的总量,单位是焦耳(J)。在电池供电设备中,电池容量通常以毫安时(mAh)或瓦时(Wh)表示,本质上也是能量单位。一次推理消耗的能量决定了电池能执行多少次推理。

功耗(P)是能量消耗的速率,单位是瓦特(W)。功耗是瞬时的,而能量是累积的。一个关键误区是:低功耗不等于低能量。例如,一个设备以 10mW 功耗运行 1 秒消耗 10mJ;另一个设备以 100mW 功耗运行 0.05 秒消耗 5mJ——后者功耗更高但能量更少。TinyML 优化的目标通常是最小化单次任务的能量消耗,而非单纯降低功耗。

核心公式链:

功率 P = U × I(单位:W)
能量 E = P × t = U × I × (N / f)(单位:J)
平均功耗 P̄ = E / t_total(单位:W)
电池寿命 T = 电池容量(mAh) / 平均电流(mA)(单位:h)

2.2 判断方法与操作流程:如何测量与计算

2.2.1 周期数的获取方法

在 Cortex-M 上获取周期数有几种常用手段:

  1. DWT->CYCCNT 寄存器:Cortex-M3/M4/M7 内核自带数据观察点与跟踪单元(DWT),其中的 CYCCNT 是一个 32 位自由运行计数器,每个时钟周期加 1。使用时需先使能 DWT 和 CYCCNT,然后在代码段前后读取差值。
  2. 调试器周期计数:Keil、IAR 等 IDE 的调试器提供周期计数功能,但会因断点或调试干扰而失真,适合粗测。
  3. SysTick 定时器:SysTick 通常配置为 1ms 中断,但也可以读取当前计数值来估算周期数,精度较低。
// 使用 DWT->CYCCNT 测量周期数
volatile uint32_t *DWT_CYCCNT = (uint32_t *)0xE0001004;
volatile uint32_t *DWT_CTRL = (uint32_t *)0xE0001000;
volatile uint32_t *DEMCR = (uint32_t *)0xE000EDFC;

void enable_dwt_counter() {
    *DEMCR |= 0x01000000;    // 使能 TRCENA
    *DWT_CTRL |= 1;          // 使能 CYCCNT
}

uint32_t get_cycles() {
    return *DWT_CYCCNT;
}

// 使用示例
enable_dwt_counter();
uint32_t start = get_cycles();
// 执行 TinyML 推理函数
model_inference();
uint32_t end = get_cycles();
uint32_t cycles_used = end - start;  // 注意处理溢出

2.2.2 电流与电压的测量

测量电流的常用方法包括:

  • 串联采样电阻法:在电源路径中串联一个 10Ω 或 100Ω 的精密电阻,用示波器测量电阻两端电压,再除以电阻值得到电流。注意电阻压降会影响芯片实际供电电压。
  • 电流探头:使用霍尔效应或罗氏线圈电流探头,非侵入式测量,适合高频动态电流。
  • 功耗分析仪:如 Joulescope、Otii 等专用设备,可同步采集电压、电流和时间,直接输出能量数据,是 TinyML 功耗评估的首选工具。

电压测量相对简单,在芯片电源引脚附近用示波器探头测量即可。但要注意:测量点应尽量靠近芯片 VDD 引脚,避免 PCB 走线电阻造成的压降误差。

2.2.3 能量换算流程

完整的能量评估流程如下:

  1. 使能 DWT 周期计数器,记录推理开始和结束的周期数 N。
  2. 用功耗分析仪或示波器记录同一时间段内的电压 U(t) 和电流 I(t) 波形。
  3. 计算平均功率 P̄ = (1/T) ∫ U(t) × I(t) dt,或简化为 P̄ = U_avg × I_avg(若电压波动小)。
  4. 计算能量 E = P̄ × t,其中 t = N / f。
  5. 若需要评估电池寿命,将能量除以电池电压得到等效毫安时消耗。

2.3 案例拆解:一次 MNIST 推理的功耗实测

假设我们使用 STM32L476(Cortex-M4F,80MHz)运行一个量化后的 MNIST 手写数字识别模型,模型包含 2 个卷积层和 1 个全连接层,共约 12,000 个参数。

初始条件:

  • 供电电压:3.3V(由 LDO 提供,波动小于 50mV)
  • 时钟频率:80MHz
  • Flash 等待周期:2 个等待周期(80MHz 下需要)
  • 工作模式:正常运行,无 DMA 传输

测量过程:

  1. 使用 DWT->CYCCNT 测得推理总周期数 N = 1,850,000 cycles。
  2. 使用 Joulescope 功耗分析仪记录推理期间电流波形,平均电流 I_avg = 8.2mA,电压稳定在 3.28V(LDO 有轻微压降)。
  3. 计算执行时间 t = 1,850,000 / 80,000,000 = 23.125ms。
  4. 计算平均功率 P̄ = 3.28V × 8.2mA = 26.9mW。
  5. 计算能量 E = 26.9mW × 23.125ms = 0.622mJ。

结果分析:

若使用一颗 200mAh 的纽扣电池(电压 3V),理论上可执行推理次数为:200mAh × 3V = 600mWh = 2160J,2160J / 0.622mJ ≈ 3,470,000 次。但实际还要考虑睡眠电流、电池自放电和电压跌落,实际可用次数约为理论值的 60%-70%。

优化对比:若将频率降至 40MHz,周期数不变(仍为 1,850,000),但执行时间变为 46.25ms。由于 CMOS 动态功耗与频率成正比,电流可能降至 5.1mA,平均功率为 3.28V × 5.1mA = 16.7mW,能量为 16.7mW × 46.25ms = 0.772mJ。可见频率降低反而使能量增加了 24%——因为虽然功率降低了,但时间延长了更多。这说明在 TinyML 中,盲目降频并不一定节能,需要找到能量最优频率点。

经验提醒:对于计算密集型任务,通常在较高频率下执行更节能,因为可以更快回到低功耗睡眠状态。但频率过高会导致 Flash 等待周期增加,反而降低有效执行效率。建议在 2-3 个频率点下实测能量,选择最优值。

2.4 常见误区与总结复盘

误区一:将功耗与能量混为一谈。功耗是速率,能量是总量。一个设备功耗高但运行时间极短,可能比功耗低但运行时间长的设备更省电。TinyML 优化的核心指标是单次推理能量,而非峰值功耗。

误区二:忽略电压波动。许多工程师假设电压恒定为 3.3V,但实际在电流突变时(如 Flash 写入、射频发射),电源电压可能跌落 100mV 以上。这会导致功率计算误差达 3%-5%,在低电压(1.8V)系统中误差更大。

误区三:周期数统计不完整。DWT->CYCCNT 只统计 CPU 内核周期,不包含 Flash 预取等待、总线仲裁延迟和 DMA 占用周期。如果代码从 Flash 执行,实际消耗时间可能比 N/f 计算值多 10%-30%。更准确的做法是使用定时器测量真实墙钟时间,或使用 ETM 跟踪。

误区四:忽略静态功耗。在深度睡眠模式下,Cortex-M 的静态电流(漏电流)可能达到 µA 级。虽然单次推理能量中静态功耗占比很小,但在低占空比应用中(如 1 分钟推理一次),静态功耗可能占总能量的 80% 以上。

误区五:单位换算错误。mAh 与 J 的换算需要乘以电压:1mAh × 3.7V = 3.7mWh = 13.32J。很多工程师直接使用 mAh 计算能量,导致数量级错误。

场景推荐测量工具关键参数注意事项
快速估算万用表 + 示波器平均电流、电压无法捕捉瞬态电流尖峰
动态功耗分析Joulescope / Otii电流波形、能量积分采样率需 ≥ 100kS/s
周期精确测量DWT->CYCCNT周期数 N需处理 32 位溢出
电池寿命验证电池模拟器 + 功耗仪放电曲线、内阻需模拟真实负载模式