google-site-verification: google3bd66dd162ef54c7.html
FC2ブログ

Arduinoで商用電源周波数を測定(ESP32編)

◆まえがき
電源周波数測定の話の続きです。前回は Arduino NANO (ATmega328P) を使いましたが 、今回はESP32でやってみます。ただ、簡単に出来ると思っていたのに思わぬ苦戦を強いられました。

◆電源周期の周期の測定方法
前の記事では、電源の周期測定の方法として micros() の値を参照する方法と、タイマーカウンタを使う二つの測定方法を試しました。タイマーカウンタを使った方が精度が高い測定が出来るのですが、残念ながらESP32で同じことをやる方法が判りません。仕方が無いので micros() の値を使う方法でやることにしました。

◆プログラム
プログラムは以下の通りです
// AC period measurment ESP32
// (割り込みの排他制御は省略している)

#define AC_pin 32 // 信号入力ピン
volatile uint32_t period; // ACの周期
volatile boolean flag;

void IRAM_ATTR acIrq() { // ピン割込み処理(排他制御は省略)
static uint32_t lastMicros;
uint32_t x;
x = micros(); // microsの値を取得
period = x - lastMicros; // 周期の値を計算
lastMicros = x; // save for next time
flag = true;
}

void setup() {
Serial.begin(115200);
pinMode(AC_pin, INPUT);
attachInterrupt(AC_pin, acIrq, FALLING);
}

void loop() {
while (flag == false) { // フラグが立っていたら
}
flag = false;
Serial.println(period); // 周期の値を出力
}
電源の1周期毎に割り込みを掛け、micros() の値から周期の時間を求め、その値をシリアルに出力するようになっています。つまり50Hzなら1秒間に50回、結果を出力します。

セマフォやミューテックスを使った排他制御を行うべきなんでしょうが、正しいやり方が判らなかったので、今回は省略しています。でもアクセスするタイミングは固定で競合は起こらないはずなので、このままでも良い気もしますが、どうなんでしょう。

あと、前回の記事に書き忘れましたが、micros() の値は約70分でオーバーフローしてゼロに戻るので何か対策が必要になりそうで心配になります。でもよく考えたら、符号無し整数間の引き算なのでオーバーフローをまたいで計算しても大丈夫でした。

以下、入力回路を変えた場合の結果を見て行きます。

◆抵抗入力
前の記事のArduino NANO でやったのと同じで、一番簡単な回路です。
・回路図
直結
I/Oピンはいっぱいありますが、とりあえず D32 ピンを使いました。なおこの回路図は モジュールとして ESP32 DEVKITV1を使った状態です。トランスの出力はP-Pで±20V出ますが、CPU内部の保護抵抗で0-3.3Vにクランプされます。
C1はノイズ対策用で、R1と組み合わせて時定数 1msとしてみました。

・入力電圧波形
AC入力波形
保護ダイオードのVfの分だけ外側の電圧でクランプされています。

・測定結果(シリアルモニタで観察)
直結の場合
交流の1サイクル毎にその周期の値、つまり20000付近の値が出力されるはずなのですが、ゼロと10000付近の値しか出てこないので全然ダメです。

オシロの波形を見ると判りますが、入力電圧が変化するのに1msもかかっているので、スレッショルド電圧付近で もたもた しているうちに割り込みが何度も掛かってしまうのだと思います。ちなみに NANO (ATmega328) でこのような問題が起きなかったのは 、入力がシュミットトリガ回路になっているからだと思います。

◆トランジスタ入力
入力波形の遷移速度を早くすれば良さそうなので、トランジスタのバッファを入れてみました。
・トランジスタ入力バッファ回路
トランジスタバッファ
D1は、ベース電圧が大きくマイナスになってベース逆耐圧を超えないように入れています。
これでいけるのではと思ったのですが、結果はダメでした。ちょっとくらい増幅しても非飽和でアクティブな期間はあるので、論理が確定しないタイミングが残るということだと思います。ESP32 の I/O クロックは 80MHz なのでこれを上回る速度でスイッチングさせないと危険、ということだと思います。

◆シュミットトリガ入力
仕方が無いので74HC14を使い、シュミットトリガ入力にしました。74HC14でインターフェイス
流石にここまでやれば問題解決して、きっちり電源周期の測定が出来るようになりました。
D1とD2 にはショットキバリアダイオードを使います。74HC14 の中にもクランプダイオードが入っているので D1,D2 は無くても良さそうなものですが、これを入れないと誤検知が発生しました。高速なオシロで見ると波形立ち上がり部に波形割れが発生していたので、これが原因だと思います。たぶん飽和したダイオードが逆回復する時に非線形な挙動を起こしているのだと思います。ちなみに D1,D2 にシリコンダイオードを使ってもダメだったので逆回復時間の影響と考えて間違い無いと思います。これって、ロジックの専門家なら常識なのかも知れませんが、私は初めて経験しました。

・測定結果
最終的な周期測定結果
20000付近の値が出力されるようになって、やっとまともな測定結果が出るようになりました。
このグラフは電源の1サイクル毎の周期の測定結果を表わしていますが、そのバラツキは約6μs程度に収まっています。ATmega328 では micros()  の仕様から 4μステップの値しか得られませんでしたが、ESP32 では 1μs ステップの値が得られるので分解能の点で有利になります。

・回路の外観
74HC14入力
74HC14を使うとブレッドボードのピンをいっぱい消費するのが嫌だったんです。

◆まとめ
出来れば74HC14 は使いたくなかったのですが、仕方無いですね。他の手として、トランジスタでシュミットトリガ回路を作れば面白そうですが、そんなことやっているより話を先に進めた方が良さそうです。

Arduino UNO などで使われているCPUのATmega328Pはシュミットトリガ入力になっているので今回の記事のような苦労はしなくても良い訳で、改めて使い易さを再認識した次第です。

ともかくこれでAC電源の周期測定のための回路とプログラムは出来たので、この後はデーターの収集と保存関係のプログラム作りを開始できそうです。保存先としては、無料で使えるデーター可視化サービスの ambient を考えています。ここは昔使ったことがあるので何とかなりそうな気がしているのですが、さてどうなることやらです。

Arduinoで商用電源周波数を精密測定(ATmega328編)

◆まえがき
商用電源の周波数を記録しておくと、稀に興味深い現象が記録されていることがあることが判りました。ただ、現在のやり方では周波数の分解能が0.1Hzと粗いので、小さな変化を見逃す恐れが高いです。ということで、もっと高い分解能で測定出来る方法を検討することにしました。

なお測定には Arduino を使いますが、今回の記事では CPU に UNO などで使われている ATmega328 を使ってテストします。次回の記事では ESP32 でテストを行い、最終的にはWiFi経由でサーバーにデーターを蓄積ということを考えているのですが、はたしてこの筋書き通りにいくのか現時点では判りません。

◆トランス式のACアダプタの改造
周波数を測定するためにAC100Vラインに直接接続するのはちょっと危険です。そこでトランスを入れて測定することにして、そのトランスはACアダプタを改造して使うことにしました。

・ACアダプタ(AC-DCアダプタ)
トランス式ACアダプタ
いらなくなったDC12V/300mAのトランス式のACアダプタがあったので、これを改造することにしました。なお、スイッチング方式のアダプタではこの改造は出来ません。

・AC出力に改造
AC出力に改造

元の回路はセンタータップ方式の全波整流になっていましたが、このダイオードと電解コンデンサを外し、トランスの片側の電圧を直接出力するように改造しました。つまり、AC-ACアダプタを作ったことになります。なお、出力される交流電圧の実効値は13Vくらいで、最大値は約20Vあります。

最終的にはマイコンの電源もこのトランスから供給する予定です。全波整流用のトランスを半波整流で使うことになるので供給能力がちょっと落ちますが、軽い負荷で使うのでまあ良いかと思います。あと、こんなふうに殻割りした時点で安全規格には不適合な状態になるので注意ください。

これで測定用の信号は準備出来たので、いよいよ測定のテストに入ります。冒頭に書いたように、まずは CPU に ATmega328 を使った Arduino でテストします。

◆ピンチェンジ割り込みで測定
交流の周波数測定には割り込みを使う方式で行うこととし、まずは単純なピンチェンジ割り込みでやって見ました。

・回路図
ピンチェンジ割り込み回路図
D2ピンに交流波形を入力して割り込みを発生させ、その周期をソフトで測定します。

交流電圧の中心が 1/2 Vdd になるようにシフトさせた方が良いのですが、面倒なのでそのまま抵抗(R1)を経由して入力するだけの回路にしました。CPU のピンには保護ダイオードが付いているので、信号電圧は 0-5V の範囲にクランプされます。なお、D2 は Arduino のピンチェンジ割り込みで使用可能なピンです。

・実際の回路
電源周波数測定のブレッドボード
配線はたったこれだけです。

・テストプログラム
/*
   AC電源周波数測定方法のテスト ピン割込み方式
*/

volatile uint32_t acPeriod;   // ACの周期
volatile boolean flag;        // 割込み処理完了フラグ

void setup() {
  Serial.begin(115200);
  attachInterrupt(0, acIrq, FALLING);   // Pin2 割込み
}

void loop() {
  while (flag == false) {     // フラグが立つまで待って
  }
  flag = false;
  Serial.println(acPeriod);   // 周期の値を出力
}

void acIrq() {                // Pin2 割込み処理ルーチン
  uint32_t x;
  static uint32_t lastX = 0;
  x = micros();
  acPeriod = x - lastX;       // 周期を計算
  lastX = x;                  // 次サイクル用に値を保存
  flag = true;                // フラグセット
}

交流波形の1サイクル毎にピンチェンジ割り込み(FALLING)を発生させ、割り込み処理ルーチンの acIrq() の中で割り込みの間隔(=1周期の時間) を micros() の値から求めています。loop 側ではその値をシリアルに流すだけという単純なプログラムになっています。


・実行結果(シリアルプロッタの画面)

ピン割り込み方式、サイクル毎の周期

電源の1サイクル毎に値が更新される、つまり1秒で50ポイントのデーターが流れていくグラフになります。

50Hzなので値は約20000μsとなっていて正しく測定出来ているようです。micros() の値から計算しているので 4μs ステップに離散化されていますが、平均値を取れば分解能は上がるのでこれで大丈夫だと思います。

ちなみに、ノイズなどの影響で意図したタイミングで割り込みが入っていないと、この波形は激しく乱れるのですぐに判ります。

とりあえず電源周波数の測定にはこれくらいの分解能が出ていれば大丈夫なのですが、CPU に内蔵されたタイマーカウンタを使えばもっと分解能の高い測定が可能になります。ということで Timer1 を使った測定もやって見ました。

◆タイマー1を使った測定

・回路図
タイマーカウンタ1割り込み回路図
この測定方法では、タイマー1に接続されているD8ピンに交流波形を入力します。

・プログラム
タイマーを使った周期測定については、先人の方の事例がいっぱい公開されていますが、同じ目的で作成された tomono さんの「電源周波数の変動を測ってみた」という記事に記載されていたプログラムが一番参考になったので、少し手を加えた形で使わせていただきました。
// tomonoさんの記事 https://tomono.tokyo/2021/01/11/9106/ でテスト
// TC1割込み方式 D8に信号を入力
#define TCCCLK 2000000    // CPUクロックを8分周した値。16Mhz/8 = 2E+6

// 周期測定用変数
volatile uint16_t NumV;
volatile uint32_t SumV;
volatile uint16_t CapV;
volatile uint16_t PreCap, NowCap;

// 1秒間の最大最小平均を格納するための変数
uint16_t tNumV;
float    tAveV;
uint32_t tSumV;
unsigned long current_time;

// 割り込みハンドラ
ISR(TIMER1_CAPT_vect) {
  TIFR1 |= (1 << ICF1);
  NowCap = ICR1;
  CapV   = NowCap - PreCap; // 差分を求めて周期を算出
  PreCap = NowCap;
  SumV  += CapV;            // 差分を累積
  NumV++;                   // 累積回数を更新
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);

  // TCC1でICP1信号(PB0端子=IO8)の周期を計測する
  TCCR1A = 0;               //initialize Timer1
  TCCR1B = 0;
  TCNT1  = 0;
  TCCR1B =  0x02;           // 16MHzを8分周
  TIMSK1 |= (1 << ICIE1);   // キャプチャ割り込み許可
  current_time = millis();
}

void loop() {
  static uint8_t skp = 3;   // 最初の何回かはデータを捨てる
  if (millis() - current_time >= 1000)  {
    // 割り込みで更新している変数をコピー&初期化する
    noInterrupts();         // 割り込み停止
    tSumV = SumV;
    tNumV = NumV;
    SumV = 0;
    NumV = 0;
    interrupts();           // 割り込み再開
    tAveV = (float)tSumV / (float)tNumV;  // 1秒間の平均値

    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    current_time = millis();

    if (skp == 0) {
      Serial.println(tAveV / 2); // usに換算
    } else {
      skp--;
    }
  }
}

Timer1 のインプットキャプチャ機能を使って分解能 0.5μs で測定を行い、1秒間の平均値をシリアルに流すようになっています。測定の周期は millis() の値で刻んでいるので、電源周波数と非同期になっています。つまり1回の測定が電源の50周期だったり51周期になることがあります。


・実行結果(シリアルモニタの画面)

タイマーカウンタ方式の測定例
このグラフは1秒間の平均周期を1点として500点、つまり500秒間の変化を表わしています。

一定だと思っていた電源周波数ですが、こういう感度で見るとかなり変動していることが判りました。

◆ここまでのまとめ
この記事の状態で電源周波数の測定は出来ますが、PCを併用しないと記録を残すことは出来ません。PCの代わりにラズパイを使う手もありますが、それでもちょっと大げさな気がします。そんなことで、ESP32 で同じことをやってみたいと思っていますが、その様子は次回の記事で紹介予定です。

電源周波数の測定については、本文に記載したように tomono さんの記事を参考にさせて頂いていますが、2月13日深夜の大きな地震についても、大きな地震が起きると電源周波数が大きく変動する?という記事を書かれていて、これもとても参考になりました。そんなことで、tomono さんの記事にコメント入れているのですがなぜか書き込めませんでした。連絡が取れそうも無いので、この場を使い、感謝申し上げます。

商用電源電圧と周波数の長時間記録と分析

◆まえがき
今年の冬は電力の需給バランスが危なくなっている(いた)そうです。特に寒波の襲来で気温が下がった1月10日あたりは供給余力がほとんど無い状態だったそうです。

電力の需給バランスは電源周波数に現れてきますが、この値は比較的簡単に自分で測定出来ます。うちには電力ロガーがあるので、これを使って電源周波数を連続記録してみました。まあ、自分でも電力の需給バランス調整の片鱗でも確認出来れば面白いと考えた野次馬根性ではあります。

以下はその記録のまとめですが、先にお断りしておきます。2月13日23時頃の大きな地震に伴う周波数の変化(低下)ははっきりと検出出来たのですが、それ以外は特に特徴は発見出来ませんでした。たぶん周波数測定の分解能が足らなかったのだと思うのですが、ともかくほとんど失敗の記録ということになります。

それでも、何をどう使ったらこうなった、ということを記録しておくのも意味があると思うので、恥を忍んでまとめておきます。

◆測定系
PZEM-004TとArduinoを使った電力ロガーを使い、シリアルに流しているデーターを Windows のターミナルソフト( TeraTerm)で受信し、タイムスタンプを付けてネットワークの共有ファイルに保存しました。なお、無負荷で測定したので電源電圧と周波数だけが意味のある値で、それ以外はゼロになっています。

・使用した電力ロガー
電源モニタ

・PCの画面
tereTermと保存ファイル
小さなノートPCを使いました。画面の手前がTeraTermです。なお、測定中はディスプレイを閉じています。

測定は1月15日から2月16日までの33日間行い、測定間隔は10秒なのでデーター数は約285kで、ファイルサイズは約22MBになりました。

◆EXCELで分析
まずはEXCELで時系列のグラフを見ていきます。
覚え書き:teraTermのタイムスタンプからExcelのtimeの値への変換式
 TeraTeramのタイムスタンプ文字列:[2021-01-15 09:41:55.248]  (これがA2にある場合、)
 変換式 =DATE(MID(A2,2,4),MID(A2,7,2),MID(A2,10,2))+TIME(MID(A2,13,2),MID(A2,16,2),MID(A2,19,2))

・電源電圧の変化
電源電圧変化(4週間分)

・電源周波数の変化
電源周波数変化
2月13日の地震の時に周波数が低下していますが、ここの挙動は前の記事で詳しく解説しています。

周波数の分解能は0.1Hzステップしか無いのでデーターは極端に離散値化されていて、PWMの波形みたいになっています。この移動平均を取ると変動の様子が見えてきます。

・電圧と周波数の散布図
電源電圧vs周波数

周波数(縦軸)は移動平均(前後と自分の41点)した値で横軸は電圧です。なお、2月11日までのデーターをプロットしたので地震発生時のデーターは入っていません。

点の重なり具合が表現出来ていないのでこのままでは何とも言えないのですが、本来なら同心円状になっているはずなのに上側がカットされているのはちょっと不自然です。

ここまでの調査では傾向が見えてこなかったので、もっと詳しい分析が必要です。次は周期的な特徴が無いか調べることになり、FFTでやるのが常套手段だと思います。調べてみると、EXCELでFFTは出来ますが、データー数は2のべき乗になっていることが条件で、最大は4096まででした。今回はデーター数が233kもあるのでそのままでは分析は出来そうにありません。(VBAなどを使えば出来ます)

あと、これほどデーター数が多いとEXCELでは操作のレスポンスが悪くなってきて使い難いです。ということで、EXCELには見切りをつけて、統計解析ツールのRを使うことにしました。

◆Rを使った分析
RStudioを使って分析しました。なお週を単位とした変動の検出を容易にするために、データーの範囲を1月16日から2月11日までの4週間にしました。

・RStudioの画面
Rstudioの画面

Rを使うとサクサクと分析結果が出て来ます。

・電源周波数の時系列グラフ
移動41平均の周波数変化(時系列)
周波数の測定結果を41点移動平均したグラフです。つまり、EXCELの散布図の縦軸(周波数)の時系列グラフになります。

・周波数のスペクトラム
周波数の測定結果のまま、つまり移動平均せずにいきなりスぺクトラム分析した結果が次のグラフです。
電源周波数のスペクトル分析(生データー)
波数が0.07付近にピークがあります。これが実際の周期の値のいくつになるのか、恥ずかしながら良く判りません。

ちなみに、電源周波数の測定結果を41点移動平均した波形で分析すると、

電源周波数スペクトル(移動41平均)
変な折り返しノイズが乗って挙動が判り難くなってしまいました。移動平均に伴い波形に自己相関が出てしまっているのだと推定しているのですが、どうなんでしょう。

・電源電圧
電源電圧で同じことをやって見ると、
電圧の周波数分析
0.16と0.33付近のピークが気になりますが、それを除くと特に傾向は無い感じです。しいて言うと、周波数が高いほど振幅が小さくなっているので、1/f ノイズが乗った波形と言えそうです。

◆まとめ
・大量のデーターを取集しRまで使ったのに、意味のある特徴を発見できなくて残念です。もう少し勉強して出直したいと思います。

・「電源周波数変化には1日単位の周期性があり、毎日XX時頃に周波数が低下する。」なんて結論が出せるかと思ったのですがダメでした。いくら大量のデーターを集めても、そもそも周波数測定の分解能が0.1Hzしか無いのでは、そういう議論に参加する資格が無かったようです。

・電源の周波数をもっと高い分解能で測定することは可能なので、Arduinoを使って自動記録する仕組みを作ると面白そうです。あとは、既に電源周波数を測定してネット上に公開している方もいらっしゃるので、そういうデーターを使った方が手っ取り早いのかもしれません。

カレンダー
02 | 2021/03 | 04
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。
記事の内容のご利用は読者の自己責任でお願いします。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード