ページ

2022/11/26

ラズパイとラズピコで分電盤センサを作成(14)

回路の実装図作成に取り掛かろうと思ったが、ここで一つ寄り道。
ADCへの入力前に交流電圧に対して直流バイアスをかける手段として、オペアンプを使う方法が出てきた。
アナデジ太郎の回路設計

というか、バイアスをかけたい場合、この方法の方がメジャー・・?

と思ったのだが、オペアンプは以前も勉強しかけて挫折したもの。
製品選定にあたって検討が必要なパラメータが多く、電子工作初心者からすると何を選んでいいのか分からない。
本当は勉強→オペアンプ購入→失敗 みたいなループを繰り返して理解していくものなのかもしれない。(なお、シャントレギュレータの中にもオペアンプが入っているらしい。知らずに使ってきたわけだ。)
まあ、今考えている方法で行けるのならば、当面オペアンプはスルーしたい。

ただ気になっているのは、今考えている方法はVrefをバイアス電圧としてを使っているが、測定信号がVrefの安定性に影響を与えないかということ。
影響を与えないのであれば、複数ch計測時も一つのvrefをバイアス電圧として使用できる。

そこでバイアス電圧について調べていて、このオペアンプにたどり着いたのであった。

このサイトも参考。完全に技術者向けのサイトで難しい。。
信号の A/D 変換を正しく行う 7 つのステップ(シグナル・コ ンディショニングのノイズ計 算)

もう一つ考えていることは測定値の変動。
特に、今回作った測定系で入力ゼロの時の換算交流電流が0.2A前後まで変動するのを解消できないかという探求。

  • Vref由来のバイアス電圧が変動している
  • ノイズが変動している

の2種類の原因を想定している。早速実験してみよう。


このグラフは線が水平であるほどバイアス電圧がぶれていないことを示す。バイアス電圧に対する、この結果からの考察。

  • Vref自体がぶれている可能性
  • Vrefの分圧から作るバイアス電圧がぶれている可能性(Vrefの分圧でバイアス電圧を作っているので、この要因だけ独立している可能性は低い)
  • どちらもぶれていないが、ADCの内部ノイズで計測がうまくいっていない可能性
  • アルコールチェッカーの時もこんな結果のぶれがあった
  • ADCのデジタル分解能4095のうち±3程度のぶれは、手持ちのテスターでは観測できない
  • 青と橙は、実配線上は異なるポイントをプロットしているが(ブレッドボードを使っているため)、結線図上は同一電圧であるはず。なのにこの差は何だろうか?ADC上はCh6と7を使用しているが、ADC内のノイズがch毎に異なるのだろうか?

そして、オシロスコープがここで活躍。
オシロで測ってみると、ADCを動作させている時だけ、バイアス点に10mV程度のノイズがのることが分かった。周期は500us程度で方形波。これは除去したいなー。ただ、上記グラフのノイズとの因果関係は不明。定量的にはあまり関係ないかも。

次にVBus(+5V)のラインに、パスコンを3種類つけたら、6時間放置でバイアス電圧の変動は安定していそうに見える。
計測開始直後のみ大きく変動しているのだが、原因不明。また、このグラフは20000サンプリング1プロットなので、個々のばらつきは平準化される。そのため、ここから言えるのは長期トレンドとしては一定になっている、という程度。


現在の回路と疑問点。多ch化するときのバイアス電圧はどうしたらよいのだろうか?


☆の部分をch4, 5, 6, 7につないで、ノイズのRMSを観測してみる。

どうも、回路に物理的に手を入れるとADCの出力値が大きく変わり、長時間稼働させると安定していくように思える。経験的なものだが。


1プロット40000サンプルのRMS、1日弱の観測。うーん。。


2日目も同じような計測。今度は2に収束している。。

今回は平均もとってみた。RMSと印象が変わる。あまりRMSを取る意味はないか?
ばらつきは少なく、あくまで平均が移動しているように見える

平日は機械も遊んでいるので、、もっと長期的なデータを取ってみよう。
二日間強の結果。またしても謎の変動が。絶対値としては小さいが。




2022/11/01

ラズパイとラズピコで分電盤センサを作成(13)

出来上がった交流電圧(RMS)測定プログラムはこんなかんじ。

import machine
import utime

from machine import Pin, SPI

led_onboard = machine.Pin(25, machine.Pin.OUT)

Vref = 2.495
Resistance = [100, 100, 100, 100, 100, 100, 100, 46.7]
sampling_count = 1000
CT_ratio = [2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000]
bias_voltage = 1144

#1MHz
spi = SPI(0, baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(2), mosi=Pin(3), miso=Pin(4))
cs = machine.Pin(5, machine.Pin.OUT)
cs.value(1)
ite = 0
CHNs = [0, 1, 2, 3, 4, 5, 6, 7]
write_buf = []
for i in CHNs:
    write_buf.append(bytearray([((0b1000+CHNs[i])>>2)+0b100,((0b1000+CHNs[i])&0b0011)<<6 -="" 0.0="" 1="" 8="" adc_rawdata_sum="" avg_current="[0.0," avg_voltage="[0.0," bias_voltage="" bit12_0="" chns:="" cs.value="" for="" i="" if="" in="" ite="" read_buf="" spi.write_readinto="" true:="" while="" write_buf=""> sampling_count - 1:
        ite = 0
        for i in CHNs:
            avg_voltage[i] = ((adc_rawdata_sum[i] / sampling_count) / 4095) * Vref
            avg_current[i] = (avg_voltage[i] / Resistance[i]) * CT_ratio[i]
            adc_rawdata_sum[i] = 0.0
        print(avg_current)
        led_onboard.toggle()

spi.deinit()

そして、実際に交流電圧を計測し、自作のプログラムから電圧測定値として出してみる。緊張の瞬間。その計測結果はこう。1プロットで1000サンプリングの平均値。

DMMでの指示値は6.1A。これに対して、大分差がある。また、ぶれも大きい。

絶対値の差については、サンプリング周期の長さ、CTの各種誤差、ADCの誤差の蓄積など、要因が色々重なっているかもしれないので、現時点での原因分析は難しい。入力値に対して出力値がリニアになっていれば、結果を補正するだけなので簡単なのだが。。

ぶれについてはやはりVrefのぶれか、ADCがノイズを拾っているということだろうか?
ちなみに電流を流していないときの0点はかなり落ち着いた値になっている。ということはADCに入るノイズは少ないのだろうか?
→DMMで計測した値もよくみると交流電流の時は結構ぶれていた。ということは、このぶれは精度として問題ないかも。

特性はこんなかんじ。


線形を見て、ん?となったが、線形になっていない2プロット分はいずれもカーボンヒーター300Wを使ったもの。
つまり、電圧のRMSを測るようにプログラムしたつもりだが、うまくいっていない(誤差が大きい)ということになる。

もしくは8ch分を一気に計測しているので、1ch当たりのサンプリング周期が長くなってしまっているのが原因か。交流電流を1chのみ測った場合は、元の交流電流波形にかなり追随できていたため。
そこでサンプリング周期を短くすることを試したが、非正弦波の部分の測定精度がよくなるということはなかった。

改めて、RMSの出し方についてよく見てみると、サイトに書いてある数式と自分の実行順序が少し違うことに気づく。
自分は、(Σ((電圧^2)60.5))(1/N)だった。
サイトに書いてあるのは、((Σ(電圧^2))(1/N))^0.5という感じ。
このやり方に書き直したところ、非正弦波部分の乖離が減った!ゼロではないが。
そして、全体の測定結果も真値に近づいた。

さてそろそろ、測定精度の追及は終わりにしようか。
0A測定時のフロアノイズは、DMMでも同じように発生していた。
DMM指示値で0.1A弱程度のノイズ。0.1A以下はすべて0Aとして処理してしまおうか。
また、バイアス自体、もしくはその計測値が変動する問題は、お手上げ状態。
しかしそれは±0.2A程度の変動なので、これも無視してしまってもよいかと思う。
各chの絶対値ではなく、ch間の相対的な割合を見る分には問題なさそうだ。



ラズパイとラズピコで分電盤センサを作成(12)

次は測定精度の追及の続きとして、シャントレギュレータの基準電圧の安定度を見てみたい。いろいろなサイトにシャントレギュレータは基準電圧源として使うと書かれているから、精度はよいのだろう。それを実際に目で見たかった。

が、よく分からなかった。
電圧が結構変動している。。パスコンを外して最小構成にしても、変動は減らない。

大量に電圧をサンプリングして分布を見ることで何か原因が掴めるかとも思うのだが、ラズピコはファイル出力ができず、ラズパイのように大量のデータをCSVに吐き出して分布図を作ることができない。
ラズピコの出力はUSB経由でラズパイ上のThonnyのコンソールに出力しているが、ここは何万データも出力する場所ではない。表示できる行数も制限があるようだ。
まあ、大量のデータを見るまでもなく、電圧変動が激しいように見える。0.1Vレベルの変動であるため、分電盤センサとしてはとりあえず見逃すか・・?
シャントレギュレータの特性よりも、自分が作ったプログラムや測定環境の方が疑わしいので。

次に、シャントレギュレータのことは置いておいて、ブレッドボード上の配線がごちゃごちゃになっていたのでこれをスリム化した。
そして、バイアス電圧付きのRMS電圧を出すプログラムでも作ろうかと思っていたのだが、ここで問題発生。
1000サンプル周期の長周期で見ているとADCからの取得電圧値がどんどん下がっていく。計測している電圧は直流で一定であるにもかかわらず。何だこりゃ?

四苦八苦してデバッグしたが、原因がわからない。
SPI通信の受信ビット列を見ても見事に数字が下がっていく。SPI通信の受信クロックがずれているのかとも思ったが、1ずつ下がっていくのでそれはなさそう。見るべきビットが1ずつずれていくなら、10進数としては1/2ずつになっていくはずであるが、10進数で律儀に1ずつ計測値が下がっている。。
ADCを触ってみた。特に発熱はしていない。

もしやVrefが下がっているのか?
→DMMで計測したが、下がっていなかった。
ちなみに、一度計測値が下がると、プログラムを一時停止/再実行しても下がったまま。回路構成を変えたりして電源ON/OfFすると値が戻る。これがヒントになっているか?

次に、プログラムにタイマを仕込んでデータの取得を間欠動作にしてみた。
→値は下がらない(様に見える)。ということは、時間依存ではなくSPI通信の回数依存で下がっていくということか?

ここで原因判明!
何気なくブレッドボードを眺めていたら、ピンが刺さるべき場所の1つ隣の穴に刺さっていた!まさかの配線ミス。。配線スペースを節約しようと圧縮配線したのが真因か。。これで3時間無駄にしてしまった。しかし、それでは、なぜ最初に電圧が計測できたのだろうか。ブレッドボードの隣同士の穴は電気的に結合しているのだろうか?今回間違って刺した穴は、完全に独立ではなく、2本のピンを同じように間違って刺していた。

不正解の回路図(43列目)


正解の回路図


もしかすると、コンデンサが計測値漸減の役割を果たしていたのだろうか。

とりあえず、治ってよかった。


2022/10/19

ラズパイとラズピコで分電盤センサを作成(11)

さて、前回直流電流のバイアスをかけたことで、なんとなく交流波形の全体像が見えたが、やはり測定器でも見てみたいので、Amazonで中華製格安オシロスコープを買った。早速測ってみる。

CT(KCT-6)に接続した抵抗に直接オシロをつなぐ。0点調整をしていないので、絶対値は適当。

カーボンヒーター300W(左)と600W(右)



うーんこれは。。やはり300Wの波形が歪んでいる。
つまり、ADCは正しい値を示していたのか!
驚き。なぜKCT-6のカーボンヒーター300Wの時だけこんなに歪むのか。

次に、CTをURDに変更して測った。
カーボンヒーター300W(左)と600W(右)

KCT-6と波形の歪み方が異なるが、極性が逆になっただけか?
すると、CTの種類の問題ではなく、もとのカーボンヒーターの問題だったことになる。
もう1回、バイアス付きADCでURDの出力を見てみる必要があるだろう。一見正しそうな負電圧側を見ていたのかも。
電流を求めるにあたって、最大値を採用で良いやと考えていたが、これはきちんと実効値を出すようなプログラムに変更した方がよいかもしれない。

他のCTでも試してみる。
CTKD-10、100Ω接続
カーボンヒーター300W(左)と600W(右)

KCT-10、100Ω接続
カーボンヒーター300W(左)と600W(右)

SCT-013 100A 50mA 、100Ω接続
カーボンヒーター300W(左)と600W(右)

それぞれわずかに概形が違うものの、波形の歪みは300Wカーボンヒーターの特例であることが分かった。

なぜ電化製品の入り口で測定している交流電流波形が歪むのか?
このサイトが参考になるやも

ただ、ここはこれ以上追いかけないことにしよう。


2022/09/25

ラズパイとラズピコで分電盤センサを作成⑩

では、肝心のADCの値との比較テスト。

ラズピコのADCによる測定プログラムを作成。測定対象を1chのみにして、まずは波の概形をとらえられるようにスリープ時間を入れない高頻度計測をする。もし十分なサンプリング間隔の短さであれば、頻度を落としても実効電圧をそれなりの精度で出せるようにしたい。

そして、やってみたところ、ADC出力3.73Aに対してDMM指示値2.68A、6.1Aに対して7.31Aと、非線形な応答を見せた。なぜだろう?

KCT-6のメーカーサイト(後記:今はないが)にある「Load resistance」のとおりCT接続50Ωも試したが、6.1Aの方で乖離が大きかった。メーカーサイトによると、少ない電流の方が誤差が大きいように見えるが。

いずれにせよ、大電流領域で誤差が大きいのは、今回分電盤センサの目的からいってよろしくない。対策は何だろうか・・もっと電流の種類を増やして、プロットの傾向をつかんでみよう。

CHを一つだけにして高頻度で測ってみる。CT接続の抵抗は50Ω。DMMの指示電圧は0.141V。ここで思い出したのだが、DMMの値は真の実効値(RMS)を示しているとのこと。

ADCで測ったのは瞬間値なので、一致しないのは当たり前であった。

真でなくとも、正弦波と仮定すれば、最大電圧を√2で割れば実効値になるはず。すると、0.139Vとなり、なかなかよいということになる。

カービンヒーター600W設定の計測結果。


いいね。マイナスの電圧はとれていないものの、正弦波がグラフとして出てくると、やっている感、できている感がある。

次に300Wの時。


なんだこりゃ???
最大値の部分が崩れているのがわかる。
つまり、大電流の域が乖離していたのではなく、小電流(というほどでもないが)の域が乖離していたことになる。
次は、なんでこんな波形になるかを考察せねば。。

カービンヒーターではなくはんだごてをつなぎ、DMM指示電圧0.011Vという小さい場合で試してみる。


あれ、また一見正しそうな波形になった。計算した実効値は0.00815V。うーん、まあさすがに値が小さすぎて誤差の範囲だろうか。

次にDMM指示電圧0.077Vの場合。(カーボンヒータ300W+はんだごて25W)

波形の乱れはちょっと解消?

他にも電熱系の家電をいろいろ測ってみたが、300W近辺だから崩れるというわけではなさそうだ。
そこで一つの考えが浮かんだ。カーボンヒーターは300Wの時はもともとそういう崩れた波形なのではないかと。
もとの電流がそのように変動しているのではないかと。
もしそうだとすると、これは、オシロスコープでないと調べられない。(そしてオシロスコープを持っていない)

次に、CTの異常を考えて、ほかのCT(KCT-6と一緒に買ったKCT-10)で試してみた。


正しい波形に見える。。?

次にADCの入力をch6とch7を入れ替えてみても波形の歪みは変わらず。
ということは、KCT-6とカーボンヒータ300Wの組み合わせでしか出ない現象ということなのか・・?

次にKCT-6の別個体を使ってch6とch7で計測したところ、別個体でも歪み発生。うーん。。
これ以上は悩んでも分からない。やはりオシロスコープで元の波形を直接観測したいかも。

ちなみに同じタイミングで購入していた日本製URD製のCT(CTL-6-S32-8F-CL)でも正常波形(のようなもの)を測定。

KCT-6に戻ってきて、CT接続抵抗を10Ωに変えても波形は変わらず歪む。(値の精度は下がる)
では接続抵抗1MΩではどうだ?


んー波形は変わったが、なんかこれはこれでおかしい波形。。600Wにしてもこの傾向は変わらず。

ちなみにURDのサイトには下記にようなありがたい特性資料がある。



抵抗が大きいと特性が悪くなるようなので、もともと1MΩは参考にしてはいけないということか。

次に試しにCTの±を逆に接続したら、あれ?治った?


しかしよく見ると電圧の最大値がおかしい。DMMの実効値の2倍以上を指している。波形は正常に見えるが、まだ直っていない。ブレッドボード上の接触状況が変わったのだろうか?
→CTの配線をまた逆にしてみたら波形の歪みが再現。これは原因究明の大きなカギになるのではないだろうか。

最終的にはオシロスコープを買おうと思っているのだが、その前に試してみたいこと。
交流信号に直流電圧のバイアスをかける方法を見つけた。
回路図をみると、なるほど~という感想。
コンデンサの容量は特に計算せず、手持ちのもの(容量不明)を入れて試してみた。
直流のバイアス電圧として、MCP3208のVrefを1/3に分圧したものを使用。


そして、結果がこれ。


なんか久々に達成した感がすごい。
これで交流電圧の全体像が見れるようになった!
極性を変えて計測しなくてもいいわけだ。

このグラフから3つのことがわかる。

  • 波形のゆがみは一方向のみ
  • 600Wの方が周期が遅れていくように見える
    →ADCが電圧を比較していく順序によるのだろうか?つまり電圧が大きいとVrefと一致するのが遅くなる?
    →振幅が大きいのだから、この説明では不足しているな
  • 交流電圧の直接測定は、バイアスかけた方が倍のサンプルがとれる

まあ、波形の歪みの謎はつかめないままなのだが、大分前進した感がある。

2022/09/24

ラズパイとラズピコで分電盤センサを作成⑨

アリエクスプレスで購入したCTであるKCT-6が10個届いた。
リンクを貼りたいのだが、HEYI社のホームページのKCT-10のリンクが見つからなかった。

日本製の小型CTというと、結構高い。これは安く手に入ったし、サイズ的にも分電盤に収まりそうな気がしている。(後記:この判断は浅はかであった)

早速CTを試してみるべく、CTで電線を挟み、その出力をデジタルマルチメータ(DMM HIOKI 3287)でとらえる回路を作った。シャントレギュレータTL431使用。

結果がこれ。横軸がCTを通過する交流電流、縦軸がDMMでとらえた交流電圧(RMS)である。
CTに接続する抵抗をいろいろ変えて測定した。

注:どこかで書いたかもしれないが、CT(変流器)はオープン接続にすると高電圧が発生しする可能性があり危険。必ず抵抗を接続しなければならない。逆に、変圧器はショート接続禁止。


うーん、このグラフが正解なはずだが、X軸のプロットが少ないためわかりにくい。。
そこで、プロットの仕方を変えた。


これならわかりやすいグラフ。
今回使用したCTでは、Vref2.495Vのシャントレギュレータで20Aまで測りたいなら、線形だとして6.1Aのとき0.75Vであってほしい。すると、CTに接続する抵抗は200~300Ωがよさそうだ。

2022/08/29

ラズパイとラズピコで分電盤センサを作成⑧

少し毛色が変わり、ラズパイ上で電流値をためこむDBを作ったとき、どのくらいのサイズになるかを検証した。

というわけでラズパイで分電盤センサ用DBの作成。

Mysql -u root -p
CREATE DATABASE log_current CHARACTER SET utf8;
Use log_current
CREATE TABLE current (
    Date datetime NOT NULL,
  Ch0 float, ch1 float, ******, ch11 float);

ラズピコ側でラズパイ側へ12ch分の測定電流を書き込むプログラムを作成し、実行。
ラズパイ側はシリアル通信で受け取り、それをMariaDBに読み込んでいくプログラムを作成し、実行。

60秒のサンプリング周期でどれくらのDBサイズになるか試してみる。

DBのサイズ確認SQL文は下記。

Select table_schema, sum(data_length) from information_schema.tables group by table_schema;

12時間後、720回のサンプリングで81920bytes=82kバイト。1日で160kB。1年で58.4MB。サンプリング周期1分で、十分実用的なサイズだな。サンプリング周期10秒でも、まあまあいける。

ラズパイとラズピコで分電盤センサを作成⑦

 次は、交流電圧を直流電圧に変換する勉強だな。

交流電流センサ・応用回路1

このサイト。いろいろやり方が乗っている。
これまで考えていた、全波整流+平滑の方式だと、ダイオードで電圧降下がおこり、測定したい電流レンジでは事実上使い物にならなそうだ。

交流電圧のまま、高サンプリングレートで測定して、ソフトウェア上で実効電圧を得るのがよさげに見える。

というわけで、高サンプリングレートで電圧を測定する実験。
MCP3208のCH0とCH2で疑似作動入力。CH2側にカーボンヒーターの電源を入れる。
その他プログラムの条件

  • コンソールへのprint文を使わず
  • ラズパイ上で1シーケンスごとにファイル読み込み→書き出しを行う
  • CTは-005を使用

結果がこれ。

まあ、欲しかった電圧のピーク値1.2Vはとれてそう。
この条件で、0.5msecくらいのサンプリングレートとなった。しかし、ばらつきが多い。
なんらかの処理負荷のせいか、0.8msecくらいのサンプリング周期になっているところもある。

最終的に直流電圧をどう決定するかにもよるが、サンプリングレートのばらつきは少ない方がいい。ラズパイではなくラズピコなら割り込みとかもなくなってもっと高速になるのだろうか。
その他MCP3208の入力条件を変えてみたところ、
  • CH0のみにすると0.3msecくらいのレート
  • CH0+2でシングルエンド入力では0.5msくらいで変わらず
  • CH0+2疑似差動でファイル入出力をシーケンスごとに行わないようにして、0.2~0.3ms台
となった。

これまで分かった情報をまとめると、以下のような分電盤センサになる。
  • ADCのVref=2.5Vとする
  • ADCの4096諧調で測定値が分解されると、1LSBあたり0.61mVで、±2LSBの変動があるとすると、±1.22mVの変動
  • 1CTあたりMAX20Aをとらえるとする(分電盤のブレーカー仕様)
  • CTにより、20Aは1/2000され、10mAになる
  • 10mAでVref2.5Vに到達させるためには、R=250Ωを使用
  • この条件の場合、1LSBは4.88mAを意味する。±2LSBの変動で、±10mAの変動があることになる
  • 10mAなら、積算しても誤差としては十分許せる(気がする)
  • この条件の場合、ADC(MCP3208)は差動入力なので、チップ一つで4CHしか測定できない。家の分電盤の断路器は12系統あるので、MCP3208が3個必要。
現時点で思いつく課題は以下。
  • 回路実装規模もそれなりになりそうだが、ラズパイではSPI通信は2デバイスしかつなげないので、MCP3208が3戸となった場合どう接続するか。
    →GPIO端子を消費すれば、3個程度は分別できそう。
  • 12CHで1サイクル1.5msくらいかかりそう。交流電源50Hzだと1周期20msなので、13サンプルとれるとして、電圧がマイナスの時はとれないので
    半分の6サンプルしか取れない。
    →これがかなり不安。6サンプルで最大電圧を測定できるか。実際に試してみないとわからないかも。ラズパイとラズピコでも結果が変わりそう
  • 実際にどうやってデータとして上げるのか。
    →この課題が出てきた。最終的にはラズピコ→WiFiモジュールで送ることを考えていたが、そんなことをやっていたら(ラズピコにWiFi通信処理をさせていたら)上の課題のサンプリング周期に影響が出そう。これもやってみるしかないか。。ラズピコ→ラズパイ(DBサーバ)へ有線接続というやりかたもありかも。。



ラズパイとラズピコで分電盤センサを作成⑥

ADCの精度の実験は一区切りつけ、分電盤センサの次の要素に目を向けてみる。

変流器、カレントトランス、CTと呼ばれるセンサだ。分電盤を流れる電流はそのままでは扱えない大きな電流なので、小さくする役割がある。小さくしたところで抵抗に通せば電圧に代わり、電圧をADCで計測するという流れ。

調べたところ、お手軽なCTは変流比2000:1。
Ali Expressで手に入れた、YHDC社製SCT-013シリーズ。CTはたくさん使うし、その割に単価が高め(電子工作の部品の中では)のため、安い方がよいということでこれにした。
SCT-013

この変流比で60Aを測る場合、2.495Vのシャントレギュレータ出力をVrefに入れたMCP3208で最大値60Aまで測れるようにするには、83.17Ωの抵抗が必要となる。

SCT-013は、ご丁寧に?ケーブルの先がステレオミニプラグになっている。ということは、それを受けるジャックが必要だ。秋月電子にステレオミニジャックのDIP化キットが売っていたので購入。

DIP化キットの基板の穴すべてにピンをはんだ付けしたら、ブレッドボード上では干渉して逆に使いづらくなってしまった。。

さて、このCTをお試ししてみるために、2芯の電源延長コードをカッターで二つに割いて、1芯ごとに分割した。割くときに失敗して金属の芯線が見えてしまった。ここには100Vがかかるので、要注意。絶縁テープでグルグル巻きにした。メガネコードのような切りやすいタイプにすればよかった。。

さて、この特製コードにマルチテスタのクランプを挟んだり、購入したCTをかませたりして、いろいろ測定してみる。

ちなみにCTは2種類購入している。YHDC SCT013-100とSCT013-005だ。恐らく、抵抗がビルトインされているバージョンとそうでないバージョンと思われる。


-100は抵抗の種類を変え、両端の交流電圧を測定。
-005は抵抗を入れず、ステレオミニプラグの交流電圧を測定。

結果は以下。

●HIOKIの結果が交流0.28Aのとき

HIOKI-005-100
AC0.28A0.06V0.268V@抵抗なし
AC0.28A0.051V@0.33kΩ
AC0.28A0.122V@1kΩ
AC0.28A0.184V@2kΩ
AC0.28A0.214V@3kΩ
AC0.28A0.234V@4.55kΩ
AC0.28A0.251V@9.57kΩ
AC6.04A1.20V3.84V@1.749kΩ
AC6.04A5.08V@3.21kΩ
AC6.04A5.53V@4.55kΩ
AC6.04A5.93V@9.57kΩ

抵抗を増やすほど電圧があがる。。。想定外。これはもしや、自分の学生時代意味不明だった電流源というやつか・・?

(追記)CTは電流源として振舞うようだ。そして、オープンにすると高電圧がかかって危ないので、オープンにしてはいけないらしい。逆に変圧器は電圧源として振舞い、ショートにしてはいけないらしい。同じようなものに見えるのに・・よくわからん

まあ、基礎データは取れた。ぱっと見で-005の方が抵抗が内蔵されており、初心者向けのように見える。が、抵抗で自在に調整できる-100の方がスタンダードなのだろう。

(追記)やはり-100は電流源扱いのようだ。

交流電流
22Ω(18.5Ω)0.044V6.03A
100Ω0.182V0.301V
150Ω(145.8Ω)0.261V0.432V
270Ω(261.7Ω)0.464V0.770V
CTが流れた電流を1/2000するとして、V=RIに当てはめるとよく数値があう。
ということは、-100を使った場合、
  • 2.495VのTL431をVrefとして使用
  • ブレーカーの20Aまで検知→CTには0.01A流れる
  • 249.5Ωが正解
ということになる。また、有効数字を増やしたければ、抵抗は1個ずつテスタで測った方がよさそうだ。

-005の方は結果をいじるには分圧が必要だが、そうすると抵抗の実装面積が増えるので、低電流が期待されるところに使おう。

ラズパイとラズピコで分電盤センサを作成⑤

 別のサイトでこんな記事を見つけた。

ラズパイでアナログ電圧を扱う (7) MCP3208のプログラム③

Raspberry Pi 4にてMCP3208を使用して測距センサーの値を得る

アナロググラウンドとデジタルグラウンドをショートさせる策は既にやっているので、Vddの入力側に0.1μFのコンデンサを入れるのと、ADCの疑似差動入力を試してみる。

ふむふむ。

さらに、測定対象を単3乾電池にしてやってみた。これは化学反応による電圧なので、ノイズがほぼないらしい。



疑似差動のほうが精度が悪いように見えるが、これは集計上の誤差と思われる。(0点を出すときにINT関数で桁落ちさせているため)
+2とかの差では、わずかに疑似差動がまさっている。しかし、シングルエンドも十分使える性能だな。シングルエンド入力は、ADCのピンが倍使えるので、メリットは十分にあるな。

同じく単3乾電池使用で、Vrefとしてシャントレギュレータではなくラズパイから出力される3.3V電源を使ってみた場合がこれ。


ここから学んだのは次の点。
  • ラズパイから出力される3.3V電圧は結構変動する ロングテール。Vrefとして使わないほうが良い。
  • 乾電池の電圧安定性は高い。但し、長期間の電圧低下・内部抵抗変化はどうなるか分からないので要注意。
  • ADCの疑似差動入力が効果を出すようなコモンモードノイズは、今回組んだ回路ではもともと少ない(今回1分程度の計測ではあるが)
ということなので、シングルエンド入力を使うことに決めた。

それにしてもこの一連の実験はなかなか勉強になった。分電盤アプリとは関係ないが今後も実験してみたい。他にも気になることもある。
  • MCP3208のDoutから出ているデジタル出力電圧は実際何Vなのか?
  • Doutを何Vまで下げると、ラズパイSPI入力はデジタル信号を読めなくなるのか?

ラズパイとラズピコで分電盤センサを作成④

ADCの測定精度を上げる。

まずはシャントレギュレータTL431とパスコンを使ってみる。定番らしい。
MCP3208のデータシートにも書いてある。

ラズパイでアナログ電圧を扱う (3) 使用するパーツ

現場で役立つ パスコンの容量値選定方法

パスコンの容量選びは難しそうだな。

面倒な計算や理解をするほど意識は高くないので、パスコンは0.1μF~10μFを試してみる。

→どうも、シャントレギュレータにパスコンはつけないほうが良いようだ。付けてもよいが、きちんと容量計算をしないと、発振?してしまうらしい。上のパスコンも3端子レギュレータに対して計算をしている。

シャントレギュレータの大元の抵抗rはどうするかだが、いろいろ調べてみて下記の計算か。

電圧リファレンスを使用した 設計のヒントとコツ

MCP3208のVrefに流れる電流は、データシート上2行書いてあってどちらを採用してよいかわからなかったが、Iref_min=0.001uA, Iref_max=150uAとした。Vddは4.5~5.5Vの範囲とした。グラウンド側に流れる電流はどうしたらよいか書いていなかった(読み取れなかった)ので、1mAとした。すると、Rは1.74kΩ~3kΩとなる。
→別のTL431データシートをみると、カソード電流1~100mAとあった。この範囲に入るように外部抵抗を調整する。

もともとブレッドボードに刺してあった抵抗4.7kΩでやってみた。それっぽく動いている。まずはこれで統計を取ってみよう。負荷に変動がなければ抵抗の範囲に収まっていなくてもいいのかもしれない。


シャントレギュレータ効果は表れたようだ。明らかに分散が減った。相変わらず最大値や最小値は結構幅があって、これの発生理由がよくわからない。本当にこのくらい電圧が変動しているのだろうか。シャントレギュレータにパスコンは要注意であるが、入り口と出口側にコンデンサをつけてみるか。

これが結果。1秒間隔で10分プロットしたので、サンプル数は少ないが、0.1μFはあまりよくないように見える。そして、パスコンを入れても入れなくても結果が変わらないようにも見える。
次は、抵抗4.7kΩを、当初予定の抵抗に変えて実験してみる。

外部抵抗2kΩでも問題なさそう。このとき外部抵抗に1.2mA流れてた。概ね設計内か。ちなみにデジタルマルチメータでははかれず、アナログ電流計を使用。
外部抵抗を0.968kΩにすると2.5mA。こちらの方が安パイだな。









ラズパイとラズピコで分電盤センサを作成③

 分電盤センサ作りに何が必要なのか、まだ全体像が見えていないない中、思いついたところから実験してみる。ADコンバータで計測する場合の測定値のばらつきについて実験。

ラズパイの3.3V出力をADコンバータ(ADC)MCP3208で測定した。MCP3208のVrefにはラズパイの5V出力を入力した。


 グラフ横軸は測定結果の平均値を0として、そこからの差分を示している。MCP3208の分解能は12bitなので4096段階の回答が返ってくる中で、平均値に対して-20から+64までぶれる結果となった。その差84というのは二進数にすると1010110、つまり7ビット分である。これがよくある測定結果なのか、何か問題があるのか分からないが、12ビットADCコンバータが実質5ビットの分解能だとすると少し寂しい。ADCの精度を高めるため、ネットで調べた対策を打ってみることとする。(ちなみに-12から+12で全データの95%をこえている。これだと5ビット落ち。)

 上記の結果は2万サンプル以上とったうち、冒頭の5300サンプル程度の結果である。なぜそうしたかというと、当初、全ての測定結果をプロットしたところ、平均値のトレンドが時間変化しているように見られたからだ。なぜ時間変化したのか?ラズパイ内のDDコンバータに温湿度依存特性がある(長く実行して温度が上がり、特性が変わった)のかもしれないし、その前段、家からの供給電源に変動があるのかもしれないし、誤差要因の積み重ねはやればやるほど難しい。

 とりあえず、今回は明らかに怪しい電子回路内のノイズ等に起因する誤差を減らす工夫をしてみることにする。これにより、この後の分電盤センサでも実測値とのかけ離れを減らすことが期待できるはずである。
 仮に、ADC7ビット精度で電流センサを作ったとすると、最大60A・127段階として、1段階で0.47Aとなる。もう少し細かく把握したいところ。実際は最大60Aとはしないだろうけども。



2022/05/08

ラズパイとラズピコで分電盤センサを作成②(SW最終形)

続いて、SWの最終形はこんなかんじ。

CT2DB.py(ラズパイ側常時起動プログラム)

import time
import datetime
import MySQLdb
from datetime import datetime as dt

import smtplib
import ssl
from email import encoders
from email import message
from email.mime import multipart
from email.mime import text

import serial

#ttyACM0はタイミングによって変わる可能性あり
ser = serial.Serial('/dev/ttyACM0', 115200)

filename = "ログファイル"

#メールを大量に送信しないようにするためのフラグ
sendmail = 0

from subprocess import getoutput

def _update():
    # ADCの電圧を取得する(USBより)
    str_serial = ""
    str_serial = ser.readline()
    while ser.in_waiting:
        str_serial = str_serial + ser.readline()

    #ラズピコからのテキストデータを整形する
    str_serial = str(str_serial).replace('b', '').replace('\\r\\n', '').replace('\'', '')
    nowdatastr = str(str_serial)
    str_list = str(str_serial).split(',')

    #データべースへの書き込み
    connector = MySQLdb.connect(host="localhost", db="log_current", user="root", passwd="パスワード", charset="utf8")
    cursor = connector.cursor()
    sql = u"insert into current values(now(), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (str_list[0] , str_list[1] , str_list[2] , str_list[3] , str_list[4] , str_list[5] , str_list[6] , str_list[7] , str_list[8]>    #print(sql)
    try:
        cursor.execute(sql)
    except MySQLdb.Error as e:
        print(e)
        nowtime = dt.now()
        nowtimestr = nowtime.strftime('%Y/%m/%d %H:%M:%S')
        fileobj = open(file, 'a', encoding='UTF-8')
        fileobj.write(nowtimestr)
        fileobj.write(e)
        fileobj.close()
    connector.commit()
    cursor.close()

    #画面表示用の整形 0.4A以下の場合はノイズと区別がつかないので( )をつける
    for i in range(10):
        if float(str_list[i]) < 0.4:
            str_list[i] = "(" + str_list[i][:5] + "A)"
        else:
            str_list[i] = str_list[i][:5] + "A"
    str_list[16] = str_list[16][:4]

    #標準出力へ表示
    nowtime = dt.now()
    nowtimestr = nowtime.strftime('%Y/%m/%d %H:%M:%S')
    print(nowtimestr);
    print("CH0:" + str_list[0])
    print("CH1:" + str_list[1])
    print("CH2:" + str_list[2])
    print("Ch3:" + str_list[3])
    print("CH4:" + str_list[4])
    print("CH5:" + str_list[5])
    print("CH6:" + str_list[6])
    print("CH7:" + str_list[7])
    print("CH8:" + str_list[8])
    print("CH9:" + str_list[9])
    print("気温" + str_list[16] + "℃")
    print(" ")

    #ログファイルに現在時刻を書き込む プロセスの稼働監視用
    try:
        file = open(filename, 'w')
        lasttime = file.write(str(time.time()))
    except Exception as e:
        print(e)
    finally:
        file.close()

    #気温センサが70度以上を示した場合、メール送信
    if float(str_list[16]) > 70.0:
        sendAlertMail(1, str_list[16], '')

#メール送信用メソッド
def sendAlertMail(reason, temperature, errorbody):
    global sendmail

    #メール送信は条件を満たしたとき1回のみ行う
    if sendmail == 0:
        smtp_server_host = '送信メールサーバ'
        smtp_server_port = 送信メールサーバのポート番号

        account = 'アカウント名'
        password = 'パスワード'
        from_email = 'メールアドレス'

	msg = multipart.MIMEMultipart()
        msg["Subject"] = "ラズピコ:通報メール"
        msg["To"] = "メールアドレス"
        msg["From"] = "メールアドレス"
        if reason == 0:
            msgstr = "ラズピコが停止しました" + str(temperature) + "℃ " + errorbody
        elif reason == 1:
            msgstr = "高温です " + str(temperature) + "℃ " + errorbody
        elif reason == 999:
            msgstr = "正常です " + str(temperature) + "℃ " + errorbody
        else:
            msgstr = "不明な事象が起こっています " + str(temperature) + "℃ " + errorbody
        msg.attach(text.MIMEText(msgstr, 'plain', 'utf-8'))

        server = smtplib.SMTP(smtp_server_host, smtp_server_port)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(account, password)
        server.send_message(msg)
        server.close()
        sendmail = 1
        print("!!Send Mail!!")

def main():

    while True:
        _update()

if __name__ == '__main__':
    main()

CT_mesurement.py(ラズピコ内のプログラム)

※一部HTML表示が崩れるため、全角文字を使っている部分あり

import machine
import utime

from machine import Pin, SPI

#動作している間はオンボードLEDを点滅させる
led_onboard = machine.Pin(25, machine.Pin.OUT)

#ラズピコ内蔵の温度センサを利用
sensor_temp = machine.ADC(4)
conversation_factor = 3.3 / (65535)

#CSピンを使うことで、1つのSPIバスで2つのADCを制御
cs1 = machine.Pin(5, machine.Pin.OUT)
cs2 = machine.Pin(14, machine.Pin.OUT)
cs1.value(1)
cs2.value(1)

#SPIの初期化
spi = SPI(0, baudrate=300000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(2), mosi=Pin(3), miso=Pin(4))

ite1 = 0
ite2 = 0

Vref = 2.447 #TL431の基準電圧(テスタ測定値)
Resistance = [42.2, 41.8, 50.5, 41.9, 41.9, 42.1, 42.0, 41.9, 50.8, 43.2, 43.8, 50.2, 50, 50, 50, 50] #各chの抵抗値(テスタ測定値)
sampling_count = 10000 #RMSをとるサンプリング数
moving_avg = 3 #移動平均区間
CT_ratio = [1866.662, 1792.035, 2238.42, 1870.499, 1865.004, 1849.13, 1781.08, 1849.199, 2231.249, 1842.651, 2000, 2000, 2000, 2000, 2000, 2000] #chごとの計測結果の補正
bias_voltage_bit10 = [445.5, 445.3, 445.8, 445.5, 445.7, 445.0, 445.1, 444.9, 445.5, 446.9, 445.9, 446.0, 0, 0, 0, 0] #各chのバイアス電圧の初期値
prev_bias_voltage_bit10 = []

CHNs = [0, 1, 2, 3, 4, 5, 6, 7]

#10bit ADC MCP3008の場合
read_buf = bytearray(3)
write_buf_mcp3008 = []
for i in CHNs:
    write_buf_mcp3008.append(bytearray([0b00000001,
    	(0b00001000+CHNs[i]) << 4,
        0b00000000]))

for i in range(16):
    prev_bias_voltage_bit10.append([])
    for j in range(moving_avg):
        prev_bias_voltage_bit10[i].append(445)

adc_rawdata_sum = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
avg_voltage = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
avg_current = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

bit10_sum = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

while True: 
    for i in CHNs:
        #ch0~7に対する処理
        cs1.value(0)
        spi.write_readinto(write_buf_mcp3008[i], read_buf)
        cs1.value(1)
        bit10_0 = ((read_buf[1] アンド 0b00000011) << 8) + read_buf[2]
        adc_rawdata_sum[i] += ((((bit10_0 - bias_voltage_bit10[i])/1023)*Vref)**2) #ADCが読み取った値を瞬時電圧に変換し、2乗したものを加算
        bit10_sum[i] += bit10_0
        
        #ch8~15に対する処理
        cs2.value(0)
        spi.write_readinto(write_buf_mcp3008[i], read_buf)
        cs2.value(1)
        bit10_0 = ((read_buf[1] アンド 0b00000011) << 8) + read_buf[2]
        adc_rawdata_sum[i+8] += ((((bit10_0 - bias_voltage_bit10[i+8])/1023)*Vref)**2)
        bit10_sum[i+8] += bit10_0        
    
    ite1 = ite1 + 1
    
    if ite1 > sampling_count - 1:
        for i in CHNs:
            #ch0~7に対する処理
            avg_voltage[i] = (adc_rawdata_sum[i] / sampling_count) ** 0.5 #瞬時電圧の2乗の積算値から平均電圧を計算し、さらに平方根を計算(RMS)
            avg_current[i] = (avg_voltage[i] / Resistance[i]) * CT_ratio[i] #電圧RMSから電流RMSを計算
            adc_rawdata_sum[i] = 0
            #バイアス電圧の移動平均処理
            for j in range(1,moving_avg):
                prev_bias_voltage_bit10[i][j-1] = prev_bias_voltage_bit10[i][j]
            prev_bias_voltage_bit10[i][moving_avg-1] = bit10_sum[i] / sampling_count
            bias_voltage_bit10[i] = sum(prev_bias_voltage_bit10[i]) / len(prev_bias_voltage_bit10[i])
            bit10_sum[i] = 0
            
            #ch8~15に対する処理
            avg_voltage[i+8] = (adc_rawdata_sum[i+8] / sampling_count) ** 0.5
            avg_current[i+8] = (avg_voltage[i+8] / Resistance[i+8]) * CT_ratio[i+8]
            adc_rawdata_sum[i+8] = 0
            for j in range(1,moving_avg):
                prev_bias_voltage_bit10[i+8][j-1] = prev_bias_voltage_bit10[i+8][j]
            prev_bias_voltage_bit10[i+8][moving_avg-1] = bit10_sum[i+8] / sampling_count
            bias_voltage_bit10[i+8] = sum(prev_bias_voltage_bit10[i+8]) / len(prev_bias_voltage_bit10[i+8])
            bit10_sum[i+8] = 0

        print(avg_current) #ラズパイへ各chの電流値をシリアル送信
        ite2 = ite2 + 1
        ite1 = 0
        led_onboard.toggle()
        
        reading_temp = sensor_temp.read_u16() * conversation_factor #周囲温度を計算
        temperature = 27 - (reading_temp - 0.706) / 0.001721

spi.deinit()

2022/04/22

ラズパイとラズピコで分電盤センサを作成①(HW最終形)

ラズパイを使って家の電気使用量を調べたいーーー

ラズパイを使って何をするかを考えていた時に、割と初期からその想いはあったが、アイデアを実行に移すのは結構大変だった。半年ほどかけて勉強し、分電盤センサを作成したので、記録として残しておく。まずは出来上がった最終形を載せる。

やりたいこと:
家の分電盤に電流センサを仕込み、どの家電がいつどのくらい電気を使っているかを分かるようにする。主幹ブレーカーではなく、枝のブレーカー単位で測れるようにする。
→節電や、将来の電気プラン変更、太陽光発電の導入(?)時に参考情報として使いたい。

感想:
ブレッドボードでLチカ、とは違い、実際に使えるものを作ろうとするとこんなに苦労するのか、と思った。前半の勉強・実験パートもまあまあ大変だったが、後半の詳細設計・実装になると、モノ作りの経験がゼロのため、発想が出てこない。ネット上には要素実験、PoCをして終了、みたいな記事ばかりで、「で、実際作るときどうするの?」みたいな答えは少なかった。数少ないネット上の作例などを参考にしながらひたすら思考実験。部品を買うときも、実装するときも、失敗=即追加出費になるのも怖かった。こればかりは、経験を積まないとダメなんだろうなあ。

できあがった全体概要図はこのようなかんじ。


回路図はこう。

完成写真ものせる。
・電流センサ

・電流電圧変換基板

・ラズピコ基板

・分電盤施工後(汚い・・・)

使用したハードウェア
  • Raspberry Pi 3A+ ×1
  • Raspberry Pi Pico ×1
  • MCP3008 ×2
  • KCT-6 ×10
  • TL431シャントレギュレータ ×1
  • カーボン抵抗 多数
  • 積層セラミックコンデンサ 10μF 25V ×10
  • C型ユニバーサル基板 ×2
  • C型ユニバーサル基板用アクリル板 ×4
  • 樹脂ナット、スペーサ
  • 対熱ビニル電線 AWG22
  • UEW線
  • XHコネクタセット ×12
  • L型ピンソケット ×28
  • コネクタ付きケーブル
  • USBケーブル
  • アダプタ
ラズパイは除くとしても、トータル5000円以上かかっている。勉強とか実験で無駄な部品も買ったので、実際は10000円以上・・まあ、趣味と実益を兼ねていてかなり勉強にもなったので、安い方だろう。

ソフトウェア周りは次回。




ラズパイとラズピコで分電盤センサを作成(14)

回路の実装図作成に取り掛かろうと思ったが、ここで一つ寄り道。 ADCへの入力前に交流電圧に対して直流バイアスをかける手段として、オペアンプを使う方法が出てきた。 アナデジ太郎の回路設計 というか、バイアスをかけたい場合、この方法の方がメジャー・・? と思ったのだが、オペアンプは以...