Arduinoで商用電源周波数を測定してみた
Arduino を使って商用電源の周波数を測定します。
今回は Arduino Nano を使って測定しましたが、Arduino UNO でも同様に測定可能です。ロジックレベルは 5V ですが、3.3V の Arduino ボードでも問題なく測定できます。
回路
回路図 | 実装例 |
交流をそのまま Arduino に入力はできません。今回はフォトカプラを使って電源を分離、Arduino に入力できる信号に加工します。周波数さえ測定できればよいので Arduino に入力される信号は矩形波になります。
回路は日本の交流 100V を想定していますが、その他の地域においては使用する抵抗値を変えてください。
回路シミュレータの結果 |
使用部品
部品名 | モデル・特性 | 個数 | 入手先 |
---|---|---|---|
フォトカプラ | TLP785(GB F) | 2個 | 秋月電子 など |
炭素皮膜抵抗 | 100kΩ 1/4W | 2個 | 秋月電子 など |
ターミナルブロック | TB111-2-2-U-1-1 | 1個 | 秋月電子 など |
ACコード | SH-015 | 1本 | 秋月電子 など |
Arduino とブレッドボードはお好みのものを使ってください。
プログラム
#define SIZE 100
#define CORRECTION_A (0.9986498254360101)
#define CORRECTION_B (7.275957614183426e-12)
uint16_t index = 0;
uint32_t times[SIZE];
uint32_t old_time = 0;
void setup() {
Serial.begin(9600);
Serial.println("avg");
old_time = micros();
attachInterrupt(0, acin, RISING);
}
void loop() {
float avg, favg;
uint8_t index_tmp = index;
avg = 0.0;
for (uint8_t i = 0; i < index_tmp; i++)
avg += times[i] * CORRECTION_A + CORRECTION_B;
avg /= (float)index_tmp;
favg = (1.0 / (avg / 1000000.0)) * 1000;
if (favg < 65000.0 && favg > 45000.0)
Serial.println(favg);
index = 0;
delay(1000);
}
void acin() {
uint32_t time = micros();
if (index >= SIZE)
return;
times[index] = time - old_time;
old_time = time;
index++;
}
フォトカプラからの入力の立ち上がりを外部割り込みで検知させ、関数 acin()
を実行します。この関数では配列に「前回の測定時刻からの経過時間(μs)」を格納していきます。関数 loop()
内で格納された経過時間の平均をとり、読みやすい Hz に直してシリアル出力します。
商用電源周波数 50 Hz / 60 Hz に対して Arduino の関数 micros()
は 250 kHz[1] の分解能を持っており、十分な精度が期待できます。
ただし電源プラグの抜き差しなどで正常に値がとれない場合を考慮し、45 ~ 65 Hz の範囲外の結果は出力しないようにしています。通常の状況であれば 50 Hz / 60 Hz からは大きく外れることはないはずです(詳細は後述)。
経過時間の補正
外部割り込みのタイミングや関数 micros()
の呼び出しオーバーヘッドにより、経過時間の補正をせずにそのまま周波数を計算すると期待する値よりも若干低い値が出ます。
そこで、商用電源の代わりにファンクションジェネレータに接続し、経過時間を補正してみます。なお、ファンクションジェネレータの出力電圧は低いので抵抗は 100kΩ の代わりに 1kΩ を使って測定します。
入力周波数 (Hz) | 期待する値 (μs) | 測定された平均値 (μs) |
---|---|---|
50.0 | 20000.00 | 20027.04 |
60.0 | 16666.67 | 16689.20 |
あとは連立一次方程式を解いて、補正に使う乗算値と加算値を求めます。加算値は小さく、float
の精度ではほぼゼロになるので無視してもよいかもしれません。
#define CORRECTION_A (0.9986498254360101)
#define CORRECTION_B (7.275957614183426e-12)
観察
Arduino のアプリケーションからシリアルプロッタを開き、ボーレートを合わせるとプロットが始まります。観測地は東京電力管内のため 50 Hz が基準になります。
周波数の変動は常に生じていますが、東京電力管内では 50.0 ±0.2Hz が目標値となっています[2]。この範囲から大きく外れる場合は周波数低下リレー(UFR)の作動によって電力系統から脱落するはずで、範囲から外れた周波数を観測することは難しいはずです。
ただし、たとえば災害などで多数の電力系統が脱落した場合、たとえ停電に至らなくても急激に周波数が低下、その後長い時間をかけて復帰していく様子が観測できる場合があります[3]。
通常時でも ±0.1Hz 程度の変動は常に起きていますが、その変動は即時ではなく10秒~60秒前後の緩やかな変化です。異常検知としては上記の目標値の監視のほか、瞬時の最大値と最低値の監視、もしくは差分をとって急激な変動がないかの監視が有効かもしれません。
-
関数
micros()
はボードのプログラムが実行開始してからのマイクロ秒を返す関数ですが、その分解能は Arduino Nano においては 4 μs です。出典: (https://www.arduino.cc/reference/en/language/functions/time/micros/) より ↩︎ -
出典: 電力会社における周波数調整と会社間連系について 平成15年9月12日 東京電力(株) ↩︎
-
2021年の福島県沖地震によって周波数が変動した例: https://twitter.com/TomonoTokyo/status/1360593240936751108 ↩︎
Discussion