赤ちゃんのマジ泣きアナライズ

赤ちゃんがマジ泣きしたときの声が頭にキンキン響くので、
泣き声をスペクトルアナライズしてみた。

昔はMatlabでやっていましたが、
個人だとライセンスが高いのでpythonでやってみました。

取得方法

Macbook airの標準搭載のマイクを利用
python3 pyaudioモジュールでストリーミングを取得
ストリーミングのデータを高速フーリエ変換
pyqtでグラフを高速表示させることで、リアルタイムスペクトルアナライザを実現

スペクトル結果

テレビの砂嵐のとき

赤ちゃんが聞くと泣き止むというアナログテレビの砂嵐音。
この音はホワイトノイズに似ていて各周波数ある程度スペクトルが立っています。
一番高い周波数が1500Hzぐらいなので聞いていても不快感はない。
f:id:cyamax:20170311102336p:plain
横軸:Hz、縦軸:強さ

「shi」のとき

口で「shi」の音を出した時のスペクトル。
この音もホワイトノイズに近いかなと思い測定してみました。
赤ちゃんにこの音を聞かせると落ち着いてくれるので、最近はずっと「しーっ」と言っている。
誰かが「しーっ」と言うと自然と静かになるのは、大人でも子供でも外国でも共通だと信じています。
2500Hzとその倍音の5000Hzにピークがあるようです。
日本語の中でだいぶ高い周波数。※これよりも高い五十音はあるのかな
f:id:cyamax:20170311102342p:plain
横軸:Hz、縦軸:強さ

赤ちゃんのマジ泣きのとき

はい、スペクトルが振り切れました。
音量もすごいですが、高音帯域のスペクトルが高いので耳鳴りのように聞こえる。 f:id:cyamax:20170311102355p:plain
横軸:Hz、縦軸:強さ

まとめ

赤ちゃんの泣き声は高周波満載。
日常会話で使う周波数は250Hz〜4000Hzなので、それと比べるととても高いのがわかる。

感想

マイクデバイスにリアルタイムで処理する方法がわかったので、いろいろ発展したものができそう。 ただグラフはpythonpyqtを使ってみましたが、対数表示にしたかったけどスケール調整の方法がわからなかったので見づらくなってしまった。

学生時代に研究室で教授の話し声がうるさかったので、
マイクから拾った音の逆位相をイヤホンから出し、声を打ち消すノイズキャンセラを作ろうとしたことがありますが、
当時は処理速度が間に合わなくてただイヤホンからも教授の声がする声増幅器になってしまいました。 今のPCスペックならお手製のノイズキャンセラを作ることができるかもしれないですね。

「やっぱりすいかTシャツ」作ってみた

GMOペパボのサービス「suzuri」を使ってTシャツ作ってみた。

suzuri.jp

今年の夏はこれで決まり。

安価なホームルータを高機能ルータに改造する

経緯

Debianの対応アーキテクチャを眺めていたら、様々なCPUに対応していることに気がつく。
無線ルータのCPUアーキテクチャにOSが対応していたらLinuxをインストールできて面白そう。

DD-WRTとは

調べると「DD-WRT」 というものを発見。すでにあるのね。
無線ルータのファームウェアを書き換えることで安価なホームルータも
ハイエンドモデルの機能ができるようです。

DD-Wrtは、ゲートウェイ、無線LANアクセスポイントなどの組み込みシステム用ファームウェアとして開発されているLinuxディストリビューションの一種である。OpenWRTを元にして作られている。組み込みシステムはパソコンとは違い、規格が統一されていないため、各製品毎に対応が図られている。各製品毎の対応状況は、公式サイトの"Router Database"で型番から検索して確認することが出来る。家庭用ルーターの非公式ファームウェアの中では最も有名である。

DD-WRT - Wikipediaより

DD-WRT公式ページ

dd-wrt.com

どんなことができるのか

以下のページにまとまっていますが、
・OpenVPNサーバ
・イーサネットコンバータ
・DDNS
・VLAN
などなど

DD-WRTとは何ですか? - DD-WRT Wiki

8年前に3000円で買った眠ってたバッファロールータが超高機能になりそうな予感。

ファームウェアを書換える

やり方はルータによって異なる&調べたら色々出てくるので割愛しますが、
バッファロー製ルータなどがやりやすいようです。

私のバッファロールータ(WHR-HP-GN)はDD-WRTからファームウェアをダウンロードして、
既存の設定ページからファームウェアのデータを上書きするだけでできました。

注意

ダウンロードしたファームウェアを適応すると初期設定では出力電波が最大になっています。
日本では電波法違反になったりと色々注意することがあるので、ちゃんと調べてから実施しましょう。

やったこと

公式ページで自分のルータを検索してダウンロード

既存のバッファロールータの管理画面

ファームウェア更新画面でダウンロードしたファームウェアを選択

再起動後、無線が繋がらなくなる。
そして知らないdd-wrtというSSIDが鍵なしで出てきた。

デフォルトで192.168.1.1.にアクセス。 先ほどとは違う管理画面が出てくる。

日本語化や電波強度など設定を終えて、接続してみる。
元々ssh、telnetできないルータだったのでこれだけでも面白い。
ルータなのでメモリや容量は小さめ。

CPUを確認してみる。

cat /proc/cpuinfo

最近のルータはMIPSのSoC(System on Chip)構成が多いようです。
SoC構成だと汎用的なCPUが使われることが多いのかな?
Linuxがインストールできるものが増えてきそうですね。

RaspberryPiで家の騒音をグラフ化

赤ちゃんがいつ泣いているのかログを取りたい

f:id:cyamax:20170309173036j:plain 1日何時間泣いているのかや、
何時頃に泣くなど傾向がわかったら面白そうなのでやってみました。

用意するもの

  • RaspberryPi 2 or 3
  • USBマイク

環境準備

Elasticsearch×kibana×Fluentdのインストール

グラフ化するために以下環境を用意します cyamax.hateblo.jp

Python3のインストール

Pythonは2系と3系がありますが、今後主流になっていく3系を使います。
普通はpyenvやvenvを挟んで環境を切り替えることが多いですが、
RaspberryPi上だとうまくできなかったので、 シンプルに直接Python3系とモジュールをインストールします。

$ sudo apt-get install python3 python3-numpy python3-pyaudio

マイクデバイスの認識

こちらのサイトにマイクデバイスの設定方法が書いてあるので、参考にさせていただきました。 karaage.hatenadiary.jp

設定後以下のようにUSBデバイスが優先されていればOKだとおもいます

$ cat /proc/asound/modules
0 snd_usb_audio
1 snd_bcm2835

マイクのサンプリング周波数を確認

マイクから信号を受け取りにあたりサンプリング周波数を設定する必要があります。
マイクに合った設定をしないとエラーが出て取得できません。
サンプリング周波数はUSBマイクを一度Macに挿して
システム情報->ハードウェア->オーディオ->デバイス
USB PnP Sound Deviceの欄で確認できました。
Windowsの場合は試していませんがデバイスマネージャなどから確認できるかもしれません f:id:cyamax:20170308215921p:plain

騒音をログ化する

動作のながれ

  1. マイクからのストリーミングデータをCHUNK分(1024*2)ずつ抜き出してその中で最大振幅を配列max_dataに入れる。
  2. Thredingを使って指定時間ごとに割り込み処理(sendlog)を実行
  3. 割り込み処理では配列max_dataの平均値を計算してFluentdに送り、max_dataを初期化

Pythonでの割り込み処理はThredingモジュールで実装
Fluentdへはsubprocessでechoを使って実装

コード

# -*- coding:utf-8 -*-

import pyaudio
import numpy as np
import threading
import subprocess

max_data=[]
CHUNK=1024*2 # マイクによって変わる。上手くいかない場合色々試してください
RATE=48000 # 事前に確認したサンプリング周波数
p=pyaudio.PyAudio()

stream=p.open(format = pyaudio.paInt16,
        channels = 1,
        rate = RATE,
        frames_per_buffer = CHUNK,
        input = True,
        output = True)

def audio_trans(input):
    frames=(np.frombuffer(input,dtype="int16"))
    max_data.append(max(frames))
    return

def sendlog(): # 定期的に呼び出される
    global max_data
    if len(max_data) != 0: # 初回実行時だけ無視
        mic_ave=int(sum(max_data)/len(max_data)) # 60秒間のマイク受信音量の平均値を出す
        max_data=[]
        #print("スレッドの数: " + str(threading.activeCount())+threading.currentThread().getName()) #Thredingでプロセスが乱立しないかチェック用
        ## fluentdに最大音量値を渡す
        json = '{'+'\"mic_max\":{0}'.format(mic_ave)+'}'
        cmd = "echo '" + json + "' | /usr/local/bin/fluent-cat log.hoge"
        try:
            print (cmd)
            res = subprocess.check_call(cmd, shell=True )
        except:
            print ("error")
    t=threading.Timer(60,sendlog) #60秒ごとにsendlogを実行
    t.start()

t=threading.Thread(target=sendlog)
t.start()

print ("mic on")

while stream.is_active():
    input = stream.read(CHUNK)
    input = audio_trans(input)

stream.stop_stream()
stream.close()
p.terminate()

print ("Stop Streaming")

実行結果

f:id:cyamax:20170308230824p:plain 1、2時間ごと夜泣きをしてそのタイミングでグラフが上昇。
朝方を過ぎた頃に子供を移動させたのとテレビをつけたので全体的に平坦になっているわかる。

感想

マイクの受信感度やメモリ管理などまだまだ調整する箇所はありますが、
やりたいことはできた感じ。
マイクはベビーベッドに設置してましたが、
泣いたタイミングで抱っこして違う部屋であやしたりしていたので、
数値の大きさはあまり当てにならない結果になってしまいました。
※上昇タイミングだけ意味のあるデータとなった

参考サイト

Raspberry Pi 2で音声認識・音声合成してみる - karaage. [からあげ]
PyAudioの基本メモ2 音声入出力 - たけし備忘録
python - Pythonのthreading.Timerで定期的に処理を呼び出すサンプル - スタック・オーバーフロー

RaspberryPiのCPU温度、電圧、クロック数をElasticsearchに送ってグラフ化

ログの可視化

せっかくelasticsearch×kibana×fluentdの環境を構築したので、
データを入れていきます。

準備

以下の手順で環境を準備します。 cyamax.hateblo.jp

CPU温度、電圧、クロック数の取得

以下の公式?サイトに載っていました。 RPI vcgencmd usage - eLinux.org

##CPU温度
vcgencmd measure_temp
##電圧
vcgencmd measure_volts
##クロック数
vcgencmd measure_clock arm

ただしこのままではグラフ化できません。 Elasticsearch側に送る必要があります。

JSONに整形

以下のスクリプトで取得したデータを整形&Elastisearchに送信をします。
crontabなどで5分ごとの定期実行させると良い感じになります。

#!/bin/bash
#raspberryPiの情報をjsonに整形する
##CPU温度
ras_temp=`vcgencmd measure_temp      |sed -e "s/temp=//" -e "s/'C//"`
##電圧
ras_volt=`vcgencmd measure_volts     |sed -e "s/volt=//" -e "s/V//"`
##クロック数
ras_freq=`vcgencmd measure_clock arm |sed -e "s/frequency(45)=//"`

#echo $ras_temp
#echo $ras_volt
#echo $ras_freq

json_date={\"ras_temp\":$ras_temp,\"ras_volt\":$ras_volt,\"ras_freq\":$ras_freq}

echo $json_date |/usr/local/bin/fluent-cat log.hoge

kibanaを見てみる

crontabで実行するごとにデータが送られて、
以下のようにkibana側で見ることができました。 f:id:cyamax:20170308040522p:plain

電圧・クロック数が動的に変化

グラフ化して初めて知ったのですが、
RaspberryPiは入力電圧によって動作クロックが変わるようです。

私の環境ではRaspberryPiに繋いでいるUSBアダプタはiPhone用の1Aアダプタを使用し、
USBケーブルは60cmほどの長めのものを使っているので、
電圧が不安定になってしまっているのだと思います。
f:id:cyamax:20170308041814p:plain 電圧とクロックが上下していることがわかります

まとめ

RaspberryPi上でデータ収集&グラフ化までできるようになりました。
次は別センサのデータを集めてみようと思います。

参考

RPI vcgencmd usage - eLinux.org

RaspberryPiでログの見える化するよ(Elasticsearch×kibana×Fluentd)

自宅簡易サーバにRaspberryPi

RaspberryPiで収集したデータを見える化したいけど、
外部のサーバやサービスを借りるとお金かかるし、
家に本格的なサーバを立てても設備代や電気代かかる・・・。
そもそも手軽に使えたら何でも良いんだけどと思い、
そのままRaspberryPi内でログ見える化の環境を構築しました。

完成図

Elasticsearch×kibana×Fluentd で構築します。 こんな感じに様々なデータが簡単にグラフ化できました。 f:id:cyamax:20170308021150p:plain

用意したもの

RaspberryPi 2(Raspbian Jessie with PIXEL)
※ネットワークへの接続やapt-get updateなど最低限のセッティングは完了しているものとする

注意

RaspberryPiはそのコンセプトから安定稼働する作りではありません。
ちょっとした学習や研究用にサーバを立てたいときは便利ですが、
中期以上の継続的な稼働が必要な場合はちゃんとサーバを用意しましょう。

Elasticsearch

Javaの確認

OSがRaspbian Jessieであれば、Javaがインストールされているはずですが一応確認。

$ java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) Client VM (build 25.65-b01, mixed mode)

バージョン1.8以上が必要なので、古ければアップデートしましょう。

Elasticsearchのインストー

Elasticsearchとkibanaはバージョンの組み合わせによっては動かないことがあるようなので、
今回は動作が確認されている以下バージョンでやります。

  • Elasticsearch 2.4.1
  • kibana 4.6.2

以下コマンドで、Elasticsearchの公式HPからzipをダウンロードし、
ディレクトリに展開していきます。

$ wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/zip/elasticsearch/2.4.1/elasticsearch-2.4.1.zip
$ unzip elasticsearch-2.4.1.zip
$ rm elasticsearch-2.4.1.zip
$ mv elasticsearch-2.4.1 elasticsearch
$ cd elasticsearch
$ ./bin/elasticsearch

起動確認は以下コマンド。
curlすると返ってきます。

$ curl -XGET http://localhost:9200/
{
  "name" : "Micro",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "",
  "version" : {
    "number" : "2.4.1",
    "build_hash" : "",
    "build_timestamp" : "2016-09-27T18:57:55Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.2"
  },
  "tagline" : "You Know, for Search"
}

kibana

同様にkibana(4.6.2)を公式ページからダウンロードします。
以下URLからRaspberry Piのバージョンに合わせてダウンロードしてください。
RaspberryPi 2の場合:LINUX 32-BIT
RaspberryPi 3の場合:LINUX 64-BIT
https://www.elastic.co/downloads/past-releases/kibana-4-6-2

以下wgetコマンドはRaspberryPi2(32bit版)の場合

$ wget https://download.elastic.co/kibana/kibana/kibana-4.6.2-linux-x86.tar.gz
$ tar xvfz kibana-4.6.2-linux-x86.tar.gz
$ rm kibana-4.6.2-linux-x86.tar.gz
$ mv kibana-4.6.2-linux-x86 kibana
$ cd kibana
$ ./bin/kibana

しかし実行するとエラーが出ます。

./kibana/bin/../node/bin/node: 1: ./kibana/bin/../node/bin/node: Syntax error: "(" unexpected

これはダウンロードしたkibanaのファイルがRaspberryPiのCPU(ARM)アーキテクチャではないためです。
エラーが出るnodeとnpmをRaspberryPiのものに変更してあげます。
※kibanaのダウンロードページでDEBのパッケージもダウンロードできますが、
これも中身がi386アーキテクチャ用なのでdpkgでインストールできません。

$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb
$ sudo apt-get remove npm node
$ sudo dpkg -i node_latest_armhf.deb
$ rm node_latest_armhf.deb
$ cd kibana/node/bin
$ mv node node.orig
$ mv npm npm.orig
$ ln -s `which node` node
$ ln -s `which npm` npm
$ cd ../../
$ ./bin/kibana

これでhttp://localhost:5601にアクセスするとkibanaのページが表示されます。

fluentd

fluentdはelasticsearchにデータを集めるために使用します。

fluentdのインストー

# インストールから設定まで
$ sudo apt-get install gem
$ sudo gem install fluentd --no-ri --no-rdoc
$ sudo fluent-gem install fluent-plugin-elasticsearch
$ fluentd --setup ./fluent

# 起動とテスト
$ fluentd -c ./fluent/fluent.conf -vv &
$ echo '{"json":"message"}' | fluent-cat debug.test

debug.test: {“json”:“message”} OKのような応答があれば初期設定は完了です。

fluentdの設定ファイル

fluentdに来たログをElasticsearchに飛ばす設定をします。
※fluentdを理解していないので、動作はしますが適切でない可能性が高いです。参考程度に見てください。

vim ~/fluent/fluent.conf

するとデフォルトの設定値が書いてありますが、
それを以下の内容にしてElasticsearchに飛ぶようにします。

<source>
    type forward
</source>

<match log.**>
    @type elasticsearch
    host localhost
    port 9200
    type_name raps
    logstash_format true
</match>

この設定を保存してfluentdを再起動するとfluentd→elasticsearchにデータが飛ぶようになりました。

ログは以下のように書くと飛ばせます。

echo '{"status":"OK"}' |/usr/local/bin/fluent-cat log.hoge

まとめ

今回はRaspberryPiにElasticsearch×kibana×Fluentdを入れてログの見える化をしました。
ただラズパイは安定稼働しないので限定的な用途に限られると思いますが、それでも簡単に自宅サーバが作れるのは便利です。

次回は
RaspberryPiのCPU温度、電圧、クロック数をElasticsearchに送る方法と
Supervisorを用いたデーモン化をやります。

cyamax.hateblo.jp

参考

参考にさせていただきました。ありがとうございます。
Raspberry Pi 3にElasticsearchとKibanaをいれてみた - johshisha’s diary
ElasticSearchの良く使うcurlコマンドまとめ - サナギわさわさ.json
Elasticsearch触ってみた。 - Qiita
fluentd最低限のメモ - Qiita

赤外線カメラのケースが高いから夜中にひっそりと自作する

子供が生まれてから、育児休暇を1ヶ月頂いたのですが、
1日の行動パターンが
「ミルクを飲ませる」「オムツを替える」「ご飯を作る」「沐浴をする」「泣き止ます」のどれかになってきました。
FFでももうちょっと技の種類あるよね。

オムツについてはだいぶ替え慣れたので、もう少しで「オムツァ」から「オムツラ」になれそうです。

子育てを楽にしたい

育児休暇を1ヶ月頂きました。 育児だけやっていてはもったいない&脳みそのシワが取れそうなので、
育児の問題をエンジニア視点から解決できないかと考えてみました。

ただし作業できるのは子供も妻も寝静まった深夜のみ。

赤外線カメラの購入

どう使うかはまた別の記事で書くとして、たまたま寄ったマルツ電波に売っていたので購入しました。
amazonで売り切れでもマルツではよく売っています。

rasberry pi用のsony製カメラ。
HD画質で写真・動画が撮影可能。また、赤外線フィルタも外してあるので、工夫をすれば色々使える。

ケースが高い

f:id:cyamax:20170220030251j:plain カメラが手に入ったのは良かったものの、ケースがないと心もとない。
だけどちゃんとしたケースが高い。私にはこれに2500円かける財力はなかった。

ならば自作だ

色々ケースになりそうなものを探すとちょうど良いものがありました。

SDカードケース f:id:cyamax:20170220024648j:plain

あとはいい感じに適当にやるだけ

f:id:cyamax:20170220024813j:plain 加工したところが分かりやすいようにマジックで塗りました。
ドリルがないのでカッターやドライバーやハサミでガリガリやりました。
レンズ部分が相当雑ですが、初号機なので気にしない。
ドリル欲しい。

完成

f:id:cyamax:20170220024907j:plainf:id:cyamax:20170220030304j:plainf:id:cyamax:20170220025627j:plain

とりあえず、なんとなくいい感じになりました。
写真が全部薄暗いのは、起こさないようにひっそりとやっているから。

これで色々やるぞい。😉

HappyHackingKeyboard ProfessionalJP of Bluetooth by Arduino

一年ぐらい前にHappyHacking Pro JPを買って、その使い心地に酔倒していました。

ただ私はこのキーボードには唯一にして最大の不満点があり、それは有線モデルしかないということでした。

無線がなければ作れば良い

ここからキーボードを無線にするべく勉強と研究がスタートしました。

すでにHappyHacking Proを無線化している強者がネットでソースコードを公開してくれていましたが、
それはUSキーボード版のコードであり、JP版はキーボード数や仕組みが違うため、
駆動の仕組みやコードの書き換えをやる必要がありました。

また一番の問題はJPモデルは中身がパンパンで基盤やバッテリーを詰め込む隙間がなかったため、
配線やモジュールの選定も考えて実装する必要がありました。

そして初号機の完成


HappyHackingKeyboard ProfessionalJP of Bluetooth by Arduino

開発を始めて4ヶ月(2015/12~2016/4)。勉強と試行錯誤を繰り返し、とうとう無線化に成功しました。

動画では分かりづらいですが、キーボード->Arduino->Bluetoothモジュールの順番で配線され、
キーを打つとパソコンに文字が打てていることがわかります。
※カメラを持ちながら片手でキーを打っているのでタイピングが遅いですが、遅延を感じることなく使えます

挫折、そして伝説へ。

初号機が完成し、あとは小型のArduinoに配線し本体に収めれば完成。
運よく小型バッテリーも購入でき(ネットでは手に入らないサイズを偶然マルツ電波で見つけた)、
小型Arduino用のビルドもできた(サードパーティ製の小型基盤のため、正規のArduinoで動いてもこれだと動かないことがある)。

回路を書いて半田付けをし、いざ本体に入れると微妙に入らない・・・。
適当に選定したスイッチとバッテリーからの電源を3.3Vに変換する3端子レギュレータ周りの回路が内部でぶつかっている。
でもこの部分ならいくらでも小型のパーツ売っているし、すぐにできそうだ。手元にパーツがないから今度の土日に買いに行ったら完成だな。
今日は疲れたから終わりにしよう。

そしてこれ最後に微妙にモチベーションが上がらず開発がストップすることになる。
これは私の悪い癖で、メインの開発が終わると途端にやる気が出なくなる。

数週間後、こんなものが発売される。

嘘だろ・・・。

結局意味なかったのか

そんなことは思わない。無線化するために得た知識は今後またどこかで役に立つ気がする。
どんな風にBluetoothが裏で動いているのか、どのくらい電力を消費するのか、キーボードはどうやって動いているのか。
流行りの小型電子デバイスはどう使えばいいのか。
この辺が理解できただけでも大きな報酬かと思う。

あと公式のHHKBのBT版はデザインがなんかダサい。そこが唯一の救い。

pythonでランダムな英単語を取得したい

pythonで意味のあるランダムな単語が複数必要になった。

意味のない単語であればランダムに文字を並べればできるが、 意味のある単語はそうはいかない。

初めはネットからスクレイピングして都度持って来ればいいかなと思ったけど、スマートじゃない。

なんかいい方法ないかなと考えたら、思いついた。

linuxの辞書ファイルを利用する

linuxには辞書ファイルがあるので、そこからランダムに単語を抽出すれば良さそう。

Macの場合、辞書ファイルは以下にある

/usr/share/dict/words
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random

#辞書ファイルを読み込ませる
f =open ('/usr/share/dict/words','r')
lines=f.readlines()
f.close()

for i in range(35):
    #単語の最後に改行が入ってしまうので、replaceで置換
    input_word= lines[random.randint(1,len(lines)-1)].replace('¥r','')
    print(input_word)

f:id:cyamax:20170204111040p:plain

linuxでパスワードを変更するときに、 「辞書にあるからこのパスワードは使えませんよ」と注意されるときがありますが、 どうやらこのファイルと比較して見ているらしい。

単語数も23万5886単語もあるようなのでとりあえずこれで大丈夫。

ただ、pythonのモジュールとか使ったらもっと良い方法はありそう。

AmazonDushとどいたー

f:id:cyamax:20170202211818j:image

二つ購入しました。

 

電源とか考えるとBluetoothLowEnergyとか使って親機経由かなって思ったら違った。

 

直接wifiに繋げるらしい。これは凄い。

これが500円なのが凄い。

 

改造できるのは来月かな。