> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lagerdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 能量分析仪

> 在一段窗口内对能量和电荷做积分，或者取得统计量

测量被测设备在一段窗口内消耗了多少能量和电荷，或者取得这段窗口内电流/电压/功率的统计量。

## 句柄

```rust theme={null}
use lager::LagerBox;

let lager = LagerBox::from_env()?;
let energy = lager.energy_analyzer("energy1");
```

## 方法

| 方法              | 说明                      |
| --------------- | ----------------------- |
| `name()`        | 该句柄所指向的 Net 名称          |
| `read_energy()` | 在一段窗口内对能量（焦耳）和电荷（库仑）做积分 |
| `read_stats()`  | 一段窗口内电流、电压和功率的统计量       |

## 类型

### `EnergyReading`

```rust theme={null}
pub struct EnergyReading {
    pub energy_j: Option<f64>,    // joules
    pub charge_c: Option<f64>,    // coulombs
    pub duration_s: Option<f64>,  // the window actually used
}
```

### `EnergyStats` 和 `StatSummary`

```rust theme={null}
pub struct EnergyStats {
    pub current: Option<StatSummary>,  // amps
    pub voltage: Option<StatSummary>,  // volts
    pub power: Option<StatSummary>,    // watts
}

pub struct StatSummary {
    pub mean: Option<f64>,
    pub min: Option<f64>,
    pub max: Option<f64>,
    pub std: Option<f64>,
}
```

## 方法参考

### `read_energy(duration: f64) -> Result<EnergyReading>`

在 `duration` 秒内对能量和电荷做积分。

```rust theme={null}
let r = energy.read_energy(10.0)?;
println!("{:?} J, {:?} C", r.energy_j, r.charge_c);
```

### `read_stats(duration: f64) -> Result<EnergyStats>`

给出这段窗口内的统计量，而不是积分值。

```rust theme={null}
let s = energy.read_stats(5.0)?;
if let Some(c) = s.current {
    println!("mean {:?} A, peak {:?} A", c.mean, c.max);
}
```

## 示例

### 为一个占空比做能量预算

```rust theme={null}
let energy = lager.energy_analyzer("energy1");

// One full wake/transmit/sleep cycle.
let cycle = energy.read_energy(30.0)?;
let joules = cycle.energy_j.expect("analyzer reports energy");

// 2000 mAh at 3.7 V, in joules.
let battery_j = 2.0 * 3.7 * 3600.0;
let days = (battery_j / joules) * 30.0 / 86_400.0;
println!("projected battery life: {days:.1} days");
assert!(days > 180.0, "only {days:.1} days of battery life");
```

### 抓住平均值会掩盖掉的电流尖峰

```rust theme={null}
let s = energy.read_stats(10.0)?;
let c = s.current.expect("analyzer reports current");
let (mean, peak) = (c.mean.unwrap_or(0.0), c.max.unwrap_or(0.0));
assert!(peak < mean * 20.0, "peak {peak:.4} A is {:.0}x the mean", peak / mean);
```

## 受支持的硬件

| 仪器               | 备注                     |
| ---------------- | ---------------------- |
| Joulescope JS220 | 动态范围宽；适合休眠与发射之间差距很大的场景 |
| Nordic PPK2      | 源表模式和电流表模式             |

## 说明

* **Box 会把窗口钳位在 0.1 至 120 秒之间。** 超出该范围的请求会被拒绝，而不是被悄悄调整。
* 客户端会把它的 HTTP 预算放宽到 `max(30, duration + 30)` 秒。
* 响应中的 `duration_s` 是仪器实际使用的窗口，它可能与您请求的值略有出入。把积分值换算成平均值时，请除以它，而不是除以您的请求值。
* 能量的单位是焦耳，电荷的单位是库仑。如果您的预算是用别的单位写的，请在测试里换算成 mWh 或 mAh。
