社内コーディング
Processingは簡単だなぁ。おでかけの行きの電車の中でデータをFFTして表示するプログラムができた。
上の青い部分が入ってくる信号の波形がリアルタイムに書かれる部分で、いまは電車内でつなぐセンサーを持ってないのでランダム+サイン波になっている。したの緑の部分がFFTの結果で、サイン波の周波数に相当する部分に鋭いピークが立っているのがわかる。
Processingのコード:
import processing.serial.*; import ddf.minim.analysis.*; import ddf.minim.*; FFT fft; Serial serial; boolean OFFLINE_TEST = true; int WIDTH = 1024; int HEIGHT = WIDTH / 4 * 2; int BUF_SIZE = 1024; int VALUE_RANGE = 1024; // means 0..1023 float buf[] = new float[BUF_SIZE]; // RATIONALE: FFT#forward take float[] float fftResult[] = new float[BUF_SIZE]; int photo=-1, prev=-1; int time = 0; boolean needFFTRedraw = false; void gotPhotoValue(){ buf[time % BUF_SIZE] = photo; time++; if(time % BUF_SIZE == 0){ fft.forward(buf); needFFTRedraw = true; } } void serialEvent(Serial p){ int d = serial.read(); int value = d / 8, mode = d % 8; if(mode == 0){ prev = photo; photo = value * 32; }else if(mode == 1){ photo += value; gotPhotoValue(); } } void setup() { size(WIDTH, HEIGHT); stroke(255); background(0, 0, 0); serial = new Serial(this,"/dev/cu.usbserial-A9004xwG", 9600); fft = new FFT(BUF_SIZE, 10); } void draw() { if(OFFLINE_TEST){ for(int i=0; i < 10; i++){ photo = floor(random(512) + 512 * sin(time / 1.0)); gotPhotoValue(); } } if(time == 0) return; if(needFFTRedraw){ fill(0); rect(0, HEIGHT / 2, WIDTH, HEIGHT); stroke(0, 255, 0); for(int i = 0; i < BUF_SIZE / 2; i++){ line(i, HEIGHT, i, HEIGHT - fft.getBand(i) / 256); } needFFTRedraw = false; } fill(0); rect(0, 0, WIDTH, HEIGHT / 2); stroke(0, 0, 255); for(int i = 0; i < BUF_SIZE; i++){ int oldx = (i + BUF_SIZE - 1) % BUF_SIZE * WIDTH / BUF_SIZE; int newx = i % BUF_SIZE * WIDTH / BUF_SIZE; int oldy = floor(buf[(i + BUF_SIZE - 1) % BUF_SIZE] / VALUE_RANGE * HEIGHT / 2); int newy = floor(buf[i % BUF_SIZE] / VALUE_RANGE * HEIGHT / 2); line(oldx, oldy, newx, oldy); line(newx, oldy, newx, newy); } }
ちらつくかなぁと思いつつ普通にrectで消してみたら意外とちらつかない。書いているものが細い線だから目立たないのか、それとも中で勝手にダブルバッファリングしてくれちゃってるのか。後者でもおかしくないよなぁ、こういう至れりつくせりフレームワークだと。
明日の夜ぐらいまで実際の心拍センサーをつないで試せないのが残念だ。むー。