「PIC AVR 工作室」サイトの日記的なブログです。
サイトに挙げなかった他愛ないことを日記的に書き残してます。
PIC AVR 工作室 ブログ



http://www.kurims.kyoto-u.ac.jp/~ooura/fft-j.html

例のC言語用FFTライブラリを、実際に弄って、パラメタ
の指定の仕方によって、意図した結果が得られるかを
確認してみることに。



いろいろ探ってみると、

http://geisterchor.blogspot.jp/2011/04/fft_16.html

こちらに、例のFFTライブラリを使ってみた結果がリポート
されているので、その情報を頼りに、Ubuntu環境下でgccで
まずは動かしてみることに。





gccを久々に使ったので、コンパイルでいろいろ手間取った。

もともとのライブラリのmakeファイルの中身をすっ飛ばして
使いたかったので、上記のサイトのページで示されている
ヘッダファイルを利用させていただいた。

さくっとコンパイル通るようになった。ありがたい。

このヘッダファイルを使わせていただきつつ、64サンプル
の場合と、256サンプルの場合を使って、あるデータを
ぶっこんだら、想定どおりの結果が出てくるのかを確認
してみる。




まず、実験に使ったプログラム。64サンプルから。

上記のサイトのプログラムでは、mallocで配列のエリアを
確保してるんだけど、出来ればmalloc使わずに済ませたい
ので、固定サイズで割り当てするように変えたりとか、
いろいろ弄って、最小限のコンパクトなプログラムに
したのがこれ。
(例によって、このブログの仕様により、include文など
 の不等号マークを全角文字に置き換えてあります)


//  gcc fftsg.c myfft64.c -lm -o myfft64 //

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "./fftsg.h"

#define FS 6400  // サンプリング周波数
#define LEN 64  // 信号長 == FFT点数
#define N (LEN * 2)  // データ個数(実数、虚数)
#define F0 500  // 正弦波周波数


void outdata (char *title, double *a) {
  int i;
  
  printf("%s\n",title);
  printf("No , real , imaginal , log10\n");
  for (i=0; i<LEN; i++) {
    printf("%d , %f , %f , %f\n",
    i, a[i*2], a[i*2+1],
    10.0*log10(a[i*2]*a[i*2] + a[i*2+1]*a[i*2+1]) );
  }
  printf("\n");
}


int main () {
  int ip[8 + 2]; // sqrt(64) + 2
  double a[N];  // points * 2
  double w[LEN]; // points

  int i;

  // generating data
  for (i = 0; i < LEN; i++) {
    a[i*2] = sin(2.0 * M_PI * i * F0 / FS);
    a[i*2 + 1] = 0.0;
  }
  
  /* display original data */
  outdata("*** input data ***", a);

  /* do fft */
  ip[0] = 0.0;
  cdft(N, -1, a, ip, w);

  /* output result */
  outdata("*** fft result ***", a);
}



プログラム中の、配列「a」に初期値としてぶっこんでる
正弦波が、FFTを掛けたいデータ。実数→虚数の順に、
64組のデータを入れておけば、FFTがかかる。
(通常に使うときは、実数のところにADCのサンプリング
 データを入れて、虚数のところに0を入れておけばok)


結果は、標準出力に出してるので、これをパイプでファイル
に繋ぎ換えて、表計算ソフトでグラフにする。

入力データ。サンプリング周波数6400sps、データの正弦波
は500Hzという前提で、64サンプル分。青が実数、橙が虚数。




FFT掛けた結果。



左下のとんがりが、正の周波数分の出力。ちょうど500Hzの
ところにピコンと立つ。
右上のとんがりは、負の周波数分。

これらのデータを、実数、虚数それぞれを平方和して
平方根とれば、各周波数成分の量がわかる。




さらに256サンプルも試してみる。


プログラム。ほとんど同じだけど、定数だけ調整。

//  gcc fftsg256.c myfft.c -lm -o myfft256 //

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "./fftsg.h"

#define FS 6400  // サンプリング周波数
#define LEN 256  // 信号長 == FFT点数
#define N (LEN * 2)  // データ個数(実数、虚数)
#define F0 500  // 正弦波周波数


void outdata (char *title, double *a) {
  int i;
  
  printf("%s\n",title);
  printf("No , real , imaginal , log10\n");
  for (i=0; i<LEN; i++) {
    printf("%d , %f , %f , %f\n",
    i, a[i*2], a[i*2+1],
    10.0*log10(a[i*2]*a[i*2] + a[i*2+1]*a[i*2+1]) );
  }
  printf("\n");
}


int main () {
  int ip[16 + 2]; // sqrt(256) + 2
  double a[N];  // points * 2
  double w[LEN]; // points

  int i;

  // generating data
  for (i = 0; i < LEN; i++) {
    a[i*2] = sin(2.0 * M_PI * i * F0 / FS);
    a[i*2 + 1] = 0.0;
  }
  
  /* display original data */
  outdata("*** input data ***", a);

  /* do fft */
  ip[0] = 0.0;
  cdft(N, -1, a, ip, w);

  /* output result */
  outdata("*** fft result ***", a);
}



入力のデータ256サンプル分。



サンプル数が4倍になっているので、取り込まれている波の
数も4倍になっている。(サンプル周波数6400spsとデータ
となる正弦波の周波数500Hzはおなじまま)


結果は、こう。




周波数分解能が高くなってる分、とんがりが細くなってる。
けど、当然ながら500Hzのところにピコンと立ってる。





うん。できた。普通にFFTができる。ただ、このライブラリ
には、窓関数の処理が付いてないので、その辺は独自に処理
する必要有り。

キリのいい周波数じゃないと、窓掛けずにFFTすると、
エンベロープが広がってしまうのは、普通のFFTといっしょ。





というわけで、どこにどんなパラメタを指定すれば、
どんな結果になるのかは判った。

あとは、この浮動小数点処理のまま、mbedにぶっこんだら、
十分な処理速度で処理できるのかが問題かな。

うちにあるSeeeduino Archは、FPUなんて搭載してなかった
よなぁ。たしか。


あと、平方和の平方根も、FPUなしで処理すると、すんごい
時間かかるんだよな…

Nulceoシリーズで、FPU搭載してる(かつmbedで有効化が
されてる)のって、あるのかなぁ?



できればやっぱ、整数処理にして、開平なんかもテーブル
処理したいところなんだけどな。
ArduinoのFFTライブラリは、その辺よく出来てるんだよな。



コメント ( 0 )




頭の中のアレコレを、とりあえず放出する日。

Arduinoオシロのトリガ条件とか、UI周りの
ロジックとか考えないといけないんだけどな。
そっちは今日は手付かずだな。



http://www.huffingtonpost.jp/2014/06/04/tiananmen-square-massacre_n_5443123.html?utm_hp_ref=japan

あれから25年か。六四とか、5月35日とかが検索できない
としたら、0x40とか、0b1000000とかはどうなんだろ?



http://videotopics.yahoo.co.jp/videolist/official/others/pc7e2b99c638cfc610b818fd2a4b5f63e
タイムラプス映像。いいな。きれい。広角で撮る
ときの、天頂付近と地平付近の光害の影響度合い
の違いは、どうやって処理してるんだろうなぁ?
キレイに消えてるんだよな。



https://twitter.com/photongraphic/status/471319621757173760
頭文字D。全巻買ったけど、こんなお話だったとは
知らなかったな。
でもまぁ、なんにしても、バイテンの解像度には、
デジカメは当分追いつくことはできないだろうな。

バイテンはともかく、シノゴのフィールドカメラを
一度でいいから持ち出して、風景撮ってみたかったな。



http://karapaia.livedoor.biz/archives/52164848.html
ネコが好きだとアタマいい人なの?
マジで?了解!今日からネコ好きになる!!

…おかしい。頭よくならないぞ。この実験、
やり直し!!


http://ja.wikipedia.org/wiki/%E7%9F%AD%E6%99%82%E9%96%93%E3%83%95%E3%83%BC%E3%83%AA%E3%82%A8%E5%A4%89%E6%8F%9B
STFT(短時間フーリエ変換)、なんじゃ?こりゃ?



コメント ( 0 )




http://nyusokuropedia.ldblog.jp/archives/12469498.html

うぁ!こんなのあったのか…これは見てみたかったな…

「君がわかるまで!教えるのを止めない! 」が
ツボッた。


http://www.iza.ne.jp/news/newsarticle/natnews/education/578004/
三原順子氏、いじめ加害生徒に怒!
  「顔はやばいよ、ボディやんな、ボディを」


http://headlines.yahoo.co.jp/hl?a=20120725-00000085-zdn_n-inet
kobo、コケタか?事故レベルだな。


http://picavr.uunyan.com/warehouse_fft.html
FFT、長々とというかだらだらと書いて、ようやく
まとまった。解ったつもりで書き出してみると、
結構あやふやなところとか残ってたりして、やっぱ
書いてみて初めて弱いところが自覚できるんだなと
思った。

でもやっぱFFTは使ってナンボだからな。アレの
続きを進めないと。




コメント ( 0 )




今日もまた、コンプレッサをどうにかしてソフト的
に実現できないかをもがき中。

とりあえず10ビットでADCした結果を8ビットに圧縮
掛けるんだけど、原点付近(0V付近)では入力と
出力は1:1に、原点から離れるにしたがって逓減して
行くっていうグラフをでっち上げたところまでいった
訳だけど、プラス側、マイナス側両方についてきれいな
数値になるようにテーブルを(表計算ソフト上で)
作ってみる。↓こんな。


原点付近は入力が1増加するごとに出力も1増加、
そこから徐々に増加の度合いが減っていく感じの
グラフ。(マイナス側はその反対)

10ビットでADC掛けてからこのフィルターを通すと、
原点から遠ざかるにつれて圧縮された出力が得られる
というわけ。
試しに普通に8ビットでADCしたsin波と10ビットで
ADC後に圧縮したグラフを重ねてみると↓こんな。


これは5Vppの波形を入力したイメージ。赤い線が
普通の8ビットADCを想定した波形(つまりsin波)。
青い線が圧縮掛けた場合の波形。

こんな風に原点付近ではゲインが大きく、離れるに
つれてゲインが下がっていくというのが見て取れて
まずまず。当然ちょっと太る方向に歪んでくるん
だけど、そこは想定内。

で、5Vppから減衰していくイメージもグラフに描かせて
みる。まずは1/4の電圧幅にしたら(1.25Vpp程度)↓


こんな感じ。だんだんと出力が大きく出る傾向が
グラフから見えてくる。シメシメ。

さらに1/16の電圧幅にしてみる(0.3125Vpp)。

出力が弱まりすぎて値がよく判らないのでレンジを
切り替えると…

こんな風にコンプレッションを掛けていない時と
比べて2倍以上の出力が読み出せるわけ。シメシメ。

さらに、1/128の電圧幅にしてみる(0.0390625Vpp)。

この電圧は8ビットADCだとsin波としてプラス・
マイナスが数字になって現れる最低限レベル。
それでもコンプレッション掛けてる方のグラフは
ちゃんとsin波と判る波形が得られてシメシメ。


さて、折角の表計算ソフトだし、以前表計算上で動く
128点FFTワークシートも作ってあることだし、FFTに
掛けてどんなんなるか見てみる。
(5Vpp入力を仮定して128点FFTでハミング窓使用)


パッと見、普通にsin波を入力したかの様にすら
見えちゃうくらい倍音成分が無いけれど、実際は
セルの中身を見ると極微量の倍音成分が残っている
のは判る。

まぁ、FFT掛けた後のプログラム処理で見るだけなので、
ピークが判ればそれで充分。sin波に比べ見た感じでも
判る程度に波形がゆがんでいるのに、むしろこんなに
倍音成分が小さかったことの方がびっくりかな。意外。

ちなみに、窓掛けたりFFT計算の結果レンジが狭く
なったりするので、FFT結果がノイズに埋もれない
独立した信号として確認できるのは、5Vから1/128倍
まで減衰するところまで。ダイナミックレンジと
しては42dbといったあたり。(オイラが表計算
ソフトで計算値を眺めてみた上での個人的判断)

欲を出せばもっと小さい信号まで拾えると良いん
だけど、まぁ、金かけず、手間もあまりかけず、
部品も使わない範囲ならとりあえずここまでかな。
その後のことは後で考えよう。

少なくとも8ビットでADCしてそのままFFT掛ける
よりはダイナミックレンジが4倍程度広がって
いる計算だから、悪いほうには転ばないだろう。


Kenkoのenergがフル充電できたので、とりあえず
試してみた。
例によっておいら謹製のポタ赤を使って、フル充電
状態からlow battery表示になるまでの時間を計測。
(同時に、LCD上の残電量表示も監視)

とりあえず2.5時間丁度で電池切れになった。
この間エネループで実験したときには3.5時間
だったことを考えると… なんか短いなぁ。

まだ電池の活性が上がってないのかな?初回
だからな。あと数回充放電したらもうちょっと
伸びるのかな?それとも数値に偽りありなのかな?
容量は100mA/hくらいの違いしかないはずなんだけどな。

もう1回くらい試してみたいところではあるけど、
まぁ、GX100を載せると考えれば出力電圧を絞って
消費電力を下げる手は有るだろうな。9Vから6V程度
まで下げれば消費電力は半分以下になるはず。

電池ばかりに手をとられてる場合じゃないのだ。
次はまた例によって方眼紙でモックを作るのだ。


このOUT RUN、すげぇな!
http://videotopics.yahoo.co.jp/videolist/official/others/paa02200281aeab6d0d708258680fe82f

http://oshiete.goo.ne.jp/qa/768664.html
フライホイールダイオードじゃなくて、フリーホイール
ダイオードが正しいのか…。フライバックダイオードは?



コメント ( 0 )




相変わらずFFTのその後をどうするかで悩み中。
どうやったらFFT結果の精度を高くできるか。
ダイナミックレンジと周波数を共にできるだけ
精度高くしつつ、処理時間は極力短く…という
欲張りさん。

まぁ、もぞもぞ言っているよりも実機のセンサー
回路を組んじゃった方が話は早いんだけどな。
机上の空論なのは解っちゃいるんだけど、手を
動かす時間がちょっとねぇ…。


なんにしても、8ビット精度の128点のままでは
ちょっと厳しいかもしれない。かといって16ビット
幅にすると計算時間が厳しくなるし。
ってことで、次の1手を考えてみる。


(1)64点16ビット幅のFFTにする

 これなら精度は大幅に上がりそうなもんだけど、
 周波数分解能が半分になっちゃうのと、元々
 AVRのADCは10ビットだからイマイチなんだよな。

(2)ARMに鞍替え

 最後の1手にしたい。

(3)負の周波数領域もデータとして利用する

 FFTを掛けると、直流以外は半分が負の周波数に
 振り分けられるから、周波数を正に読み替えて
 データ化し、正の周波数のデータと合わせること
 で倍精度が得られるはず。


うーん。(3)で行けないかなぁ?なんとなく
ヨサゲな気がするんだけど…

負の周波数は符号がどうなのかがちょっとわかんない
んだけど、どうやって正の周波数と足せばいいんだ?
単純に足すの?絶対値を足すの?間違えないのは
多分スカラー化してから足すことなんだけど、
スカラー化も結構な時間食うからなぁ…

もうちょっと考えてみよう。


今日はポメラで打ちまくる。いい。なかなかいい。
画面の狭さがどうなのかなぁと思ってたんだけど、
そんなに気になんなかった。ctrlキーなんかもIME
と一緒。

単4エネループLITE2本でも電池切れを気にせずに
ガンガン打ってられるのはいいなぁ。



コメント ( 0 )



« 前ページ