HASC Tutorial 2011
http://hasc.jp/
スライドコンテンツ• HASC Tool内部構成の解説• HASC Toolの独自開発（座学）• HASC Toolの独自開発（演習）Part 3

名古屋大学 河口研究室
修士２年 小川延宏

1

HASC Tool
• HASCが開発する行動認識ツール• 行動データ収集機能• 行動データ処理機能• ラベル付与機能• 機械学習機能• HASCToolの種類• ダウンロード版:お試し版• Sourceforge版：開発者向け

2

HASC Tool 内部構成
• HASC Tool Projects• HascLoggerServerPlugin

アクセス⇒
http://svn.sourceforge.jp/svnroot/hasc/• 行動データ収集機能• HascTool• 行動データ処理機能• ラベル付与機能• HascToolDataPrj• サンプル行動データ• サンプル実行ファイル• HascWekaPrj• 機械学習機能

3

HascLoggerServerPlugin• 行動データ収集機能• HASC Loggerで収集した行動データを受信• Projectの構成

ソースコード4

HascTool• ラベル付与機能• 行動データ処理機能• Projectの構成

ソースコード

行動データ処理で重要な部分• data• filter• sink• sourcecore5HascToolDataPrj• サンプル行動データ：HASCXBD• サンプル実行ファイル：SampleData• Projectの構成

行動データ処理
実行ファイル

6

HascWekaPrj• 機械学習機能• WEKAとの連携

http://www.cs.waikato.ac.nz/ml/weka/• Projectの構成
学習器：
learningディレクトリ内にあります

ソースコード7

機械学習ツール : WEKA
• Walkato大学で作成された機械学習ツール• http://www.cs.waikato.ac.nz/ml/weka/• 使用言語：Java• オープンソース• GPNライセンス

8

HascToolの独自開発（座学）• HascTool• ブロック図で様々な処理を記述可能• Javaで独自のブロックを開発可能• メッセージの定義• ブロック間のやりとり• data• 新規フィルタを追加• filter• sink• source

9

Data (メッセージ)• ブロック間のデータ送受信• 任意のオブジェクトをメッセージとする• メッセージの紹介• ArrayVectorSignalMessage• 時刻情報 ＋ 実数値の配列• ScalarSignalMessage• 時刻情報 ＋ 実数値• ComplexVectorSignalMessage• 時刻情報 ＋ 複素数値の配列• NullSignalMessage：開発用

10

Sink / Source• HASCToolからデータを出力：sink• LineWriterSink• データをファイルに書き出し• HASCToolにデータを入力:source• LineReaderSource• ファイルから読み込み• UDPStringReceiver• UDP形式でデータを受信• SinWaveGenerator• 行動データを生成(Sin波を生成)11

Filter• 行動データ処理を実行• file• ファイル関連（例：パーサ）• Frequency• フーリエ変換関連• interpolator• サンプリング補完関連• label :ラベルデータ関連• meta :メタデータ関連• time :時間パーサなど• window :窓関数

12

Filter• ここから、ソースコード的な説明• RuntimeBeanインタフェースを実装した
任意のクラス• デフォルトコンストラクタ• プロパティをセットするためのsetterメソッド• 入力/出力ポートを返すgetterメソッド
13

サンプル
• スカラ値に、valueToAddプロパティの値を加算する
１入力１出力フィルタ
public class SampleAddFilter
implements RuntimeBean, MessageProcessor{// valueToAdd プロパティ
private double valueToAdd_ = 0;
public void setValueToAdd(double valueToAdd) {this.valueToAdd_ = valueToAdd;}// MessageProcessor interface@Override
public void processMessage(Object message)
throws InterruptedException{
if (message instanceof ScalarSignalMessage) {// ScalarSignalMessageの場合
ScalarSignalMessage inValue =(ScalarSignalMessage)message;// 新しい値を計算
double newValue =inValue.getScalarValue() + valueToAdd_;// 結果を出力
outputPort_.processMessage(new ScalarSignalMessage(inValue.getTime(), newValue));}else{// その他のメッセージ（BEGIN, ENDなど）は// そのまま出力
outputPort_.processMessage(message);}}// outputPort
private MessageConnector outputPort_=new MessageConnector();public MessageConnector getOutputPort() {return outputPort_;}// inputPort
public MessageProcessor getInputPort() {return this;}// RuntimeBeans interface@Override
public void setup(RuntimeContext context) {}}14

入力・出力ポート• 入力ポート• MessageProcessorインタフェースを実装したオブジェクト• 入力ポートのprocessMessageメソッドで、メッセージ受信時の処理を実装• 出力ポート• MessageConnectorオブジェクト• 出力ポートのprocessMessageメソッドを呼び出して、メッセージを送信• 単に、接続先の入力ポートのprocessMessageメソッドを呼び出しているだけ• connectメソッドでポート間を接続

15ヘルパークラス• AbstractFilter• RuntimeBeanを実装した抽象クラス• １入力１出力のブロックを作るのに使う• AbstractSink• RuntimeBeanを実装した抽象クラス• １入力、出力無しのブロックを作るのに使う
16別スレッドでの処理• 入力ポートのprocessMessageメソッドは、入力ポートごとに、別々のスレッドから非同期に呼び出される可能性がある• １入力ブロックの場合： メッセージ受信時に、同じスレッドで処理を行って良い。（別スレッドで行っても良い）• 多入力ブロックの場合： スレッド間の同期のため、メッセージをキューにためておき、別スレッドで処理を行う• 入力無し（出力のみ）のブロックの場合： 別スレッドで処理
１出力

１入力１出力スレッド

２入力１出力
キュー
１入力

１出力

スレッド

キュー

17

別スレッド処理に使うクラス• AbstractTaskクラス• RuntimeBeanを実装した抽象クラス• 別スレッドで処理を行う場合に使う• サブクラスでrunメソッドを実装して処理を記述（Threadクラスと同様）• MessageQueueクラス• MessageProcessorを実装したクラス（入力ポート用）• processMessageメソッドで渡されたメッセージをキューにためておき、別スレッドから取り出せる18

ヘルパークラス• AbstractMultipleInputsFilterクラス• AbstractTaskを継承した抽象クラス• 多入力１出力のブロックを作る時に使う• 全入力ポートから入力された信号メッセージの、時刻が同期され、processSignalMessagesメソッド（サブクラスで実装）が呼び出される• サンプル：VectorAdderクラス• AbstractSourceクラス• AbstractTaskを継承した抽象クラス• 入力無し、１出力のブロックを作るのに使う19

その他参考• 独自ブロックの開発方法の概要を説明• 詳細は、以下を参照• readme.html• ブロックリファレンス• メッセージリファレンス• readme_developer.html• 開発環境のセットアップ• 各ブロックのソースファイル

20

HascToolの独自開発（演習）• Filterの作成• 参考：SampleFilter1• SampleFilter1をコピー• 名前を変えて貼り付け• 今回はTestFilter1

21

TestFilterのソースコード

22Filterの編集• processMessage• if (message instanceof VectorSignalMessage)• VectorSignalMesageを入力として受け付ける• double[] newValue =~~• 実際に処理を行っている部分• ベクトルの各要素に0.5をかけて1を加算• outputMessage(~~)• 出力を行っている部分• （）内に出力メッセージを記述

23

Block Class Listの更新• HascToolBeansList.xmlを更新• 実行ファイル
• jp.hasc.hasctool.ui.views.
beanslist.BeansListGenerator• 上記クラスを右クリック＞
Run As＞Run Configurationsを選択• Java Applicationを右クリック＞New• Nameを設定• BeansListGenerator• Run Configurationの設定• Main• Arguments

24

Mainタブ• Main class• jp.hasc.hasctool.ui.views.beanslist.
BeansListGenerator

25

Argumentsタブ• Program Arguments:• -dir クラスファイルのルートディレクトリのパス（HascToolのパス/classes）• -o 出力先xmlファイルのパス（HascToolのパス/HascToolBeansList.xml)• “-dir”と“-o”の間に半角スペース• Applyを選択• Runを実行
26

作成したFilterの使用• Eclipseを再起動• HascToolBeansList.xml更新• HASCToolを実行• HascToolを右クリック＞
Run As> Run Configurations>
HascToolの起動• Block Class List
• 新しいフィルタがリストに追加• 選択するとブロックが生成• HASCXBDファイルの編集27

スマートフォンでのセンシング

iOSのセンサーAPI• Core Motion Framework• iOS 4.0以降用のAPI• 加速度、ジャイロ、磁気• 姿勢（ロール、ピッチ、ヨー） - 複数センサを統合• Core Location Framework• 位置情報、方角（磁気）• UIAccelerometer クラス• 加速度

iOS サンプルコード• Core Motion で加速度を取得する例• 他のセンサの場合も同様
CMMotionManager *manager = [[CMMotionManager alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];// サンプリングレート 100Hz
manager.accelerometerUpdateInterval = 1.0/100;// 加速度取得開始[manager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *data, NSError *error) {// 加速度データを取得した時に呼び出されるブロック
NSLog(@"%f,%f,%f,%f", data.timestamp,
data.acceleration.x, data.acceleration.y, data.acceleration.z);}];

Event Handling Guide for iOS より

AndroidのセンサーAPI• android.hardware パッケージ• SensorManager, Sensor, SensorEventクラス• SensorEventListener インタフェース• 様々な種類のセンサが定義されている• 加速度、ジャイロ、磁気、光、温度、圧力、…

• サンプリングレート（delay）の指定が４段階• FASTEST, GAME, UI, NORMALAndroid サンプルコード• 加速度を取得する例• 他のセンサの場合も同様
protected void onResume() {super.onResume();mManager = (SensorManager)getSystemService(SENSOR_SERVICE);// 加速度センサを取得
mAccelerometer = mManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// FASTESTレートで、加速度センサをサンプリング開始
mManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);}// センサ値が変化した時に呼び出される （SensorEventListenerインタフェース）
public void onSensorChanged(SensorEvent event) {if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {Log.d(“ACC”, event.timestamp +”,”+ event.values[0] +”,”+ event.values[1] +”,”+ event.values[2]);}}Android 補足• 加速度の単位がiOSと異なる• iOSは(G), Androidは(m/s^2)• サンプリングの頻度• 値がある程度変化しないと、onSensorChanged()が呼び出されない• 呼び出される頻度は、機種により異なる• 外部ストレージ（SDカード）への保存が遅い• ログの書き込み速度よりも、加速度データの来る速度のほうが速いことも