ESP32電力計 改造設計書
<!-- markdown-mode-on -->
**対象スケッチ:** ArduinoWattMeter_MQTT_v3.ino
**作成日:** 2026-04-18
**改造目的:** ESP32内蔵ADCのノイズ・非線形性に起因する電流計測誤差の解消
---
## 目次
1. [現状システムの問題点](#1-現状システムの問題点)
2. [A. ハード変更](#2-a-ハード変更)
3. [B. ソフト変更](#3-b-ソフト変更)
4. [変更前後の比較](#4-変更前後の比較)
---
## 1. 現状システムの問題点
### 1.1 ADC構成
| ピン | 用途 | 方式 |
|------|------|------|
| GPIO35 | 基準電圧(Vref) | 抵抗分圧シングルエンド |
| GPIO34 | 電圧測定 | AC変圧器→半波整流 |
| GPIO32 | 電流A測定 | CT→半波整流 |
| GPIO33 | 電流B測定 | CT→半波整流 |
| GPIO36 | 周波数測定 | AC変圧器→74HC14整形 |
| GPIO39 | 電源電圧監視 | 5V分圧 |
### 1.2 問題の所在
**電流測定の主要問題**
- ESP32内蔵ADCの実効分解能は12bit公称に対し、実測では10〜11bit相当
- CT二次側を半波整流してシングルエンド入力しているため、RMS計算に使えるサンプルが半サイクル分(50%)に制限される
- GPIO35のVrefをソフトウェアで毎サイクル読み取り差し引く処理において、Vrefの読み取りタイミングと各測定チャンネルの読み取りタイミングのずれがノイズとして加算される
- ADCチャンネル切り替え時のセトリング不足により、クロストークが発生する
**電圧測定の問題(相対的に小さい)**
- 上記と同様のVrefノイズの影響は受けるが、電圧は絶対値が大きいため信号対雑音比(SNR)は電流より有利
- v3スケッチのEMAフィルタおよびOUTPUT_INTERVAL拡張により、当面は許容範囲内と判断する
### 1.3 改造の範囲
| 対象 | 改造方針 |
|------|----------|
| 電流CH(A・B) | ADS1115差動入力に移行 |
| 電圧CH | ESP32 ADCを継続使用。Vref安定化のみ実施 |
| 周波数CH | 変更なし |
| 電源監視CH | 変更なし |
---
## 2. A. ハード変更
### 2.1 Vref安定化(電圧CH改善・即時実施可能)
**目的:** GPIO35のVref読み取りノイズを低減する
**方法:** 既存のVref分圧回路(R4=100kΩ、R5=47kΩ)の出力ノードに電解コンデンサを追加する
| 追加部品 | 値 | 接続箇所 |
|----------|----|----------|
| 電解コンデンサ | 47μF(耐圧6.3V以上) | GPIO35とGNDの間 |
**効果:** Vrefのインピーダンスが下がり、ADCサンプリング時のチャージ引き抜きによる電圧変動が抑制される。ソフト変更なしで即時適用可能。
**注意:** 既存のC1=470μF、C2=470μFはAC変圧器の整流平滑用であり、本追加コンデンサとは別の目的である。
---
### 2.2 ADS1115導入(電流CH改造・主要変更)
#### 2.2.1 ADS1115の仕様
| 項目 | 値 |
|------|----|
| 分解能 | 16bit(符号付き、実効15bit) |
| 入力モード | 差動(Differential)またはシングルエンド |
| PGA(プログラマブルゲイン) | ±6.144V / ±4.096V / ±2.048V / ±1.024V / ±0.512V / ±0.256V |
| 最大サンプリングレート | 860 SPS(連続変換モード) |
| インターフェース | I2C(最大400kHz) |
| 電源電圧 | 2.0〜5.5V |
#### 2.2.2 ゲイン(PGA)設定の根拠
現状のCTパラメータからCT二次側の出力電圧ピーク値を算出する。
- ピーク一次電流: $I_p = 14.1\,\text{A}$
- 変流比: $N = 1800$
- バーデン抵抗: $R_{burden} = 30\,\Omega$(回路図R8)
$$V_{peak} = \frac{I_p}{N} \times R_{burden} = \frac{14.1}{1800} \times 30 \approx 0.235\,\text{V}$$
この電圧振幅に対するゲイン選択:
| PGA設定 | FSR | LSBサイズ | $V_{peak}$に対するマージン |
|---------|-----|-----------|--------------------------|
| GAIN_ONE | ±4.096V | 125μV | 過大(分解能を無駄にする) |
| GAIN_TWO | ±2.048V | 62.5μV | 過大 |
| GAIN_FOUR | ±1.024V | 31.25μV | 過大 |
| **GAIN_EIGHT** | **±0.512V** | **15.6μV** | **適切(マージン約2.2倍)** |
| GAIN_SIXTEEN | ±0.256V | 7.8μV | クリップの恐れあり |
**採用: GAIN_EIGHT(±0.512V)**
LSBサイズ比較: ESP32 ADC(実効11bit, 3.3V)の約800μVに対し、ADS1115 GAIN_EIGHT では15.6μV。**約51倍の分解能向上**。
#### 2.2.3 接続方式
CT二次側を整流せず、バーデン抵抗の両端を直接ADS1115の差動入力に接続する。
```
CT二次側
│
├── ADS1115 AIN0 (+) ← CHAの場合
│
R8 (30Ω バーデン抵抗)
│
└── ADS1115 AIN1 (-) ← GNDに接続(片端接地の場合はGNDと共通でも可)
同様に、CHBは AIN2(+) / AIN3(-) に接続
```
**既存回路で不要になる部品:**
| 部品 | 現用途 | 変更後 |
|------|--------|--------|
| D5, D6 (1N5817) | 電流A 半波整流 | 削除 |
| R7 (1kΩ) | 電流A 整流後プルダウン | 削除 |
| D3, D4 (※電流B側) | 電流B 半波整流 | 削除 |
| R3 (1kΩ) | 電流B 整流後プルダウン | 削除 |
#### 2.2.4 I2C配線
| ADS1115ピン | 接続先 |
|------------|--------|
| VDD | 3.3V |
| GND | GND |
| SCL | ESP32 GPIO22 |
| SDA | ESP32 GPIO21 |
| ADDR | GND(I2Cアドレス: 0x48) |
| ALRT | 未接続 |
**I2Cプルアップ抵抗:** GPIO21/22に4.7kΩをVCC(3.3V)に対して追加する。ESP32の内蔵プルアップは弱すぎるため外付けを推奨。
---
## 3. B. ソフト変更
### 3.1 変更の基本方針
- v3スケッチ(EMAフィルタ・OUTPUT_INTERVAL=5秒・Vref外れ値クリップ)を**ベース**とする
- 電流読み取り部のみADS1115対応に変更する
- デュアルコア化・FreeRTOSタスク分離は**将来拡張**とし、今回は実施しない
- コアの変更量を最小化し、既存の動作実績のあるロジックを最大限流用する
### 3.2 追加ライブラリ
```
Adafruit ADS1X15 ライブラリ(Arduino Library Manager より導入)
依存: Adafruit BusIO
```
### 3.3 変更箇所一覧
| 変更箇所 | v3スケッチ | v4スケッチ |
|----------|-----------|-----------|
| グローバル変数 | `volatile float Irms_A_sum` 等 | ADS1115オブジェクト追加 |
| `setup()` | ADC初期化のみ | ADS1115の初期化・連続変換開始を追加 |
| `sampleData()` ISR | GPIO32/33をanalogRead | **電流読み取りを削除**(ISRからI2C不可のため) |
| 電流読み取り | ISR内 | `aggregateAndSend()`内で`getLastConversionResults()`呼び出し |
| `aggregateAndSend()` | ESP32 ADCの積算値からRMS計算 | ADS1115からの生値を用いたRMS計算に変更 |
| KCの定数 | `KC_A`, `KC_B` | ADS1115のLSBサイズを考慮した新定数に更新 |
### 3.4 ADS1115の動作モード
**連続変換モード(Continuous Conversion Mode)を採用する**
- ADS1115は設定後、自動的に変換を繰り返す
- `getLastConversionResults()` は最新の変換結果を即時返す(I2Cで約40μs)
- `aggregateAndSend()` の呼び出し毎(5秒間隔)に複数回読み取り、積算する方式とする
**制約事項:** ADS1115の最大860 SPSに対し、2チャンネルを順次読むと実効430 SPS相当になる。現状のESP32 ISR(1000 SPS)より低速だが、以下の観点から許容範囲と判断する。
- 60Hz商用電源に対して430 SPSは約7サンプル/サイクル。RMSとしての計算精度はサンプル数が十分確保されれば問題ない
- 電流チャンネルのSNR大幅改善(51倍の分解能向上)の効果が大きく、SPS低下を上回る
### 3.5 校正定数(KC)の再計算
ADS1115導入後、電流の校正定数はADS1115のLSBサイズを基準に再導出する。
既存の `KC_A` の構造:
$$KC_A = \sqrt{2} \times 2.2447 \times 13.823 \div 0.986$$
- $\sqrt{2}$: 正弦波ピーク/実効値変換
- $2.2447$: ESP32 ADC 1LSBあたりの実測電圧(mV)← **ADS1115導入後は不要**
- $13.823$: CTの変流比×バーデン抵抗の合成定数
- $0.986$: 個体差補正係数
ADS1115のLSBサイズ(GAIN_EIGHT): $15.625\,\mu\text{V} = 0.015625\,\text{mV}$
新しい `KC_A` の暫定式:
$$KC_{A,new} = \sqrt{2} \times 0.015625 \times \frac{N}{R_{burden}} \div k_{cal}$$
$$= 1.414 \times 0.015625 \times \frac{1800}{30} \div k_{cal}$$
ここで $k_{cal}$ は純抵抗負荷(PF=1.0既知)による実測校正で決定する。
**実装方法:** 先にスケッチを動かし、既知の電流値(クランプメータ等の実測値)との比率から $k_{cal}$ を実測決定する。既存スケッチと同じ手順。
### 3.6 デッドバンド処理の再設定
ADS1115導入後、電流0A時の出力値はESP32 ADCとは異なるノイズフロアになる。
- 既存: `Def_A = 0.285`, `Def_B = 0.303`(ESP32 ADCのノイズフロアに合わせた値)
- 変更後: ADS1115のノイズフロアは大幅に低下するため、**実測後に再設定**する
- 初期値は `Def_A = Def_B = 0.05` 程度を仮設定し、無負荷時の読み値を確認して調整する
### 3.7 ISRの変更内容
```cpp
// v3スケッチのsampleData()
void IRAM_ATTR sampleData(void* arg){
int r = analogRead(arefPin);
v_raw = analogRead(voltagePin) - r;
a_raw_A = analogRead(currentPin_A) - r; // ← 削除
a_raw_B = analogRead(currentPin_B) - r; // ← 削除
vrms_sum += (float)v_raw * v_raw;
Irms_A_sum += (float)a_raw_A * a_raw_A; // ← 削除
Irms_B_sum += (float)a_raw_B * a_raw_B; // ← 削除
watt_sum_A += (float)v_raw * a_raw_A; // ← 削除
watt_sum_B += (float)v_raw * a_raw_B; // ← 削除
sample_count++;
}
```
ISRは電圧サンプリングのみに縮小する。電流はI2C通信が必要なためISRから呼べない。
### 3.8 電力計算の方式変更
ADS1115導入後、電圧と電流のサンプリングは同期しない。このため瞬時電力 $P = v \cdot i$ の積算によるアクティブパワー計算は現状の方式では困難になる。
**対応方針:**
| 計算項目 | 方式 |
|----------|------|
| $V_{rms}$ | 現状維持(ESP32 ISRによる積算) |
| $I_{rms}$ | ADS1115からの積算(別ループ) |
| $Watt$(有効電力) | $Watt = V_{rms} \times I_{rms} \times PF_{measured}$ での近似、またはPF=1.0固定(初期実装) |
| $PF$(力率) | 将来的に位相差補正を実装して算出。初期実装ではPF=1.0固定 |
**理由:** 電圧と電流が同期サンプリングでない場合、$\sum v_i \cdot i_i$ の積算は意味をなさない。力率が問題になる負荷(大型モーター等)がなければ、$P \approx V_{rms} \times I_{rms}$ の近似で家庭用の電力管理としては実用的に十分である。
---
## 4. 変更前後の比較
| 項目 | v3(現状) | v4(改造後) |
|------|-----------|-------------|
| 電流分解能 | 実効約800μV(ESP32 ADC) | 15.6μV(ADS1115 GAIN_EIGHT) |
| 電流入力方式 | 半波整流シングルエンド | 全波差動(整流不要) |
| 電流サンプリング | 1000 SPS(ISR) | 最大430 SPS(2CH交互) |
| Vref依存 | あり(GPIO35を毎サイクル参照) | 電流CHは完全に排除 |
| アクティブパワー計算 | $\sum v_i \cdot i_i$(同期積算) | $V_{rms} \times I_{rms}$ 近似(初期実装) |
| 力率計算 | 実装済み | 初期実装ではPF=1.0固定、後日改良 |
| Vref安定化 | なし | GPIO35に47μF追加 |
| スケッチベース | v3 | v3ベース(変更最小化) |
---
## 付記: 将来拡張(今回は対象外)
以下は今回の改造では実施しないが、今後の検討候補として記録する。
- **デュアルコア化:** Core 0にWiFi/Blynk/MQTT/NVS、Core 1にサンプリング・計算を分離。周波数ジッタの根本解消に有効
- **電圧CHのADS1115化:** 電圧もADS1115のシングルエンド入力で読む。ただしSPS低下(3CH使用で約287 SPS)とのトレードオフを評価が必要
- **位相差補正:** 電圧・電流の同期サンプリングを実現した上で、既知負荷による $k_{cal}$ 実測と組み合わせてPFを正確に計算する
- **ADS1115割り込みモード:** ALRT/RDYピンを使い、変換完了をESP32の外部割り込みで受け取る方式。ポーリングより低レイテンシ
---
*以上*