2016年7月16日土曜日

Arduinoとアナログ・バンド・パスフィルタでなんちゃってFFTをしてみる。

FFTというか周波数分離の実験です。



BPFで周波数を選択してArduinoのADCに入力してやって周波数分布が見れるかどうかという実験。

BPFはOPAMPを使ったアクティブ・フィルターもあるが、実装がめんどくさい。

ADCの入力インピーダンスは高いようなので、信号源の出力インピーダンスを十分低くできればパッシブ・フィルターも使えそうだ。

インダクタを使ったRLCフィルターもあるが、オーディオ帯域では定数がでかくなってしまってなかなか大変そう。

RCのLPFとHPFを連結すればBPFになるので、これで実験してみた。

シミュレーション


回路図

AC解析

定数はキリの良い値にして

fc = 1 / (2 * pi * r * c) ≒ 16kHz, 1.6kHz, 160Hz

になる。

Arduinoのスケッチ

BPF_ADC_Test.ino

#include <stdio.h>

int nof  = A0;
int bpf0 = A1;
int bpf1 = A2;
int bpf2 = A3;

int v0 = 0;
int v1 = 0;
int v2 = 0;
int v3 = 0;

void setup() {
  analogReference(INTERNAL);  // internal reference 1.1V
  Serial.begin(115200);
  Serial.println("*** Measuring BPF output  ***");
}

void loop() {
  char lineBuffer[80];
  v0 = analogRead(nof);
  v1 = analogRead(bpf0);
  v2 = analogRead(bpf1);
  v3 = analogRead(bpf2);
  sprintf(lineBuffer, "%d,%d,%d,%d", v0, v1, v2, v3);
  Serial.println(lineBuffer);
}

自作のPCM5102Aを使ったファンクションジェネレータからサイン波を出力し、シリアル通信のグラフ化ツールのCPLTを使ってグラフ化してみた。

160Hzサイン波

ch1: ファンクションジェネレータからの出力
ch2: 1uF/1kΩのBPF
ch2: 0.1uF/1kΩのBPF
ch3: 0.01uF/1kΩのBPF

1.6kHzサイン波

16kHzサイン波

高周波数になるとAuduinoのSerial通信やADC値の読み込みのせいで(だと思う)、サンプリング精度が低くなってファンクションジェネレータの出力のch1波形がぐちゃぐちゃになっている。

まあでも、精度は悪いが、一応特定の周波数に反応できているようだ。

メモ:


積セラを使うと精度が悪化するのでできればフィルムコンで。同じフィルムコンでもマイラとポリプロピレンのように特性が違うといろいろややこしくなりそう。

ADCのサンプリングレートもある程度高くないと帯域が稼げない。(デジタル・オシロといっしょ)

ほんとは増幅器を入れたいところだが、それだとアクティブフィルタと部品数がほとんど変わらないので意味がない(^q^;

フィルタの位相ずれがあるので、プログラムでも入力値を平均化するなどした方が良さそう。

10倍精度ならまあまあだが、オクターブ(2倍)や音階になるとかなりシビアだと思う(^q^;;;