音楽心理学実験ツールとしてのPC環境性能の再検討
2019年4月 長嶋 洋一
20年前に多くの機器/システムの遅延(レイテンシ)とばらつき(ジッタ)について計測実験を行った。 そして、音楽心理学実験の領域で便利/高性能な「道具」として普及したテクノロジーを正しく理解せずに使用することは、研究の基盤そのものを無意味にしてしまうと警鐘を鳴らした。 現在では当時に比べてPCの性能が約100倍ほど向上し、多種の周辺環境が整備されてきたが、情報技術/情報科学の本質としてのレイテンシ/ジッタは依然として存在している。 そこでネットワーク環境や物理コンピューティングの進展を受けて、改めて当時と同様の問題点に関する計測実験を行ってみた。 ここでは、 PC環境での心理学実験におけるレイテンシとジッタの再検証 の「実験環境」の部分について詳細に解説して、レイテンシとジッタの計測実験システムの妥当性について補完的な報告を行う。実験環境(再録)
- Max7から115200bpsのシリアルでArduinoのポートを叩いて、Arduinoから2つのディジタル出力を上げ下げしてPicoScope3205Aで計測する
- 時間差(遅れ)を計測するために、PicoScope3205Aはワンショット・トリガモードで立ち下がりエッジに反応する
- Max7から設定する時間精度としては、「OverDrive」とdefaultの「Scheduler:1msec」で、ほぼ1msecまで正確に動作する
- 数回〜10数回の試行実験により、シリアル通信やMax側(Mac内部)のレイテンシによるばらつき(ジッタ)は十分に小さいと確認できた
- 以上から、この「Max7+Arduino+PicoScope3205A」システムは、「遅延時間計測システム」として1msec精度の計測が可能と判断した
PicoScope3205Aの時間的性能確認
- PicoScope3205A とは英国 Pico Technology社 の2チャンネル100MHzサンプリングオシロスコープで、8ビット精度で500Msamples/sのサンプリングレートで16Msamplesのバッファメモリを持つ
- 2018年8月にリリースされた、MacOSに対応の PicoScope 6.13.7 Beta for macOS, including drivers という対応ソフトの動作を確認して使用した
- ホストは、MacOS10.11.6(El Capitan)のMac mini (2.6GHz Intel Core i5, 8GB 1600MHz DDR3)である。なお「USBシリアルドライバ」については「FTDIUSBSerialDriver_v2.3」から下げて「FTDIUSBSerialDriver_v2.2.18」を使用している。この事情については本ページの下の方にある「USBシリアルドライバについて(補遺)」を参照されたい
- 以降に並べている「PicoScope-6.13.7」のウインドウでは、上下2段(青いAチャンネルと赤いBチャンネル)はオフセット設定で上下にずらし、感度としてはアナログ入力電圧(+5V)がアッテネータで0.5Vとなる
- 確認実験では青いAチャンネルだけを使って、0.6Vのところの「H」が、Arduinoシールド上のプッシュスイッチを押して「L」になると0.1Vになる、と設定した
- オシロのトリガ設定をワンショットの「立ち下がりエッジ」として、ちょうど「H」と「L」の中間の300mVをトリガレベルと設定してrunさせて、スイッチを押して青いAチャンネルの電圧がトリガレベルになった瞬間が時間軸のゼロとして、それ以前とそれ以後の電圧がサンプリングされて表示される
- 以下の9個のグラフは、横軸の時間的分解能だけを変えて計測したデータである
- 1目盛りが1msecや100μsecのあたりでは、単に+5Vの電圧がGNDレベルに下がるだけ、と見える
- 1目盛りが10μsecや1μsecになると、立ち下がりの瞬間にGNDレベルよりもマイナス側までジャンプしているように見える
- 1目盛りが200nsecから50nsec、20nsecとさらに時間分解能をあげていくと、数回のバウンドの最初には-2V以下まで振れていること、遠いディジタル出力端子(D2)でも1V近く誘導ジャンプしている
- 1目盛りが5nsecのグラフだと、スイッチの「H」から「L」への電圧変化はおよそ10nsec近くをかけて偏移する
- 今回の「音楽心理学実験ツールとして」の用途、そして後述するArduinoを用いたシステム性能(10μsecオーダ)からすれば、計測システムとしてこの性能は十分に高速・正確である事から、本実験の計測ツールとしてPicoScope3205Aを使用することは妥当である
Arduinoの時間的性能確認(1)
- 使用したのはArduino UNOであり、CPUのクロックは16MHzである
- Arduinoスケッチは以下のように「スイッチが押されたら(変化したら)ディジタル出力ポートの信号を反転させる」という最高速の無限ループである
- スイッチOFFの初期値として入力の青いAチャンネルは「H」レベル、出力の赤いBチャンネルは「L」にしておく
- 負論理のスイッチの「立ち下がりエッジ」を検出判定する(H/Lと比較する冗長な)処理が不要である理由は、スイッチの状態変化のたびにディジタル出力が反転すれば、スイッチONで青いAチャンネルは立ち下がりが起きて赤いBチャンネルは「L」信号が「H」信号に立ち上がり、スイッチOFFの際にはそれぞれ反転して元に戻るからである
- 一定の処理時間を要するアナログ入力監視の無限ループのどの瞬間にスイッチが押されるかはランダムなので、Arduinoのクロック速度に対応して一定の時間幅が生じる(ジッタ)
- 以下は傾向を見るために連続10回、試してみたグラフである
- およその目分量で、この10回の計測データを、「130, 180, 160, 150, 125, 170, 150, 120, 155, 205」と読んだ
- 平均の遅延としては「155μsec」、最小値が「120μsec」、最大値が「205μsec」、となった
- 最小値と最大値に約2倍近い開きがあるのは、Arduinoスケッチの通り、無限ループのどの瞬間にスイッチが押されるかに依存する
- ちょっと多めに「100μsec程度の誤差」が、本質的にこの手のシーケンシャル処理で発生する
Arduinoの時間的性能確認(2)
- 上の実験のArduinoスケッチにたった1行だけ加えた実験を行った
- 以下のように、変化したディジタル出力を書き出す直前に「delay(1)」、つまり「1msecのwait」で足踏みするというものである
- 以下は傾向を見るために連続10回、試してみたグラフである。少なくとも遅延として1msec=1000μsecはかかるので、横軸の時間軸の単位を200μsecとして、さらに立ち下がりイベントの「前20%」と「後80%」を表示するように設定を変更してが、他はまったくそのままである
- およその目分量で、この10回の計測データを、「1.21, 1.14, 1.13, 1.20, 1.15, 1.18, 1.17, 1.14, 1.17, 1.12」と読んだ
- 平均の遅延としては「1.16msec = 1160μsec」となった
- 上の実験の平均値「155μsec」と比較してもオーダとしていい感じに対応している
- 結論として、Arduinoの時間管理が「10μsec」のオーダでほぼ正確である、と確認できた
[Max+Arduino]連携システムの時間的性能確認
- 心理学実験システムとしてMaxからArduinoを経由してPicoScope3205Aで時間計測を行う、というのが基本方針なので、次に「MaxとArduino」の連携について検証した
- 上の実験ではArduinoシールド上のプッシュスイッチをArduinoがアナログ入力でモニタしてディジタルビットから出力したが、今後はホストがMaxとなって基準の「スタート」情報もMaxから来るので、処理時間のかかるアナログ入力は不要となり、PicoScope3205Aに接続する2チャンネルの信号をいずれもArduinoのディジタル出力(計2ビット)として個別に出力する
- ここ にあるように、MaxとArduinoの連携の手法としては「Firmata(+Maxuino)」・「Arduino2Max」・「Arduino-USBMIDI」の3種類があるが、Arduino UNOでは「Arduino-USBMIDI」が使えない。そして「Firmata(+Maxuino)」は多機能のため冗長なので、基本戦略としては「Arduino2Max」のインターフェース手法に準じることにした
- 「Arduino2Max」では、Maxから115200bpsのシリアルUSB経由で送られるデータが"r"である事をArduinoがモニタしているが、本実験では機能を限定できるので、よりシンプルで高速なArduinoスケッチとした
- 以下はArduinoスケッチであり、115200bpsのシリアルUSB入力があるまで無限ループで待機している
- 入力が"1"であればPicoScope3205AのAチャンネルに接続されたディジタルポートを「L」にする
- 入力が"2"であればPicoScope3205AのAチャンネルに接続されたディジタルポートを「H」にする
- 入力が"3"であればPicoScope3205AのBチャンネルに接続されたディジタルポートを「L」にする
- 入力が"4"であればPicoScope3205AのBチャンネルに接続されたディジタルポートを「H」にする
- 以下はホストのMaxパッチの例であり、"1"、"2"、"3"、"4"という4種類のいずれかのデータを115200bpsのシリアルUSBから出力するだけである
- スペースキーを叩くと"2"と"4"が送られて、2ビット(→PicoScope3205Aに接続する2チャンネルの信号)とも「H」となる
- パッチ中央の大きなボタンが基準の「スタート」であり、メッセージ"1"を送ってAチャンネルの信号を立ち下げる
- このパッチ例ではそこから「delay」で設定された時間だけ遅れてメッセージ"3"を送ってBチャンネルの信号を立ち下げる
- 以下はスタートから「10msec」の遅延時間を計測した6回の実験の模様であり、正確に計測されていると確認できた
- 以下はスタートから「4msec」および「3msec」および「2msec」の遅延時間を計測した9回の実験の模様であり、正確に計測されていると確認できた
- 以下はスタートから「1msec」の遅延時間を計測した6回の実験の模様であり、ほぼ正確に計測されていると確認できた
- なお、最高性能とするために、Max7は「OverDrive」にしていて、Preferncesでスケジューラの精度を「1msec」にした
- 以上の実験から、このシステムは「msecオーダ」のレイテンシ/ジッタの計測実験として使える、と判断した
USBシリアルドライバについて(補遺)
- MacコンピュータにUSB経由でシリアルデバイス(MIDIインターフェース、Arduino、Propeller、mbed、タブレット等)を接続するためには「USBシリアルドライバ」が必要である
- 従来、この「Mac用USBシリアルドライバ」については、インターフェースのチップを提供している Future Technology Devices International社 が提供してきた
- Mac版の VCP Driver を見ると、「Mac OS X 10.3 to 10.8」に対しては「FTDIUSBSerialDriver_v2_2_18.dmg」が、そして「Mac OS X 10.9 and above」に対しては「FTDIUSBSerialDriver_v2_4_2.dmg」が最新版として公開されている
- 筆者の実験環境は「Mac OSX 10.11.6」なので、各種のUSBシリアルデバイス機器の専用ドライバをインストールすると、システムが勝手に最新の「v2.4.2」をインストールしてしまう事があるが、これにより多くの不具合が起きる
- この不具合の原因の一つとして、 VCP Driver のComment欄「This driver is signed by Apple」にあるように、それ以前のバージョンはFTDI社が提供していたのに対して、このバージョンからAppleになっている、という事が多くの専門家によって指摘されている
- このため、 OpenBCI が提供している脳波センシングシステムのように、BluetoothおよびUSBシリアルを経由して「多量のデータパケット」を連続的に送るようなシステムにおいては、「v2.3以降のバージョンは[不具合が起きる/バッファ拡張設定が出来ない]等のトラブルが起きるので使わないように」と警告し、「以下の手順で安定版であるv2.2.18に戻す」ことが推奨されている
- 筆者自身の体験として、演習室の「Mac OSX 10.11.6」に新しいタブレットのドライバをインストールすると(勝手にv2.4.2に書き換えられて)「Arduinoが認識されなくなる」というバグに遭遇したため、上記手順によってv2.2.18に戻すことで解決した(タブレットは別にv2.2.18であっても問題なく使える)
- そこでMacユーザについては、USBシリアルドライバが2.3以上になっていた場合には、安定版であるv2.2.18に戻すことが強く推奨される
- 以下がそのシリアルドライバ回復(+ buffer sizeの拡張)手順である
- Macを管理者権限で立ち上げる
- 「/Applications/Utilities/Terminal」でターミナルを起動する。全ての操作はターミナルからUnixコマンドで行う
- 「sudo rm -rf /System/Library/Extensions/FTDIUSBSerialDriver.kext」で既存のFTDI kernel extension (.kext)を消去する
- v2.2.18以外のVCPが存在していない事を確認する
- 「sudo rm -rf /Library/Extensions/FTDIUSBSerialDriver.kext」で既存のFTDIUSBSerialDriver.kextを消去する
- v2.3でもv2.4.2でもなくv2.2.18を改めてインストールする。「FTDIUSBSerialDriver_v2_2_18.dmg」の方である
- ※ ここから以下は、脳波センサ等でUSBシリアルからstreamingモードで多量のデータを取得するためにbuffer sizeを拡張する手順(対象はOSX 10.11以降)である。不具合を避けるためにv2.2.18に戻す場合にはここまででOKで、以下は省略可能
- 「sudo nvram boot-args="kext-dev-mode=1"」でenable kext dev mode and disable signature verificationする
- いったん「hold the Cmd-R key」でMacをリセットしてrecovery modeに入り、「csrutil disable」として再起動する
- ここで該当の(バッファ拡張する)USBシリアルデバイスをUSBポートに繋ぐ
- 「sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext」でFTDI kernel extensionをunloadする
- 「kextstat | grep FTDI」でunloadされた事を確認する(何もなくなればOK)
- 「sudo emacs/System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist」でInfo.plist fileを開く。emacsでなくvimで編集する場合には「sudo vim/System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist」とする
- config dataを編集する。「FT X Series」というのを探して「InBufferSize」に「64」を指定し、エディタをsaveしてcloseする
- 「sudo kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext」でkernel extensionをリロードする
- 「kextstat | grep FTDI」でreloadを確認する
- これで環境の修復/buffer拡張が完了(^o^)
- 上記のように、Mac版のUSBシリアルデバイスについては、「最新版の方が良い」という一般論とは別に、「安定版のv2.2.18の方が良い」(「Mac OS X 10.9 and above」でも安定して動作する)とここで指摘しておきたい
ここから先は→こちらへどうぞ