2016年5月27日金曜日

ゆっくり計るADコンバータにはノイズが必要だってばさ

重さを量る秤だとか、気温を測る温度計だとかをコンピュータで計る場合、アナログ回路でセンサー値を電圧値にして、ADコンバータで計る事になると思う。このアナログ回路にはある程度ノイズがある必要がある。

この「ノイズが必要」という事を忘れた設計をしている人が多いので、この場で愚痴っておこうと思います。

実験

1000回のデータを計測してその平均を出力するとします。その時に乗るノイズが正規分布で標準偏差(sigma)を0〜1の間で変化させて見ました。ヒストグラムをプロットするとsigma毎にこんな感じになります。
sigma=0のときは0と1しか取らないです、sigmaが0.4,1.0と大きくなるにつれて広い範囲に分布しているのが見て取れます。

 1000回平均値

いよいよ本題です。ノイズの大きさによる平均値の出方の違いを見ていきます。横軸(入力)は0〜1まで0.2単位で変動していて、それにノイズが乗っています。縦軸はADコンバータで計測した平均値を各ノイズ幅(sigma)毎にプロットしています。
真値とAD平均値
sigma=0すなわちノイズが無い時(青線)は0か1しか取らないのでどれだけ平均をとっても真値0.1,0.2,0.3,0.4はAD値平均では0です。逆にsigma=1、すなわちノイズの標準偏差がAD1bit分の時はほぼ綺麗な直線で1000回移動平均とれば0.1単位の値が余裕で読める事がわかります。
sigma=0.2だと正規分布関数形状由来の歪みが出るので補正が必要です。補正の仕方はσの値の大きさによって変わるので、可能ではあるが少しやっかいという状態です。

結論

ADコンバータで電圧を読み取る時で、平均値を取る位時間に余裕がある時は電気回路側でノイズを載せてもらいましょう。その程度の設計は追加コストほぼ0で出来るはずです。載せる量は積算回数にもよるので一概にはいえないですが、安全をとってとりあえず標準偏差=1bit位を目指せばいいんじゃないでしょうか?その辺は業界によって常識的な範囲が変わってくると思います。

今回は電気の話でしたが、これ以外にも、ファームウェアでノイズ取ってます!系もやっかいですよね。「ちょ、勝手に捨てないでよ!ノイズの量を計測した後に信号処理したいだってば」って事、よくある、よくある。なんだろ、この親切が超裏目に出る感じ。


2016年5月25日水曜日

音楽フェスのブッキングからパンフ作成まで

京都で行われる音楽フェス西院ミュージックフェスの応募音源の管理から、パンフレットのスケジュール一覧作成までの概要をまとめます。10年ちかくやってちょいちょい改良されてきた手法なので同じく音楽フェスの事務をやる人の参考になれば幸いです。

やること

約450組のブッキング・選考ミュージシャンの中から音源を聞いて29会場・約230枠のスケジュールにあてはめていきます。ブッキングは単にスタッフが代理でミュージシャンの代わりに代理応募しているだけなので事務屋さん的にはブッキングも選考も区別はありません。これにさらにスポンサー広告やイベント情報を追加してパンフレットのできあがりです。パンフレットはスケジュール面担当、地図面担当の2人で行っており、私はスケジュール面作成のためのデータ整理などのアシスト作業をしていました。

パンフレット:スケジュール面
パンフレット:地図面


作成スケジュール 

2016年の西院フェスの場合以下の様なスケジュールになっています。
  • 1月   ミュージシャン募集開始、webや郵送での応募を開始します
  • 3月   選考開始
  • 3月31日 スポンサー締め切り
  • 4月16日  スポンサー広告デザイン作業(大口スポンサーは5月中頃まで続く)
  • 4月28日 ミュージシャン決定
  • 5月7日 出演ミュージシャンへの連絡完了
  • 5月7日 パンフレットスケジュール欄作成開始
  • 5月7〜14日 時間の入れ替え
  • 5月15日 スケジュール(ミュージシャン名・ジャンル)最終確認
  • 訂正・確認作業(イベント関連だとか細々とした修正がちょいちょい入る)
  • 5月20日 入稿!!
5月前半は大口スポンサーの広告についてデータが入ってきつつ、一度デザインに着手したスケジュールがちょこまかと変わる地獄を見ます。

西院フェスミュージシャン応募情報

応募情報は、パンフレットやwebに掲載する情報のほか、選考用の音源をWebに登録します。基本はミュージシャンに直接webで登録して貰いますが、webが使えない人のために郵送での代理登録も行っています。

web応募画面
ちなみに郵送での登録は応募時点ではミュージシャン名と音源のみを手作業で登録して、応募用紙はカメラで撮影して画像として登録しています。選考で通過したミュージシャンのみ改めて後日メンバー表・webサイト・連絡先などをwebに登録しなおす省力化を行っています。

選考作業

 選考作業は、主に選考担当スタッフが行いますが各会場担当もこういう人が欲しいという意見を出します。膨大な量の音源を聞く必要があるので、スマホで各選考スタッフが聞けるようにしてあります。どんな感じだからxx会場に合いそうというメモ書きが所々に見受けられます。
選考画面(一部)
選考画面では○△×の3段階で選別したあとに、「採用」を決定していきます。採用決定作業は枠にいれる作業になるので、一覧性をもとめて、大きな紙に手書きでやっています。いつもは穏和な選考スタッフたちが軽く殺気だって枠を埋めていきます。その後webのスケジュール管理画面にデータが入力されます。
スケジュール入力画面
 ここで入力されたデータはそのままお客さんが見るwebのスケジュール表示画面に反映されます。よくある、スケジュール変わったから「web担当の人更新しておいて!」がほぼ存在しません。(web担当も担当会場をもつ兼任スタッフなので、そんなに暇じゃない)

スケジュール作成での工夫

ようやく本題です。妻がパンフのスケジュール面担当、webのスケジュール管理システムは私が担当。ここが気持ちよく仕事できないと家庭内不和の原因になります。

 スクリプトによる流し込み

すでに西院フェスWebからはJSON形式でスケジュールデータがダウンロード出来るようになっています。それを読み込ませてテンプレートのデザインに文字を流し込んでいきます。テンプレートは1時間後のスケジュールである右隣のデータの位置をデザインとして指定することで、時間軸に並んだ流し込みが出来るようになっています。
手作業でスケジュールをデザインする際に一番多いのは他人のジャンルを間違えて入れてしまったといった、コピペミス なのでそれが出ないだけかなり気が楽だとデザイナは言っています。


テンプレート(右側はマージン計測用のデータ)
流し込み後のスケジュール(長い文字は被るので手動調整)

スケジュールデータ(JSON形式)
参考

スケジュール変更

西院フェスでは時間の都合上パンフレット作成中も出演ミュージシャンの微調整が行われます。こういった「変更」や「追加」の事を「訂正」と呼ぶとデザイナーがキレます気をつけましょう。
この変更をスムーズにやりたいのですが、一度流し込んだあとにフォントサイズ等の微修正が行われているので、再び流し込み直すのは難しいです。そこで以下の様な差分情報をデザイナーに提出するようにしています。
差分の例 スペース区切りで左が元、右が変更後
 スケジュールのJSONデータはその時々に取得したものを保存しておきます。パンフだけならパンフを変更する度に最新と一つ前のデータだけがあれば良いのですが、ポスターにも情報を流用していた等の理由で、急に0509と0519の差分が欲しいという要望が出たりするためです。
各日付ごとのスケジュールデータ
差分はpythonのプログラムで実行しているので、デザイナが修正作業に入る直前に毎回差分データを作成しています。(差分作成プログラム

差分プログラムを作る前は、定期的に全部を確認してたのでかなり効率が悪かったのでだいぶ作業性が改善されました。

まとめ

 パンフ作成までを一旦のゴールとして西院フェスの事務作業とその工夫を纏めてみました。230組もあると、どのミュージシャンのライブを見に行く?と選ぶのも大変ですが、その事務処理にもそこそこのノウハウが隠れています。こういった細々とした事務の効率化も考えてみると楽しいですよ。

2016年5月11日水曜日

ポータブルな電光掲示板を作るには

あの楽器春日モデル、ポータブルにしました。
平たく言うと、これは電光掲示板と針金タッチセンサーを搭載したパソコン(Raspi2)です。
電光掲示板はこちらのブログで紹介されているものを7枚並べて、USB-パラレル変換のFT245RLで表示しています。

大変なのは電力です。全力出すと100W食います。これを5Vで供給するのが大変なので今までワイヤレス化を躊躇していたのですが、LiPoバッテリーが安くなったのとこの小さいのに5V20AいけるDCDCコンバータ(OKL2-T-20)が安くで見つかったので、作りました。
ラジコン用の11.1VのLiPoバッテリーが電源です。


念のためソースファイルを置いておきます。FT245をraspiで使う参考にはなるかと思います。
Raspi用ソース:https://drive.google.com/file/d/0B2MvWvAFndBdUWc1S1Y5UmhNUkU
針金タッチセンサーH8用ソース:https://drive.google.com/file/d/0B2MvWvAFndBdajhaQTItX1N3YnM

ボール盤でゾートロープ

解説もなしに、結果だけ動画にアップしているものを説明。
ボール盤で作った、ゾートロープです。



NHKのテクネ (http://www.nhk.or.jp/techne/)に応募した作品です。映像として作るべきか、技術デモとして作るべきか3秒悩んで諦めて、技術フェチにだけわかる動画になりました。「ゾートロープ」というタイトルとセットで始めてやってる事がわかります。そもそも被写体がボール盤な時点で、技術フェチ以外お断り感ありますね。


ドリルに付いている円盤にはTECHNEと文字が掘ってあって、そこだけ光が通るようになっています。そこに狙った場所に文字が来た時にタイミング良くLEDで光を照射する事でTECHNEの影を出します。


簡単に見えるでしょうが、カメラで撮影するためにはちょっと大変な裏側があります。

1.カメラは約30fps
1秒間に30回撮影するという事は、ボール盤が一秒間に31回だけ回ると回転のタイミングとシャッターのタイミングが微妙にあってしまって、31-30=1Hzで光が点滅してしまいます。ボール盤の回転を秒間100回転ぐらいにして点滅が気にならないのようにしています。
2.文字がぼけると格好悪い
光を長い時間照射すると、円盤が回ってしまうので、文字がぼけます。格好悪いですね。攻めて1/100回転ぐらいの時間にしたいとします。上にかいたようにボール盤は秒間約100回転、かつ1/100回転精度でLEDをON/OFFしたい。となるとLEDを1万分の1秒しか点灯させてはいけません。こんな感じで、わりとタイマー制御をしっかりとしなければいけないので「arduinoのdelay関数で適当にやろう。」では無理です。普通にプログラムを書く必要があります。
3.暗いと映らない
これはやるまで忘れていたんですが、点灯している時間は1/100なんですね。なので1WのLEDを使っていてもまるで10mWのLEDのような暗さになります。なので後付けで虫眼鏡をつけてLEDをスポットライトにしています。

暗いので諦めた事
暗くて残念画質なのでよくわかりませんが、文字が止まって見えるようにドリル刃も止まってみえます。止まっているドリル刃が穴をあけていく様子はストップモーションアニメのようで楽しいですよ。もう少し明るいLEDを在庫しておけば良かったですね。



参考:LEDのスポットライト化
 パワーLEDをスポットライト化する時は出来るだけ倍率が高くて、口径の大きな虫眼鏡を使うといいです。LEDはおおよそ焦点距離におく事になります。虫眼鏡の倍率と焦点距離の関係は⇒http://www.ikeda-lens.co.jp/guide/index3.php 。近ければ近いほど、大きければ大きいほど沢山の光がレンズを通過しますね。それだけの理屈です。
 昔はちょくちょく3倍倍率のレンズを100鈞でもみかけたのですが、最近は2倍ばっかりですね。

ちなみに、弾丸型のいわゆる普通のLEDの場合は元々の形状が非常に倍率の高いレンズなので+α程度のレンズで十分です。





ブログの移行テスト

特に思うところがあるわけではないのですが、移行テスト中です。
最近技術的な話も、twitterで済ませていたらあとで検索しづらいなと反省したので、
ちゃんとblogとtwitterを使い分けようと思っています。

2015年9月11日金曜日

拾い食いはVRか?



今日ふとしたことで、大北さんとIVRC(http://ivrc.net)の話をする機会があって、


VRの研究だとさらに人の感覚を細かく突き詰めていて「ぬるぬる感の本質」とか追い詰めてたりする。Daily Portal-Zさんでもそういうのやりますよね~。という話をしてたときに


「拾い食いは楽しい」というのを発見したんですがこれはVRですか?


http://portal.nifty.com/kiji/150609193761_1.htm


という質問をされて、答えを出せずに適当にごまかした。


元ネタを読んでもらうといいのだが、一言でいうと


「道に食べ物を(安全に)置いてもらって拾い食いをする。」


という企画である。実際には安全には不可能な拾い食いの「楽しさ」に繋がる部分を


抽出して体験させたという意味で広い意味でのVRだとは思うけど、なんか違う。


多分IVRCのようなVRコンテストに出したとしたら以下のように辛辣な質疑の嵐だろう。




  • 「本当に隠れる必要あるの?」

  • 「屋内ではだめなのか?」

  • 「姿勢だけの問題ではないのか?」

  • 「本当に食べるまでする必要はあるの?」

  • 「身内が仕掛けてるから楽しいのではないの?」

  • 「個人性は関係しないのか?」

  • 「その楽しさは本当に、拾い食いの楽しさと同一なの?」

  • 「単なるリアルじゃん」

  • 「普段拾い食いしている人にとっても、楽しいのか?」


色々でてくるけど、質問者の立場は大きく2つに分けられる。


一つは人間を知る科学としてのVR学すなわち拾い食いの楽しさのエッセンスは何か?


もう一つは人間の性質からVR体験を設計する工学(設計論)としてのVR学、つまり「拾い食いの楽しさを感じる手段として良い方法なのか?」


そういった、突き詰めが記事中には無いので大北さんの拾い食いは、「VR的な事例ではあるけれども、VRシステムとしてはちゃんと作られているか怪しい」となんとなく私は感じて、拾い食いは「VR」なのか?という質問に答えられなかった気がする。


 「VR的な体験だけどVRシステムじゃなさそうですね。」


と言う答えでとりあえずはいい気はする。


しかしまだ引っかかるものがあるのです。


最近VR学会の重鎮の人も草の根的な研究活動について気にしている。


大北さんの「拾い食い=楽しい」に対して、研究として体系的な実験で地道に上の質問に答えをだして突き詰める人は出ないだろう。


ただ、草の根活動として「拾い食い体験」が拡がる可能性はある。そうしたとときに、「寿司を拾い食いするのじゃなくて、回転ずしを拾い食いしたい」とか普通の実験設計ではやらないような事をする人が現れたりもする。かなりの数が無駄な実験に終わるかもしれないが、変な条件でやった例が沢山貯まると、研究者が真面目に実験設計した少数の実験を超える「拾い食いと楽しさの関係」に関する知見が得られるかもしれない。(知見をまとめるのは本業研究者かもしれないが)


何を絵空事をと思うかもしれないが、「初音ミクにそれを見た。」と言うと拾い食いのVRもブームにさえ乗れれば不可能じゃない気がしないだろうか?


そこまで考慮すると、安易にそんな奴らVRじゃねぇーよといって軽く見るのは危険な気もする。逆に拾い過ぎても薄まりすぎて一瞬のブームで忘れ去れる戯れ事となる気もする。


しょうじき、私はVR研究者ではないし、VRの学位も持たない。たんなるVR好きのオッサンだし、このモヤモヤに答えを出せる気がしない。でも世の中の色んな事に「VRかもしんない」と思ってちょっと立ち止まって見るのはいい所を付いているきがする。








注:IVRCとは関係ない個人の私見ですよ。「それは違う」と怒られる気はするけど、まぁ怒られてみないと解らないので、記事として書きました。怒るときは優しくお願いします>各位





2015年6月13日土曜日

Raspberry Pi2でws2812bを使う






この人のライブラリを使えば動くけど、レジスタアクセスは多分volatileを追加したほうが将来コンパイラが変わっても安心。


https://github.com/richardghirst/rpi_ws281x#


C-cで終了すると終了処理が走らないのでmain.cにSIGINTを追加。ついでにSIGTERMも。


ほかにもmailbox.cにおいてレジスタをmmapでマッピングするのは正しく動くけどunmapにバグがあるので修正して使っています。


差分はこんな感じ。


RPi2からWS2812Bへの接続は直接接続でやってます。安全のため100Ωの抵抗を直列に挟んでいます。(抵抗による電圧降下はなかったです)



diff rpi_ws281x-master/dma.h rpi_ws281x-master_new/dma.h
42,48c42,48
< uint32_t ti;
< uint32_t source_ad;
< uint32_t dest_ad;
< uint32_t txfr_len;
< uint32_t stride;
< uint32_t nextconbk;
< uint32_t resvd_0x18[2];
---
> volatile uint32_t ti;
> volatile uint32_t source_ad;
> volatile uint32_t dest_ad;
> volatile uint32_t txfr_len;
> volatile uint32_t stride;
> volatile uint32_t nextconbk;
> volatile uint32_t resvd_0x18[2];
55,56c55,56
< {
< uint32_t cs;
---
> {
> volatile uint32_t cs;
71,72c71,72
< uint32_t conblk_ad;
< uint32_t ti;
---
> volatile uint32_t conblk_ad;
> volatile uint32_t ti;
88,90c88,90
< uint32_t source_ad;
< uint32_t dest_ad;
< uint32_t txfr_len;
---
> volatile uint32_t source_ad;
> volatile uint32_t dest_ad;
> volatile uint32_t txfr_len;
93c93
< uint32_t stride;
---
> volatile uint32_t stride;
96,97c96,97
< uint32_t nextconbk;
< uint32_t debug;
---
> volatile uint32_t nextconbk;
> volatile uint32_t debug;
rpi_ws281x-master_new/だけに発見: dma.h~
rpi_ws281x-master_new/だけに発見: dma.o
diff rpi_ws281x-master/gpio.h rpi_ws281x-master_new/gpio.h
36,61c36,61
< uint32_t fsel[6]; // GPIO Function Select
< uint32_t resvd_0x18;
< uint32_t set[2]; // GPIO Pin Output Set
< uint32_t resvd_0x24;
< uint32_t clr[2]; // GPIO Pin Output Clear
< uint32_t resvd_0x30;
< uint32_t lev[2]; // GPIO Pin Level
< uint32_t resvd_0x3c;
< uint32_t eds[2]; // GPIO Pin Event Detect Status
< uint32_t resvd_0x48;
< uint32_t ren[2]; // GPIO Pin Rising Edge Detect Enable
< uint32_t resvd_0x54;
< uint32_t fen[2]; // GPIO Pin Falling Edge Detect Enable
< uint32_t resvd_0x60;
< uint32_t hen[2]; // GPIO Pin High Detect Enable
< uint32_t resvd_0x6c;
< uint32_t len[2]; // GPIO Pin Low Detect Enable
< uint32_t resvd_0x78;
< uint32_t aren[2]; // GPIO Pin Async Rising Edge Detect
< uint32_t resvd_0x84;
< uint32_t afen[2]; // GPIO Pin Async Falling Edge Detect
< uint32_t resvd_0x90;
< uint32_t pud; // GPIO Pin Pull up/down Enable
< uint32_t pudclk[2]; // GPIO Pin Pull up/down Enable Clock
< uint32_t resvd_0xa0[4];
< uint32_t test;
---
> volatile uint32_t fsel[6]; // GPIO Function Select
> volatile uint32_t resvd_0x18;
> volatile uint32_t set[2]; // GPIO Pin Output Set
> volatile uint32_t resvd_0x24;
> volatile uint32_t clr[2]; // GPIO Pin Output Clear
> volatile uint32_t resvd_0x30;
> volatile uint32_t lev[2]; // GPIO Pin Level
> volatile uint32_t resvd_0x3c;
> volatile uint32_t eds[2]; // GPIO Pin Event Detect Status
> volatile uint32_t resvd_0x48;
> volatile uint32_t ren[2]; // GPIO Pin Rising Edge Detect Enable
> volatile uint32_t resvd_0x54;
> volatile uint32_t fen[2]; // GPIO Pin Falling Edge Detect Enable
> volatile uint32_t resvd_0x60;
> volatile uint32_t hen[2]; // GPIO Pin High Detect Enable
> volatile uint32_t resvd_0x6c;
> volatile uint32_t len[2]; // GPIO Pin Low Detect Enable
> volatile uint32_t resvd_0x78;
> volatile uint32_t aren[2]; // GPIO Pin Async Rising Edge Detect
> volatile uint32_t resvd_0x84;
> volatile uint32_t afen[2]; // GPIO Pin Async Falling Edge Detect
> volatile uint32_t resvd_0x90;
> volatile uint32_t pud; // GPIO Pin Pull up/down Enable
> volatile uint32_t pudclk[2]; // GPIO Pin Pull up/down Enable Clock
> volatile uint32_t resvd_0xa0[4];
> volatile uint32_t test;
rpi_ws281x-master_new/だけに発見: gpio.h~
rpi_ws281x-master_new/だけに発見: libws2811.a
rpi_ws281x-master_new/だけに発見: linux.pyc
diff rpi_ws281x-master/mailbox.c rpi_ws281x-master_new/mailbox.c
76a77,78
> unsigned offset = (unsigned)addr % PAGE_SIZE;
> addr-=offset;size+=offset;
rpi_ws281x-master_new/だけに発見: mailbox.c~
rpi_ws281x-master_new/だけに発見: mailbox.o
diff rpi_ws281x-master/main.c rpi_ws281x-master_new/main.c
150a151,152
> sigaction(SIGINT , &sa, NULL);
> sigaction(SIGTERM, &sa, NULL);
194c196
< usleep(500000);
---
> usleep(1000*1000/15);