RaspberryPiでクランプメータの作成

IT系

SCT-013-030(以降、CT(クランプ型電流センサ)と呼ぶ)、ADS1115(A/Dコンバータ、以降ADSと呼ぶ)、Raspberry Pi Zero WH(以降 RaspberryPiと呼ぶ)の組み合わせで実現可能です。

ただし、CTの出力は交流(AC)電流であり、ADS1115は直流(DC)電圧しか測定できないため、電流を電圧に変換し、かつマイナス電圧を避けるための信号調整回路が必要になります。

ここでは、回路構成と、実用的なPythonでのデータ取得方法、および検証用のi2cgetコマンドの使い方を解説します。


  1. 1. 接続構成と必要な部品
    1. 1.1 必要な部品
    2. 1.2 接続図と配線手順
      1. Step 1: Raspberry PiとADSのI2C接続
      2. Step 2: CTとADSの信号調整回路
  2. 2. i2cgetコマンドでの値の取り方(検証用途)
    1. 前提作業
    2. ADSのレジスタ確認
      1. 変換結果レジスタ(0x00)の読み出し例
  3. 3.ACの正弦波からRMSを得る方法
    1. 1.デジタル処理でRMSを計算
      1. Pythonによる推奨実装
      2. Pythonライブラリのインストール
      3. ノウハウ:RMS値の計算
      4. クランプメーター(RMS計算)Pythonコード
        1. ADS電流メーター(A0-仮想GND単端子入力時)
        2. ADS電流メーター(A0-A1差動入力時の場合)
        3. 誤差の具体的な特定(現在の換算係数 30.00が間違っている?)
        4. プログラムの修正(換算係数の調整)
        5. 実行結果(単端子の方)
        6. CONVERSION_FACTOR = 41.196 に修正後
      5. 回路図
        1. 単端子入力時の回路
        2. A0-A1の差動入力時の回路(今回は使わない)
        3. CTのピンジャックの配線
        4. SCT-013-030のAmazonの商品説明
      6. 接続の詳細
        1. 1. Raspberry Pi と ADS (I2C)
        2. 2. DCバイアス回路(基準電圧 1.65V の生成)
        3. 3. CT の接続
        4. 4. 信号結合(コンデンサ C1 の役割)
      7. なぜ Vbias = 1.65V(= Vcc/2)を入れるのか
      8. 「内部抵抗」必要か?
      9. RMS
      10. 外付け負担抵抗を付けるべきか(いつ必要か)
      11. ADS1115で何端子まで測定可能?
        1. 単端子動作で4端子利用の場合
        2. ② ADS1115 のサンプリングとその速度
        3. 結論
        4. 差動入力を使うとチャンネル数が減る
    2. 2.回路で全波整流+平滑してDC化する
      1. 1. 精密整流・平滑回路の回路図
        1. 使用する部品リスト
      2. 2. 回路の仕組みと接続方法
        1. 接続のポイント
        2. 回路の動作
      3. 3. ソフトウェア(Python)での計算方法
      4. 4. この回路のメリット
        1. LM358を用いた場合
  4. 結局何がしたいのか?
  5. 1.クランプ型電流センサの基本原理
    1. (1) 変圧器そのもの
    2. (2) 誘起電圧の発生メカニズム
    3. (3) 正弦波の場合
  6. 2. 抵抗(バーデン抵抗)で電圧として取り出す
    1. SCT-013-030 の場合
  7. 3. なぜ DC では使えないのか
    1. DC電流の場合
  8. 4. 出力波形の性質まとめ
  9. 5. なぜ「バイアス」が必要になるのか(ADC視点)
  10. 6. 一言まとめ
  11. 1. SCT-013-030 の出力特性(確認)
  12. 2. RMSをPythonで算出する基本方針(60Hz)
    1. 2.1 必要なサンプリング条件
    2. 2.2 PythonでのRMS計算例(概念)
  13. 3. ADS1115 のサンプリング性能
  14. 4. 構成の整理(非常に重要)
    1. 構成
    2. 総SCT数
  15. 5. 1センサあたりの測定時間
    1. RMS計算に必要なサンプル数(現実解)
    2. 実用的な設定
  16. 6. 全SCTを一巡するのにかかる時間
    1. 1 ADS1115 内
    2. 1 TCA9548A 内
    3. 全体(TCA × 8)
  17. 7. 結論(率直な評価)
    1. 取得間隔の現実値
    2. なぜ遅いのか
  18. 8. 改善案(重要)
    1. 案1:用途が「瞬時監視」でない場合
    2. 案2:高速化したい場合
    3. 案3:電圧検波型(RMS化をアナログで)
  19. 9. 最重要ポイントまとめ
  20. 1. I2Cは物理的に「1本のバス」
  21. 2. 「別アドレス=並列」ができない理由
    1. 2.1 SDAはオープンドレイン
    2. 2.2 クロック(SCL)は1系統
    3. 2.3 マスターは1トランザクションずつ
  22. 3. TCA9548Aが「並列」に見える理由
    1. 3.1 TCA9548Aは「バス切替器」
    2. 3.2 ADS1115側も並列動作しない
  23. 4. では「本当に並列」にするには?
    1. 4.1 真の並列条件
    2. 4.2 現実的な方法
      1. 方法1:複数マイコンを使う
      2. 方法2:SPI ADCに切り替える
      3. 方法3:電力量ICを使う
  24. 5. 本構成での最重要ポイント
  25. 6. 結論(端的に)

1. 接続構成と必要な部品

ADSとRaspberry PiのI2C接続に加え、CTの信号をADCで扱えるようにするための回路(信号調整回路)を組み込みます。(今回は単端子を想定)

1.1 必要な部品

部品名数量目的推奨値
ピンヘッドフォンジャック(メス)1個SCT-013-030がピンジャックのため
抵抗 (Bias Resistor)2個
1個
・AC信号をDC中心(1.65V)に持ち上げる
・ADSへのプルアップ
100kΩ
47kΩ
電解コンデンサ2個ノイズ除去1μF

1.2 接続図と配線手順

Step 1: Raspberry PiとADSのI2C接続

ADSはI2Cインターフェース経由でRaspberry Piに接続します。

ADS1115 PinRaspberry Pi Pin機能
VCC3.3V (Pin 1 or 17)電源
GNDGND (Pin 6, 9, 14など)接地
SCLSCL (Pin 5)I2C クロック
SDASDA (Pin 3)I2C データ
ADDRGNDI2Cアドレスを0x48に設定するための接続(未接続の場合はVCCに接続され0x49になる場合もありますが、今回はGND接続で0x48を確定させます)

Step 2: CTとADSの信号調整回路

CTの出力(AC信号)を、ADSの入力範囲(0V〜3.3V)に収まるように変換します。

今回のCTは 「30 A → ±1.0V」 を出すように作られています。

その “1.0 V @ 30 A” は 内部にあらかじめ 62Ωのburden 抵抗が入っています。

【信号調整回路の構成】

  1. DCバイアス: Raspberry Piの3.3V電源GNDの間に2つの10kΩ抵抗を直列に接続します。この抵抗の中点(接続点)の電圧は約1.65Vになり、これがAC信号の中心(バイアス電圧)になります。
  2. カップリング: DCバイアスの中点(1.65V)を**コンデンサ(10μFなど)**で接続し、ADSの入力ピンに繋ぎます。

ADSのA0ピンに入力される電圧:

1.65V ± 1V = 0.65V ~ 2.65V となり、ADSの測定範囲内(0~3.3V)に収まります。


2. i2cgetコマンドでの値の取り方(検証用途)

ADSは非常に設定項目が多く、単純なi2cgetコマンドは設定の書き込みが難しいため、実際の電流計測はコマンドだけでは困難ですが、I2C通信が機能しているかや、現在の変換レジスタの値を確認する用途には使えます。

前提作業

  1. I2Cの有効化: Raspberry Piの設定でI2Cを有効にします。
sudo raspi-config
  1. I2Cツールのインストール:
sudo apt update sudo apt install i2c-tools
  1. ADSの検出:Bash結果の表に48が表示されていれば、アドレス0x48でADSが認識されています。
i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

ADSのレジスタ確認

このADSには主に2つのレジスタがあります。

  • Conversion Register (変換結果レジスタ): アドレス 0x00
  • Config Register (設定レジスタ): アドレス 0x01

変換結果レジスタ(0x00)の読み出し例

ADSライブラリなどですでに設定・動作している前提で、現在の変換結果を読み出すには、ポインタレジスタを0x00に設定してから、2バイトを読み出します。

# i2cset [I2Cバス] [アドレス] [ポインタレジスタ] [値] [設定]
# i2cget [I2Cバス] [アドレス] [ポインタレジスタ] [読み出すバイト数]

# 1. 読み出し対象をConversion Register (0x00)に設定
sudo i2cset -y 1 0x48 0x00

# 2. 変換結果(2バイト)を読み出す
# (w)h: 16進数で2バイト(ワード)を読み出す
sudo i2cget -y 1 0x48 0x00 w

【注意点】

i2cgetで読み出される値は16進数のADC生データです。これをPythonコードで処理し、交流(AC)のRMS値を計算しないと、実際の電流値(A)は得られません。


3.ACの正弦波からRMSを得る方法

  1. デジタル処理(Pi側)でRMSを計算(推奨)
  2. 回路で全波整流+平滑してDC化する(簡単だが制度が落ちる)
  3. ピークホールド方式(非推奨:最大値を保持、ノイズで簡単に暴れる、実効値と一致しない)←検討しない

1.デジタル処理でRMSを計算

RMS(実効値)を計算する考え方は、前出の以下の式で求められます

Vrms=1ni=1nVi2V_{rms} = \sqrt{ \frac{1}{n} \sum_{i=1}^{n} V_i^2 }

Pythonによる推奨実装

実際のクランプメーターとして機能させるには、ADSを連続的にサンプリングし、測定されたAC波形のRMS(実効値)を計算する必要があります。Pythonライブラリを使用するのが最も簡単で確実です。

ここでは、Raspberry Piで広く使われる adafruit-circuitpython-ads1x15 ライブラリをのPythonコードで実装してみます。

Pythonライブラリのインストール

sudo apt install python3-pip
sudo pip3 install adafruit-blinka
sudo pip3 install adafruit-circuitpython-ads1x15

ノウハウ:RMS値の計算

電流トランスの測定では、交流信号のピークではなく、RMS(Root Mean Square: 実効値)を計算する必要があります。

  1. 一定時間(例:1秒間)連続で電圧をサンプリングする。
  2. 測定値からDCバイアス電圧(約1.65V)を引いて、純粋なAC成分を取り出す。
  3. AC成分を二乗し、平均を取り、平方根を計算する。
  4. RMS電圧を電流に換算する。

クランプメーター(RMS計算)Pythonコード

このスクリプトは、ADS1115から電圧を読み取り、RMS値を計算して、実際の電流値を表示します。

ADS電流メーター(A0-仮想GND単端子入力時)
#!/usr/bin/env python

import time
import math
import board
import busio
from adafruit_ads1x15.analog_in import AnalogIn
import adafruit_ads1x15

# --- 測定パラメータ設定 ---
# Raspberry Piの電源電圧(ADCの基準電圧)。
V_REF = 3.3

# ゲイン設定 (±4.096Vスケール)。測定したい最大電圧に合わせて調整します。
# CT(クランプ型電流センサ)出力の最大電圧は約1V RMS (約1.414V Peak)なので、ゲイン1が最適です。
GAIN = 1

# SCT-013-030の換算係数(A/V)。
# ユーザーの実測データに基づき、クランプメーターとの比較で校正した値を使用します。
# (クランプメーター 12.4 A / CT出力 0.301 V) = 約 41.196 A/V
CONVERSION_FACTOR = 41.196  # (A/V) - 校正済み

# RMS計算用設定: サンプリング時間(秒)。
SAMPLE_DURATION = 1.0

# I2Cの初期化
# I2C通信はSCL(クロック線)とSDA(データ線)を使用します。
try:
    i2c = busio.I2C(board.SCL, board.SDA)
except ValueError:
    print("エラー: I2Cバスの初期化に失敗しました。SCL/SDAピンの接続またはI2C設定を確認してください。")
    raise

# ADS1115の初期化 (I2Cアドレス 0x48, ゲイン設定)
# アドレスが異なる場合は (0x49 など) 変更してください。
ads = adafruit_ads1x15.ads1115.ADS1115(i2c, address=0x48, gain=GAIN)

# AnalogIn クラスを使用してチャネルA0(P0)を指定
# SCT-013-030の電圧出力端子(K)をADS1115のA0に接続し、もう一方の端子(L)をDCバイアス(V_REF/2)に接続している前提です。
try:
    chan = AnalogIn(ads, adafruit_ads1x15.P0)
except AttributeError:
    # ライブラリのバージョンによってはP0が使えない場合があるため、ピン番号 0 を試みます
    chan = AnalogIn(ads, 0)
    print("警告: adafruit_ads1x15.P0が見つかりませんでした。代わりにピン番号 0 を使用します。")

def calculate_current_rms(adc_input_channel):
    """
    ADS1115から一定時間データをサンプリングし、電流の実効値 (RMS) を計算する関数。
    """
    start_time = time.time()
    squared_sum_V = 0.0 # 電圧の二乗和を格納
    sample_count = 0
    
    # 信号調整回路の中心電圧 (DCバイアス: 3.3V / 2 = 1.65V)
    V_CENTER = V_REF / 2.0
    
    # 測定をSAMPLE_DURATION秒間継続
    while time.time() - start_time < SAMPLE_DURATION:
        # ADCから現在の電圧値を取得
        voltage = adc_input_channel.voltage
        
        # 1. DC成分(バイアス)を除去し、純粋なAC電圧V_ACを抽出
        V_AC = voltage - V_CENTER
        
        # 2. RMS計算のために、AC電圧の二乗値を合計
        squared_sum_V += V_AC ** 2
        sample_count += 1
        
    if sample_count == 0:
        # サンプルがゼロの場合は処理をスキップ
        return 0.0, 0.0

    # 3. AC電圧のRMS (実効値) を計算
    mean_squared_V = squared_sum_V / sample_count
    V_RMS = math.sqrt(mean_squared_V)
    
    # 4. 電流の実効値 (RMS) を計算 (I = V_RMS * CONVERSION_FACTOR)
    I_RMS = V_RMS * CONVERSION_FACTOR

    return I_RMS, V_RMS

print("ADS1115 AC電流測定プログラム(最終校正版)を開始します。")
print("---------------------------------------")

try:
    print(f"ADC基準電圧 (V_REF): {V_REF} V")
    print(f"DCバイアス中心電圧: {V_REF / 2.0:.3f} V")
    print(f"ゲイン設定: x{ads.gain}{4.096 / ads.gain}V スケール)")
    print(f"**使用する換算係数 (校正値): {CONVERSION_FACTOR:.3f} A/V**")
    print("---------------------------------------")

    while True:
        rms_current, rms_voltage = calculate_current_rms(chan)
        # RMS電流が非常に小さい場合はノイズとみなし、ゼロを表示します
        if rms_current < 0.1: 
            print(f"待機中... (電流: {0.000:.3f} A)")
        else:
            print(f"測定電流 (RMS): {rms_current:.3f} A | CT出力電圧 (RMS): {rms_voltage:.3f} V")
        time.sleep(1.0) # 測定インターバル

except RuntimeError as e:
    print(f"\n実行時エラーが発生しました: {e}")
    print("I2C接続、またはADS1115のアドレス設定 (0x48) を確認してください。")

except KeyboardInterrupt:
    print("\nプログラムを終了します。")

※CTのKとL端子のLを仮想のGND(1.65V)としてA0のみの単端子入力を想定しています

ADS電流メーター(A0-A1差動入力時の場合)
#!/usr/bin/env python

import time
import math
import board
import busio
from adafruit_ads1x15.analog_in import AnalogIn
import adafruit_ads1x15

# --- 設定(SCT-013-030の「30A -> 1V RMS」仕様を直接利用) ---
# Raspberry Piの電源電圧(ADCの基準電圧)。
V_REF = 3.3

# ゲイン設定 (±4.096Vスケール)
GAIN = 1

# !!! SCT-013-030が電圧出力型(内部に抵抗内蔵)の場合、
# !!! K端子をA0、L端子を1.65V DCバイアスに直接接続します。
# !!! 外部の120Ω抵抗は「接続しません」!!!

# 換算係数: 30Aのときに1.0Vが出力されるため、電流(A/V) = 30A / 1.0V = 30
CONVERSION_FACTOR = 30.0  # (A/V)

# RMS計算用設定
SAMPLE_DURATION = 1.0  # サンプリング時間(秒)

# I2Cの初期化
i2c = busio.I2C(board.SCL, board.A2A)

# ADS1115の初期化 (I2Cアドレス 0x48, ゲイン設定)
ads = adafruit_ads1x15.ads1115.ADS1115(i2c, address=0x48, gain=GAIN)

# AnalogIn クラスを使用してチャネルA0(P0)を指定
try:
    chan = AnalogIn(ads, adafruit_ads1x15.P0)
except AttributeError:
    chan = AnalogIn(ads, 0)
    print("警告: adafruit_ads1x15.P0が見つかりませんでした。代わりにピン番号 0 を使用します。")

def calculate_current_rms(adc_input_channel):
    """
    ADS1115から一定時間データをサンプリングし、電流の実効値 (RMS) を計算する。
    ADS1115が測定した電圧RMS値に、換算係数をかけて電流に変換します。
    """
    start_time = time.time()
    squared_sum_V = 0.0 # 電圧の二乗和を格納
    sample_count = 0
    
    # 信号調整回路の中心電圧 (DCバイアス)
    V_CENTER = V_REF / 2.0
    
    # 測定をSAMPLE_DURATION秒間継続
    while time.time() - start_time < SAMPLE_DURATION:
        # ADCから現在の電圧値を取得
        voltage = adc_input_channel.voltage
        
        # 1. DC成分(バイアス)を除去し、純粋なAC電圧V_ACを抽出
        V_AC = voltage - V_CENTER
        
        # 2. RMS計算のために、AC電圧の二乗値を合計
        squared_sum_V += V_AC ** 2
        sample_count += 1
        
    if sample_count == 0:
        return 0.0, 0.0

    # 3. AC電圧のRMS (実効値) を計算
    mean_squared_V = squared_sum_V / sample_count
    V_RMS = math.sqrt(mean_squared_V)
    
    # 4. 電流の実効値 (RMS) を計算 (I = V_RMS * CONVERSION_FACTOR)
    I_RMS = V_RMS * CONVERSION_FACTOR

    return I_RMS, V_RMS

print("ADS1115 AC電流測定プログラムを開始します。")
print("---------------------------------------")

try:
    print(f"ADCゲイン設定: x{ads.gain} (フルスケール ±{4.096 / ads.gain}V)")
    print(f"DCバイアス基準電圧 (V_REF/2): {V_REF / 2.0:.2f}V")
    print(f"**使用する換算係数: {CONVERSION_FACTOR} A/V (30A/1V仕様)**")
    print("---------------------------------------")

    while True:
        rms_current, rms_voltage = calculate_current_rms(chan)
        print(f"測定電流 (RMS): {rms_current:.3f} A | CT出力電圧 (RMS): {rms_voltage:.3f} V")
        time.sleep(1.0) # 測定インターバル

except RuntimeError as e:
    print(f"\n実行時エラーが発生しました: {e}")
    print("I2C接続、またはADS1115のアドレス設定 (0x48) を確認してください。")

except KeyboardInterrupt:
    print("\nプログラムを終了します。")

上記、単端子のプログラムで、ドライヤーの電流値を測定してみたところ、市販のクランプメータでは12.4A程度だったが、今回の回路では9.043Aとなっていました。後、モジュールのバージョンが低くて P0とかの指定が出来ませんでした。以下の箇所です。皆さんと環境が違うかもしれませんので両方動くようにかいてはありますが、P0の方は試せていませんのでご了承下さい。

try:
    chan = AnalogIn(ads, adafruit_ads1x15.P0)
except AttributeError:
    # ライブラリのバージョンによってはP0が使えない場合があるため、ピン番号 0 を試みます
    chan = AnalogIn(ads, 0)
誤差の具体的な特定(現在の換算係数 30.00が間違っている?)

現在のコードでは、換算係数 CONVERSION_FACTOR を 30.00A/V に固定していました。

換算係数 = 測定電流(A) / CT出力電圧(VRMS)

今回の測定結果から、この換算係数を再計算します。

項目測定値
クランプメーター(真の値)12.4A (中央値として採用)
CT出力電圧(コードの出力)0.301V (9.043A時の値)

正しい換算係数を Knew とすると、

Knew = 12.4A / 0.301V ≈ 41.196A/V

つまり、CTセンサーは、公称値の「1.0V で 30A」ではなく、「1.0V で約 41.2A が流れている」 状態に近い特性を持っています。

プログラムの修正(換算係数の調整)

上記で計算した新しい換算係数 41.196A/V をプログラムに適用することで、より正確な電流値を表示できるようになります。

CONVERSION_FACTOR = 41.196  # (A/V) - 校正済み

実行結果(単端子の方)
chmod +x ./ads1115.py
./ads1115.py 
警告: adafruit_ads1x15.P0が見つかりませんでした。代わりにピン番号 0 を使用します。
ADS1115 AC電流測定プログラムを開始します。
---------------------------------------
ADCゲイン設定: x1 (フルスケール ±4.096V)
DCバイアス基準電圧 (V_REF/2): 1.65V
**使用する換算係数: 30.0 A/V (30A/1V仕様)**
---------------------------------------
測定電流 (RMS): 0.144 A | CT出力電圧 (RMS): 0.005 V
測定電流 (RMS): 0.144 A | CT出力電圧 (RMS): 0.005 V
測定電流 (RMS): 8.875 A | CT出力電圧 (RMS): 0.296 V
測定電流 (RMS): 9.043 A | CT出力電圧 (RMS): 0.301 V
測定電流 (RMS): 8.963 A | CT出力電圧 (RMS): 0.299 V
測定電流 (RMS): 2.513 A | CT出力電圧 (RMS): 0.084 V
測定電流 (RMS): 0.144 A | CT出力電圧 (RMS): 0.005 V
測定電流 (RMS): 0.145 A | CT出力電圧 (RMS): 0.005 V
^C
プログラムを終了します。

実際クランプメータで測定すると、12.13Aだったのでずれが発生しているため、プログラム側か回路側で調整する必要がありますが、プログラム側で調整するのが簡単そうです。

CONVERSION_FACTOR = 41.196 に修正後
./ads1115.py
警告: adafruit_ads1x15.P0が見つかりませんでした。代わりにピン番号 0 を使用します。
ADS1115 AC電流測定プログラムを開始します。
---------------------------------------
ADCゲイン設定: x1 (フルスケール ±4.096V)
DCバイアス基準電圧 (V_REF/2): 1.65V
**使用する換算係数: 41.196 A/V (30A/1V仕様)**
---------------------------------------
測定電流 (RMS): 0.181 A | CT出力電圧 (RMS): 0.004 V
測定電流 (RMS): 0.184 A | CT出力電圧 (RMS): 0.004 V
測定電流 (RMS): 0.179 A | CT出力電圧 (RMS): 0.004 V
測定電流 (RMS): 10.333 A | CT出力電圧 (RMS): 0.251 V
測定電流 (RMS): 12.478 A | CT出力電圧 (RMS): 0.303 V
測定電流 (RMS): 12.389 A | CT出力電圧 (RMS): 0.301 V
測定電流 (RMS): 11.699 A | CT出力電圧 (RMS): 0.284 V
測定電流 (RMS): 0.184 A | CT出力電圧 (RMS): 0.004 V
測定電流 (RMS): 0.182 A | CT出力電圧 (RMS): 0.004 V
^C
プログラムを終了します。

回路図

この回路の肝は、CTの出力であるAC(交流)電流を、ADSが測定可能な0V〜3.3VのDC(直流)電圧範囲内のAC信号(中心1.65V)に変換することです。

単端子入力時の回路

A0-A1の差動入力時の回路(今回は使わない)

※ADDR(アドレス)はGNDにつないでアドレスを0x48に固定しておいてください。L1がCTのプルーブにあたります。

CTのピンジャックの配線

NCはNon-Connectという事で、KとLを用いて接続します。回路図には記載がありませんが、KをA0に、Lを1.65Vを作る中心点に接続します。

SCT-013-030のAmazonの商品説明

商品の紹介ページには以下のような接続イメージがありましたが、±1Vなので1.65Vの底上げをしてから使うので以下の図のままではありません。

※出典 Amazoneの商品ページ

接続の詳細

1. Raspberry Pi と ADS (I2C)
  • VCCGND:Raspberry Piの3.3Vもしくは外部電源の3.3VとGNDに接続。
  • SCL :Raspberry PiのSDAピン(PIN5)に接続。
  • SDA:Raspberry PiのSDAピン(PIN3)に接続。
  • ADDR:GNDに接続し、I2Cアドレスを0x48に設定。
2. DCバイアス回路(基準電圧 1.65V の生成)
  • R1 と R2 (各 100 kΩ) を直列に接続し、Raspberry Piの3.3V電源とGNDの間に接続します。
  • R1とR2の中点から、ADSの入力A0ピンに基準電圧 (1.65V) が供給されます。
3. CT の接続
  • CTの出力(2本の線)のうち、一方をA0へ接続
  • CTの出力のもう一方を3.3Vを分圧した1.65Vに接続(今回は単端子とするため)
4. 信号結合(コンデンサ C1 の役割)
  • C1 (1µF) は、DCバイアスの中点(R1/R2間)の間に直列に接続されます。
  • このコンデンサを経由することで、R1の電圧信号が、1.65VのDCバイアスに正確に重畳され、ADSのA0ピンには1.65V ± 1Vの電圧が入力されます。

これで、ADCは0V〜3.3Vの範囲内で、電流波形を正確にサンプリングできるようになります。

なぜ Vbias = 1.65V(= Vcc/2)を入れるのか

ADS(と Raspberry Pi の 3.3V 電源)では ADC の入力電圧は 0V 〜 VDD(=3.3V) に制限されます。
しかし CT の出力は交流で ±(例えば ±1V) の振幅を持つため、そのまま ADC に入れると負側(マイナス電圧)が出てしまい測れません。
そこで信号を直流的に 1.65V(VDD/2)でオフセット(バイアス)し、CT の ±振幅を 1.65V ± 1V の範囲(約0.65〜2.65V)に収めて安全に読み取ります。
単端子動作(AIN0-GND)、差動測定(AIN0 − AIN1)いずれにしても入力が 0〜3.3V に入っていることが前提なのでバイアスは必要。

「内部抵抗」必要か?

  • SCT-013-030 の一般的な仕様では 30 A → 約1.0 V(RMS) という仕様があり、この「1.0 V」を作るための内部抵抗は多くの製品で内蔵されています。この製品の内部抵抗仕様書に62 Ωと記載されています (図の R1 はその負担抵抗を表しています)。
  • 外付け抵抗が必要なタイプもあるので現物で K-L 間の抵抗を測って確認するのが良いかもしれません。

RMS

バイアスすることで実効値(RMS)は変わりますのでプログラムでは以下の式でRMS値を求める必要があります。

Vrms=1ni=1nVi2V_{rms} = \sqrt{ \frac{1}{n} \sum_{i=1}^{n} V_i^2 }

外付け負担抵抗を付けるべきか(いつ必要か)

  • 内部抵抗 がある場合:外付けは不要(入れると出力電圧が大きくなり ADS1115 の入力上限を超える恐れあり)。
  • 内部抵抗 が無い場合:目的の出力電圧に合わせて外付け抵抗を選ぶ。例えば「30 A → 1 V」を得たいなら、設計に使われる二次巻数 N を用いて Rb = V * N / Ip で計算します(CTのデータシートの Rb 相当値をご確認下さい)。

簡単実用法:CT のデータシートに「30A -> 1V」と書いてあれば外付け不要で、その仕様通りに扱えばよいと思います。

ADS1115で何端子まで測定可能?

ADSの最大SPSと全CTの巡回数からRMSを取得するにあたり間に合うかという事を考えてみたいと思います。

単端子動作で4端子利用の場合

ACのマイナス成分を持ち上げる事で、無電流の時に1.65Vを示し電流が流れると、1.65Vを中心に上下に波形が振れるようになります。

  • 1.65 V バイアス
  • バイアスを作る抵抗分圧
  • デカップリングコンデンサ

CT 1つにつき独立して用意する 必要があります。

② ADS1115 のサンプリングとその速度

SCT-013-030は30Aを1Vで表現するCT(クランプ型電流センサ)ですが、ACは正弦波なので1度だけ取得するだけでは期待する値(RMS)は得らません。以下、交流の周波数とサンプリングを最低10周期程度取得する場合に必要なSPS(Samples Per Second)

  • 50Hz → 20ms → 200SPS
  • 60Hz → 16.7ms → 167SPS

ADS1115 の最大サンプルレートは 860 SPS(サンプル/秒)ですので、ADS1115 で 4 チャンネルを使うと:

  • 860 SPS ÷ 4 チャンネル ≒ 215 SPS

 → 50/60Hz の電流波形を測るにはギリギリ(最低限)

結論

4チャネル同時測定は可能だが、
精度は少し落ちる(RMS の滑らかさ・ノイズ耐性が低下)

精度が必要ならA0/A1とA2/A3の差動入力にして、サンプル数を確保する必要がある。

差動入力を使うとチャンネル数が減る

もし差動モードで精度を上げるなら:

  • A0-A1 → 1つ
  • A2-A3 → 1つ

となり 2 チャネルまで になります。

CT(Current Transformer) 測定は差動のほうが理想ですが、厳しい精度が求められない場合は、単端子(シングルエンド)でも実用上問題ないかと思われます。CT数が2倍になると考えると単端子にしたいですよね!

測定方式使用可能 CT 数メリットデメリット
単端子方式最大4個CT数が多い1chあたりのサンプルレート低下
差動方式最大2個ノイズに強いCT数が減る

回路をそのままでプログラムでカバーする場合は上記の通り。

2.回路で全波整流+平滑してDC化する

回路側で平準化(DC化)してしまう方法ですが、ダイオードだけでは順方向電圧降下(0.6~0.7V)があるため、オペアンプをを組み合わせる必要があります。今回は実際に回路を作っては試しておりませんので多分こうなるという想定で記載していますので悪しからず…

回路は以下の通り、LM358もしくは、MCP6002などを用いて作成します。汎用オペアンプ LM358 を使用した、「精密絶対値回路(全波整流)」+「平滑回路(フィルター)」の詳細な構成をまとめました。

この回路を通すと、CTからの交流(AC)信号が、電流の大きさに比例した綺麗な一直線の直流(DC)電圧に変換されます。これにより、Raspberry Pi側では ads.read_adc(0) を時々実行するだけで、安定した値を取得できるようになります。


1. 精密整流・平滑回路の回路図

使用する部品リスト
  • IC: LM358 (1個) ※8ピンのICの中にオペアンプが2つ入っています
  • ダイオード: 1N4148 (2本) ※汎用的な小信号用スイッチングダイオード
  • 抵抗 (R1~R5): 全て 10kΩ (5本) ※精度が良いもの(1%品など)を使うと誤差が減ります
  • 平滑用抵抗 (R_smooth):100kΩ (1本)
  • 平滑用コンデンサ (C_smooth): 1μF ~ 10μF (1個) ※大きいほど値が安定しますが、反応はゆっくりになります
  • 電源: Raspberry Piの 5V (Pin 2) と GND (Pin 6)

2. 回路の仕組みと接続方法

接続のポイント
  1. 電源: LM358の 8番ピンに 5V4番ピンに GND を接続します。
    • 注: LM358は出力電圧が電源電圧より少し低くなる特性があるため、3.3VのADCに送る場合でも 5V で動作させるのが最適です。
  2. 入力: CTの片方の線を GND に、もう片方を回路の入力(R1の前)に接続します。
  3. 出力: 平滑回路を通った後の電圧を ADSの AIN0 に接続します。
回路の動作
  • 前半(精密整流): ダイオードの電圧降下(0.6V)をオペアンプが自動で補正し、マイナス側の波形をプラス側にひっくり返します。
  • 後半(平滑化): 100kΩ の抵抗とコンデンサで、細かく揺れる波形を「平均化」して直流にします。

3. ソフトウェア(Python)での計算方法

この回路から出てくる電圧は「平均値(Vin)」に近い直流です。一般的に家庭で使われる「実効値(Vrms)」に換算するには、プログラム内で以下の定数を掛けます。

×1.11実効値 \approx 出力電圧 \times 1.11

Pythonコードのイメージ:

# ADS1115で値を読む(単発読み出しでOK)
value = ads.read_adc(0, gain=1)
voltage = value * 0.000125 # GAIN=1の場合の1ビットあたりの電圧(4.096V/32768)

# 電流値に変換 (SCT-013-030の場合、1V = 30A)
# 1.11は平均値を実効値に直す係数
current = (voltage * 30.0) * 1.11

print(f"Current: {current:.2f} A")

4. この回路のメリット

  • CPU負荷が少ない: Raspberry Piが高速で計算し続ける必要がありません。
  • 安定性が抜群: 物理的に信号を均しているので、1秒に1回の測定でも値がビシッと安定します。
  • ADSの保護: LM358を 5V で動かしても、LM358の最大出力電圧は約 3.5 ~ 3.8V 程度で頭打ちになるため、誤って過大な電流が流れても 3.3V 系である ADS を壊すリスクが低いです。

LM358を用いた場合

結局何がしたいのか?

この回路を応用し、I2Cのマルチプレクサ(TCA9548A)を1つでADSを8個ぶら下げるとして8x4=32端子の測定が可能。マルチプレスサも8個までアドレスを持てるので、理論上1つのRaspberry Piで32x8=256点の電流を測定することが出来る。

通信機械室では部屋の縦横比にもよりますが、1架空列あたりラックの数が10架として、A系・B系の電源冗長をしているとすると20端子が張り出されます。30Ax2で足りないラックには更に追加で張り出されたりしますが、それを見越しても数架列をカバーできる。

理論上Raspberry Pi 1つに256÷2(A・B系)=128ラック。12架列毎に1つのRaspberry Piが必要という事になります。

ただ、プログラムでは1点チェックするのに60Hzで1つのCTのRMSの得るには200msかかるとして、ADSが4チャネルで800ms=0.8秒、マルチプレクサ1つあたり8個のADSなので0.8秒x8個=6.4秒、そのマルチプレクサが8個ぶら下がるので6.4秒x8個=51秒。256点の測定に50秒以上かかる計算になりますので、snmpで取得してすぐ回答するというわけにはいかないので、cronなどで取得してファイルに出力しておき、snmpはその値を返すようにするのがよさそうです。ただ取得できていない場合を考慮してその値を取得した時間が1分以上古い場合はErrorを返す様な仕組みも必要。

これが実現できれば、後付けでNFBというかMCCBで各ラックの電力使用量を測定し、snmpを使ってZabbixやPrometheus+Grafanaや、RRDtoolでグラフを書かせたり、監視したりと異常に気付き未然に対処=予防保全ができるようになります!

また使用状況の統計が取れれば次の投資タイミングの予測も立てることが出来るようになります。

常駐の人が居る局舎であれば人的リソースをつかって定期的に測定してもらえばよいですが、無人のそれも雪の積もる遠い場所など数百カ所を巡って測定して回るとなると大変です…

その費用を考えると今回かかる費用は初期投資としては大きいですが価値があると思うのですがどうでしょう?!

マルチプレクサの試験がうまく行ってないのでそれが成功したら本件プルーブ数を増やして試してみたいと思います→うまく行きました!RaspberryPiの3.3Vや5VからマルチプレクサやA/Dへ電源供給してたのですが出力が足りず電圧降下し既定の3Vに達せず2V程度までさがってしまっていたのでUSBから5VとAMS1117で3.3Vを得られるような回路を作って供給することで正常に動作させることが出来ました!! 最初抵抗分圧で5Vから3.3Vを作ってみたのですが3.3V側でミリアンペアオーダーで負荷がかかった瞬間電圧が崩れてしまって分圧の抵抗値を大きくすると流れる電流値が確保できなかったりで結局電圧レギュレータ(AMS1117)のお世話になる事にしました…

付録

1.クランプ型電流センサの基本原理

(1) 変圧器そのもの

クランプCTは構造的に

  • 一次側:被測定導体(1ターンのコイルと同等)
  • 二次側:CT内部コイル(多数ターン)

という 電流変圧器です。


(2) 誘起電圧の発生メカニズム

一次側に交流電流 Ip(t)I_p(t)Ip​(t) が流れると、

  • 磁束 Φ(t)\Phi(t)Φ(t) が時間変化
  • ファラデーの電磁誘導により
    二次側に起電力が発生

Vs(t)=NsdΦ(t)dtV_s(t) = -N_s \frac{d\Phi(t)}{dt}


(3) 正弦波の場合

一次電流がIp(t)=Imaxsin(ωt)I_p(t) = I_{max} \sin(\omega t)であれば、

  • 磁束も正弦波
  • 誘起電圧も 正弦波
  • 極性は時間とともに反転

👉 結果:出力はプラス/マイナス両方向に振れる交流電圧


2. 抵抗(バーデン抵抗)で電圧として取り出す

SCT-013-030 の場合

  • 内部に 62Ω のバーデン抵抗
  • 二次電流がその抵抗を流れることで電圧化

Vs(t)=Is(t)×62ΩV_s(t) = I_s(t) \times 62\Omega

  • 30A(一次) → 約 1Vrms(二次)

この 1Vrms

  • 瞬時値は ±1.414V に振れます。
Vpeak=Vrms×2=±1.414V_{peak}=V_{rms} \times \sqrt2 = \pm1.414

3. なぜ DC では使えないのか

DC電流の場合

  • 一次電流が一定
  • 磁束が変化しない
  • 誘起電圧ゼロ

👉 CTはDCを検出できない


4. 出力波形の性質まとめ

項目内容
出力電圧交流
極性プラス/マイナス
波形一次電流と同相の正弦波
DC成分0V
周波数電源周波数(50/60Hz)

5. なぜ「バイアス」が必要になるのか(ADC視点)

ADS1115やRaspberry Piは

  • 負電圧を測れない
  • 入力は 0〜3.3V

しかしCT出力は

-1V ~ +1V

👉 そのままでは半分が欠落

そのため、

  • 1.65Vを中心に持ち上げる(DCオフセット)
  • 交流を「ADCが読める形」に変換

という処理が必要になります。



6. 一言まとめ

クランプ型電流センサは
「交流電流の時間変化を
プラス/マイナスの交流電圧として出力するデバイス」

付録2

プログラムでRMSを取得するとして、256個のCTの値を取得にするのにどれくらいかかるのか?実用に耐えられる最低限の品質でより早くを目指して算出してみる。

1. SCT-013-030 の出力特性(確認)

SCT-013-030(30A / 1Vタイプ)は 電流出力ではなく電圧出力型CT です。

  • 一次側:AC電流(50/60Hz 正弦波)
  • 二次側:正弦波のAC電圧
  • 30A(実効値) → 1V(実効値)
  • 出力は ±方向に振れる交流電圧
  • 内部に 62Ωのバーデン抵抗 が既に内蔵

したがって、ADCで読むときは

  • 瞬時値は常に変動する
  • そのまま1点読むと「値が揺れる」のは正常
  • RMS(実効値)を計算しない限り電流値は安定しない

というのが本質です。


2. RMSをPythonで算出する基本方針(60Hz)

2.1 必要なサンプリング条件

60Hz正弦波を正しくRMS化するには:

  • 最低でも 1周期あたり 20点以上
  • 実用的には 50~100サンプル / 周期

60Hz → 周期は 16.67ms

例:

  • 60サンプル / 周期 → 約 1kSPS
  • 3周期分測定 → 約 50ms

2.2 PythonでのRMS計算例(概念)

import math

def rms(values):
    return math.sqrt(sum(v*v for v in values) / len(values))

ADC値(電圧)を配列で集めてRMSを取ります。

電流換算は:

I[A] = Vrms / 1.0 * 30.0

(30A → 1Vrms)


3. ADS1115 のサンプリング性能

ADS1115 の最大データレート:

  • 860 SPS(最大)
  • 実効的には I2C通信込みで 700~800 SPS程度

また:

  • 1変換 = 1チャネル
  • チャネル切替ごとに新たな変換が必要
  • 差動/単端は速度に影響なし

4. 構成の整理(非常に重要)

構成

  • Raspberry Pi
  • TCA9548A × 8
  • 各TCAに ADS1115 × 8
  • 各ADS1115に SCT × 4

総SCT数

8 × 8 × 4 = 256 センサ

5. 1センサあたりの測定時間

RMS計算に必要なサンプル数(現実解)

  • ADS1115:最大 860 SPS
  • 1チャネルで実際に取れる:約200 SPS(チャネル切替・I2C含む)

→ 60Hzに対して:

  • 3~4サンプル / 周期
  • 最低限 10周期(約167ms) 取らないと精度が厳しい

実用的な設定

  • 200ms / チャネル
  • RMS安定性重視

6. 全SCTを一巡するのにかかる時間

1 ADS1115 内

  • 4チャネル × 200ms = 800ms

1 TCA9548A 内

  • ADS1115 × 8
  • 800ms × 8 = 6.4秒

全体(TCA × 8)

  • 6.4秒 × 8 = 約51秒

7. 結論(率直な評価)

取得間隔の現実値

  • 全256センサを一巡:約50秒
  • 各センサの更新周期:約50秒

なぜ遅いのか

  • ADS1115は 低速・高精度ADC
  • 多重I2C+MUX構成は 並列化できない
  • RMS計算には 時間軸が必須

8. 改善案(重要)

案1:用途が「瞬時監視」でない場合

50秒更新でも問題なし
(電力・負荷監視用途なら十分)

案2:高速化したい場合

  • ADS1115をやめる
  • ESP32 + 内蔵ADC
  • 専用電力量IC(ADE7753 / ATM90E26)
  • SCTを減らし、CTを統合

案3:電圧検波型(RMS化をアナログで)

  • 整流+RC平均
  • ADCはDCのみ測定
  • 精度は落ちるが高速

9. 最重要ポイントまとめ

  • SCT出力が揺れるのは 正常
  • 安定させる方法は RMS化のみ
  • 多チャンネル構成では 更新周期が長くなる
  • 現構成での全取得周期は 約50秒が現実解

付録3

I2Cは「アドレスが別でも並列(パラレル)通信はできない」仕様です。TCA9548Aを多数使っていても、I2Cバス自体は常に1トランザクションずつの直列動作になります。

以下、理由をプロトコル仕様と今回の構成に即して整理します。


1. I2Cは物理的に「1本のバス」

I2Cの本質は以下です。

  • 配線:
    • SDA(データ)1本
    • SCL(クロック)1本
  • 同一時刻に1マスター → 1スレーブのみ通信可能
  • 他スレーブは「アドレス一致時のみ応答」

つまり:

アドレスが違う = 同時に話せる
ではありません。

すべての通信は時間多重(時分割)です。


2. 「別アドレス=並列」ができない理由

2.1 SDAはオープンドレイン

  • SDAは全デバイスで共有
  • 複数が同時に駆動すると衝突
  • よって 必ず1デバイスのみが発話

2.2 クロック(SCL)は1系統

  • クロックは共有
  • 異なるデバイスを同時にクロックできない
  • クロックストレッチもあり得る

2.3 マスターは1トランザクションずつ

  1. START
  2. アドレス送信
  3. ACK
  4. データ送受信
  5. STOP

この流れは 必ず排他的です。


3. TCA9548Aが「並列」に見える理由

ここが混乱しやすい点です。

3.1 TCA9548Aは「バス切替器」

  • 下流に 8 本の I2C バスを持つ
  • しかし:
    • 同時に有効化できるのは1ポートのみ(通常)
    • 物理的に接続されるバスは1本

※データシート上、複数ポートONも可能ですが、
Raspberry Pi側からは1本のSDA/SCLであり、
通信は依然として直列です。


3.2 ADS1115側も並列動作しない

ADS1115は:

  • 内部にADCは1つ
  • コンバージョンは 1チャネルずつ
  • チャネル切替ごとに新規変換

仮に:

  • 複数ADS1115に「同時に測定開始」指示
    内部変換は同時に進む

しかし:

  • 結果を読むのはI2Cで順番

ここが唯一の「擬似並列」です。


4. では「本当に並列」にするには?

4.1 真の並列条件

  • I2Cバスが物理的に別
  • マスターも別
  • クロックも別

4.2 現実的な方法

方法1:複数マイコンを使う

  • 各マイコンが独立したI2Cバスを管理
  • 上位へはUART / SPI / Ethernet

方法2:SPI ADCに切り替える

  • SPIはチップセレクトで疑似並列
  • クロック高速(数MHz)
  • RMS用途には有利

方法3:電力量ICを使う

  • RMS・積算を内部処理
  • MCUは「結果を読むだけ」

5. 本構成での最重要ポイント

項目可否
アドレス違いで同時通信不可
TCA9548Aで並列不可(切替のみ)
ADC内部変換の同時進行可能
結果取得の同時読出不可
実効的な高速化限定的

6. 結論(端的に)

  • I2Cはバス自体が直列通信
  • アドレス違いでも並列通信不可
  • TCA9548Aは「分岐」であって「並列化」ではない
  • 本構成でのボトルネックは
    I2C帯域+ADS1115の逐次変換

タイトルとURLをコピーしました