• Skip to main content
  • Skip to primary sidebar
  • Skip to footer
  • HOME
  • Arduino
    • Arduino初心者編
    • Arduino基礎編
    • Arduino応用編
    • Arduino実践編
  • Raspberry Pi
  • microbit
  • XBee
  • Scratch
  • Contact Us
  • Privacy Policy

STEMSHIP

ものづくりを通して、科学を学ぼう!

現在の場所:ホーム / Arduino / Arduino基礎編 / ArduinoでSTEM教育​ 基礎編:デジタル入力フィルタ

ArduinoでSTEM教育​ 基礎編:デジタル入力フィルタ

2019年12月21日 by STEMSHIP コメントを書く

センサの入力信号は、ノイズ成分が含まれる場合がほとんどです。このノイズをソフトで除去する方法がデジタルフィルタです。今回は、代表的なローパスフィルタ、Mean(平均)フィルタ、Median(中央)フィルタのプログラム方法を紹介します。

ローパスフィルタ(RCフィルタ)

ローパスフィルタは、周波数が低い信号を通して、周波数が高い信号を遮断します。また、このフィルタはRCフィルタとも呼ばれます。電気回路でローパスフィルタを作るときは、下記のような回路構成で、抵抗(R)とコンデンサ(C)を使用します。

ローパスフィルタ

これを式で表します。ある時刻tにおけるフィルタ出力値Voutは、係数をaとして、センサ入力値をVinとすると、下記のようになります。

Vout[t] = a * Vout[t-1] + (1-a) * Vin[t]

もう少し簡単に言葉で表すと、下記のとおりです。

フィルタ出力値 = a * 前回のフィルタ出力値 + (1-a) * センサ入力値

Arduinoのローパスフィルタ(RCフィルタ)のソースコードは以下です。

//www.stemship.com
//2019.12.15

// ピンの定義
#define SENSOR_PIN 0 //照度センサ接続ピン
#define a 0.6 //フィルタ係数

//フィルター後の値
int filterVal =0;

void setup() {
  //シリアル通信設定
  Serial.begin(9600);
}

void loop() {
  //センサ値を取得
  int sensorVal = analogRead(SENSOR_PIN);

  //フィルタ後の値を計算
  filterVal = a * filterVal + (1-a) * sensorVal;

  //シリアル出力
  Serial.print(sensorVal);
  Serial.print(",");
  Serial.println(filterVal);

  //次のループまで50ms待つ
  delay(50);
}

以上のプログラムを実行した結果が下記です。CSV形式でシリアル出力しているので、シリアルプロッタでグラフ表示ができます。青がセンサ入力値、赤がフィルタ後の値です。フィルタ係数aを0~1の範囲内で色々変えて試してみてください。1に近づくほどフィルタ効果が大きくなります。

ローパスフィルタ(RCフィルタ)のグラフ

Meanフィルタ(平均フィルタ)

Meanフィルタは、過去n回分の平均値を出力するフィルタです。例として、過去10回分の平均値を計算しています。

ArduinoのMeanフィルタ(平均フィルタ)のソースコードと動作確認したグラフは以下です。

//www.stemship.com
//2019.12.15

// ピンの定義
#define SENSOR_PIN 0 //照度センサ接続ピン

//バッファの長さ
#define BUF_LEN 10

//バッファ
int buf[BUF_LEN];
int index = 0;

//フィルター後の値
int filterVal =0;

void setup() {
  //シリアル通信設定
  Serial.begin(9600);

  //バッファの初期化
  for(int i=0; i<BUF_LEN; i++) {
    buf[i] = 0;
  }
}

void loop() {
  //センサ値を取得
  int sensorVal = analogRead(SENSOR_PIN);

  //バッファに取り込んで、インデックスを更新する。
  buf[index] = sensorVal;
  index = (index+1)%BUF_LEN;

  //フィルタ用の変数
  long sum = 0;

  //フィルタ後の値を計算
  for(int i=0; i<BUF_LEN; i++) {
    sum += buf[i];
  }
  filterVal = sum / BUF_LEN;

  //シリアル出力
  Serial.print(sensorVal);
  Serial.print(",");
  Serial.println(filterVal);

  //次のループまで50ms待つ
  delay(50);
}
Meanフィルタ(平均フィルタ)のグラフ

Medianフィルタ(中央フィルタ)

Medianフィルタは、過去n回分の中央値を出力するフィルタです。例として、過去10回分の中央値を計算しています。 中央値を計算するためには、データをバッファに貯めて、昇順もしくは降順で並べて、真ん中のデータを取得する必要があり、データ処理が少し複雑です。

ArduinoのMedianフィルタ(中央フィルタ)のソースコードと動作確認したグラフは以下です。

//www.stemship.com
//2019.12.15

// ピンの定義
#define SENSOR_PIN 0 //照度センサ接続ピン

//バッファの長さ
#define BUF_LEN 10

//バッファ
int buf[BUF_LEN];
int index = 0;

//フィルター後の値
int filterVal =0;

void setup() {
  //シリアル通信設定
  Serial.begin(9600);

  //バッファの初期化
  for(int i=0; i<BUF_LEN; i++) {
    buf[i] = 0;
  }
}

void loop() {
  //センサ値を取得
  int sensorVal = analogRead(SENSOR_PIN);

  //バッファに取り込んで、インデックスを更新する。
  buf[index] = sensorVal;
  index = (index+1)%BUF_LEN;

  //フィルタ後の値を計算

  filterVal = medianFilter();

  //シリアル出力
  Serial.print(sensorVal);
  Serial.print(",");
  Serial.println(filterVal);

  //次のループまで50ms待つ
  delay(50);
}

//Medianフィルタ関数
int medianFilter() {
  //ソート用のバッファ
  static int sortBuf[BUF_LEN];

  //ソート用バッファにデータをコピー
  for(int i=0; i<BUF_LEN; i++) {
    sortBuf[i] = buf[i];
  }

  //クイックソートで並べ替える
  qsort(sortBuf, BUF_LEN, sizeof(int), quicksortFunc);

  return sortBuf[(int)BUF_LEN/2];
}

//クイックソート関数
int quicksortFunc(const void *a, const void *b) {
  return *(int *)a - *(int *)b;
}

まとめ

最後に、これまでのフィルタを全て比較したグラフが以下です。一応、ソースコードも載せておきます。

//www.stemship.com
//2019.12.15

// ピンの定義
#define SENSOR_PIN 0 //照度センサ接続ピン
#define alpha 0.6 //フィルタ係数

//バッファの長さ
#define BUF_LEN 10

//バッファ
int buf[BUF_LEN];
int index = 0;

//フィルター後の値
int meanFilterVal =0;    //Meanフィルタ
int medianFilterVal =0;  //Medianフィルタ
int rcFilterVal = 0;     //RCフィルタ

void setup() {
  //シリアル通信設定
  Serial.begin(9600);

  //バッファの初期化
  for(int i=0; i<BUF_LEN; i++) {
    buf[i] = 0;
  }
}

void loop() {
  //センサ値を取得
  int sensorVal = analogRead(SENSOR_PIN);

  //バッファに取り込んで、インデックスを更新する。
  buf[index] = sensorVal;
  index = (index+1)%BUF_LEN;

  //フィルタ用の変数
  long sum = 0;

  //RCフィルタ後の値を計算
  rcFilterVal = alpha * rcFilterVal + (1-alpha) * sensorVal;

  //Meanフィルタ後の値を計算
  for(int i=0; i<BUF_LEN; i++) {
    sum += buf[i];
  }
  meanFilterVal = sum / BUF_LEN;

  //Medianフィルタ後の値を計算
  medianFilterVal = medianFilter();

  //シリアル出力
  Serial.print(sensorVal);
  Serial.print(",");
  Serial.print(rcFilterVal);
  Serial.print(",");
  Serial.print(meanFilterVal);
  Serial.print(",");
  Serial.println(medianFilterVal);

  //次のループまで50ms待つ
  delay(50);
}

//Medianフィルタ関数
int medianFilter() {
  //ソート用のバッファ
  static int sortBuf[BUF_LEN];

  //ソート用バッファにデータをコピー
  for(int i=0; i<BUF_LEN; i++) {
    sortBuf[i] = buf[i];
  }

  //クイックソートで並べ替える
  qsort(sortBuf, BUF_LEN, sizeof(int), quicksortFunc);

  return sortBuf[(int)BUF_LEN/2];
}

//クイックソート関数
int quicksortFunc(const void *a, const void *b) {
  return *(int *)a - *(int *)b;
}
各種フィルタ比較

Meanフィルタは、急激な変化がある場合(例えば、スパイク状のノイズ)、その値も含めて平均化するため、フィルタ後の値に少し影響があります。一方、Medianフィルタは、中央値を選択するため、その影響を受けにくいという特徴があります。どのフィルタが優れているとは一概に言えません。それぞれのフィルタの特徴を理解して、状況に応じて試してみてください。

Filed Under: Arduino基礎編 関連タグ:フィルタ

Reader Interactions

コメントを残す コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。

最初のサイドバー

CONTACT US

  • Facebook
  • Twitter
  • Youtube

More to See

Arduinoベースのセンサノード:XBeeデータ収集ノードの製作

2021年9月27日 By STEMSHIP

Arduinoベースのセンサノード:Arduinoを使った温度センサの作製

2021年9月21日 By STEMSHIP

XBeeモジュールとBMP280センサを使用してデータ収集する

2021年5月31日 By STEMSHIP

XBeeモジュールでMicroPythonを使ってセンサを読み取る

2021年5月24日 By STEMSHIP

XBeeモジュールでセンサを読み取る:センサノードの設定と測定

2021年5月17日 By STEMSHIP

カテゴリー

  • Arduino (44)
    • Arduino初心者編 (15)
    • Arduino基礎編 (11)
    • Arduino実践編 (4)
    • Arduino応用編 (11)
    • Arduino番外編 (3)
  • MakeyMakey (1)
  • microbit (11)
  • Raspberry Pi (13)
  • Scratch (6)
  • STEM教育 (5)
  • XBee (15)
  • ものづくり教育 (2)
  • 子供の教育 (2)
  • 科学 (6)
  • 算数 (5)

Tags

BLE DCモータ EEPROM ELEGOO ESP32 ESP8266 IoT LCD LED makeymakey MQTT Node-RED scratch STEM教育 WiFi XBee アニメーション オンラインゲーム カメラ クローン ゲーム コスチュームの変更 サーボモータ ステッピングモータ ステートマシン スピーカ タイマー ピンポン ブロック定義 ペン ライントレース ラジコン リスト 分数 割り込み 実験 工作 幼児 当たり判定 温度センサ 無線通信 物理 角度制御 重力 音楽

Footer

最近の投稿

  • Arduinoベースのセンサノード:スケッチ(プログラム)の作製
  • Arduinoベースのセンサノード:XBeeデータ収集ノードの製作
  • Arduinoベースのセンサノード:Arduinoを使った温度センサの作製
  • XBeeモジュールとBMP280センサを使用してデータ収集する
  • XBeeモジュールでMicroPythonを使ってセンサを読み取る

タグ

BLE DCモータ EEPROM ELEGOO ESP32 ESP8266 IoT LCD LED makeymakey MQTT Node-RED scratch STEM教育 WiFi XBee アニメーション オンラインゲーム カメラ クローン ゲーム コスチュームの変更 サーボモータ ステッピングモータ ステートマシン スピーカ タイマー ピンポン ブロック定義 ペン ライントレース ラジコン リスト 分数 割り込み 実験 工作 幼児 当たり判定 温度センサ 無線通信 物理 角度制御 重力 音楽

Search

2023年3月
月 火 水 木 金 土 日
 12345
6789101112
13141516171819
20212223242526
2728293031  
« 10月    

Copyright © 2023 · STEMSHIP.COM