kerasを使ってT-fal のお湯の温度を測ってみる(音声→温度)

# お湯の温度が測りたい！！

**はつ雪に　白湯すゝりても　我家哉**　～小林一茶～

　この句がいつも身に沁みるくらい私は白湯が好きである。
　現代生活でお湯を沸かすとなるならば当然、瞬間湯沸し器になるだろう。我が家にはT-falがある。しかしながら、湯沸し器の欠点として100℃の沸点まで加熱してしまうことが挙げられる。私のような白湯好きや緑茶にこだわる人には80℃程度のお湯が好ましいのであるが、そうはいかない。水で薄めるのもばからしい。  

　結果として「お、そろそろいい感じの温度だな！」と耳で判断してT-falを止める。  
  
<font color="red">**　あれ、これ別に人間がやらなくてもよくない！？** </font>

# というわけで機械にやらせたい
　環境はWindows10、Anaconda+Jupyternotebook、Tensorflow+kerasといった感じ。

　[リポジトリはここ](https://github.com/ac-yasushi/measure_temp_Tfal)

　私は現在機械学習初心者の初心者くらいで、ちょうどkerasの勉強中であったのでT-falから出る音を録音してFFTでスペクトル分解。それをkerasで組んだモデルで学習させて様子を見ようという考えである。
　本当は先行事例があるか調べると良かったのだが、特にしていない。  

　この方法、実際大なり小なり化学的には面白い利点があるので紹介しよう。

- 温度計を水に突っ込む必要がないのでコンタミが起きない
- 温度を測るために中身を取り出す必要がない
- 温度計自体の熱容量が影響することがない
- 音声スペクトル分解が普通の温度計の原理に比べて早いので測定がリアルタイムである

　まとめるなら、非破壊式リアルタイムT-fal温度測定器となるわけである。

## 実験準備(学習・予測データの収集)

<img src="https://qiita-image-store.s3.amazonaws.com/0/371781/557d6f0b-b27f-e320-06d8-66961b75de4f.jpeg" width=70%>  

　道具は3つ。T-fal、USBマイク、アルコール温度計。余計なお金はかけたくないので極力家にあるものでやった。アルコール温度計は500円もしない。  

　しかし、アルコール温度計。温度計自体の熱容量もあるし、遅延もあるし、説明書を見たら±1℃が精度らしいので、既に誤差がすごい。
　ちなみに、このアルコール温度計も音声による温度測定も測定の原理は変わらない。温度という物理量を別の物理量に変換しているわけであるから。アルコール温度計では温度がアルコールの熱膨張率に作用して体積に変換され、それが校正されたガラス管の中を昇って値を示すだけである。赤外線温度計なら物質の温度による輻射の電磁波を校正して温度に変換しているわけである。他にはサーミスタなどが温度を電気抵抗に変換できるので温度計に利用できる。  
　ここではその**"校正"**部分を機械学習という形で直接連続値として出力しようというものである。

---
実験条件は以下の通り。  

1. 1.0Lの水道水で満たしたT-falの1, 2, 3, 4, 5minごとの温度をそれぞれ測定する。(1min測定したサンプル(水道水)は捨てる。測定温度を正確にするため連続では測定しない)
2. マイクは位置が可変なので、T-falから距離4㎝のところに収音部分を水平にして高さ15㎝を保って設置した。また、T-falの音声取得方向を揃えるためにT-falのスイッチランプのある部分とマイクの首が同一直線状になるように位置を決めた。
3. T-falのスイッチONと同時に録音プログラムを起動、所定の時間経過後に3秒間の録音を行ったあとにすぐにT-falをOFFにしてアルコール温度計で温度を測定する。この時の温度と音声を1セットの学習データとする。
4. 結果をエクセルシートでまとめて一旦時間と温度変化の関係を考察する。

##実験結果

　結果として26セットの学習データと4セットの予測データを集めた。正直、手順が面倒くさいのと冬場に集めたので寒くてこれ以上集めたくなかった。(本音)
  
　これをいったんExcelでグラフにしたのが以下である。
<img src="https://qiita-image-store.s3.amazonaws.com/0/371781/b0d3efba-203b-7151-1a5c-be844f5a5176.png" width=70%>
　一定の電力が水を温めているので(水の熱容量がほぼ一定より)結果は温度変化は直線になった。実際、人力で80℃付近を見極めるのは難しかったので、右上がりの曲線かと思ったがそうでもなかった。低温域が外れているのは加熱部の熱容量分のロス、高温域が外れるのは蒸発により潜熱が奪われることとアルコール温度計の測定の遅さが影響していると思われる。
  
　時間と温度の関係は以上のようになったが、このデータから温度を推算するにはスイッチがONになった時間を記録しないといけないので厳密にはリアルタイムとは言えない。
　**そこで周波数スペクトル⇒温度の機械学習をやるわけである。**(曲線ならもっと面白かったのに……)

# FFTによるスペクトル分解
　拙者化学系につきFFTは全く分からない侍でござる。
　実際、フーリエ変換に関しては熱伝導方程式の解析解の導出や不連続波形の近似などの側面では利用したことがあるが、情報系における高速フーリエ変換は全く分からないので最低限の情報を仕入れる。
  
　結果として4096点に周波数を分解し、3秒間の音声データから等間隔に10点を取り平均を取ることにした。0～22050Hzの範囲内にある点をすべて利用することにした。またノイズに近い弱い振幅の音声を正規分布で取り除こうかと思ったが、それも見送ってとりあえず生データで学習させる。
  
　また、waveファイル録音とFFTのプログラムはこちらをほとんど参考にさせて頂いた。
  
[【Python】マイクの音を録音してwaveファイルに保存](https://algorithm.joho.info/programming/python/pyaudio-record/)
[【Python】WAVファイルの波形データにFFTかけて周波数スペクトルを複数表示する【サウンドプログラミング】](http://tacky0612.hatenablog.com/entry/2017/12/12/174405)

　こちらの記事も分かりやすかった。

[【NumPy】高速フーリエ変換 （FFT）で振幅スペクトルを計算](https://algorithm.joho.info/programming/python/numpy-fast-fourier-transform/)
[FFTとは何か、フーリエ変換との関連と絶対抑えるべき注意点](https://www.hellocybernetics.tech/entry/2017/03/22/043855)

　上記のページでは素晴らしいコードを書かれているので参考になった。私の場合、化学実験のノリで音声のファイル名を分かりやすくしたらデータ格納項が汚くなった。

# 学習モデル
　FFTのスペクトルデータと実測の温度をデータとして保存して、これを学習データとしてモデルを構築する。コード全文はGitHubを見てもらうとして、モデルの構造と学習周りのコードは以下の通り。

```Python:data_analysis_by_keras_Sequential.ipynb

model=keras.Sequential([
    keras.layers.Dense(4096, activation=tf.nn.relu, input_dim=4096),
    keras.layers.Dense(512, activation=tf.nn.relu),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dense(1)
])


optimizer = tf.train.AdamOptimizer()
 
model.compile(loss='mse',
            optimizer=optimizer,
            metrics=['mae'])


model.fit(sound_data, temp_data, epochs=80, batch_size=20, callbacks=None)
```

　ぶっちゃけ、わからない。
　勘で作った学習モデルである。レイヤー数が4なのは、T-falのお湯が沸くときに沸騰が近くなるほど音が大きく、音が低くなるからで、このような特徴があるならレイヤー数は少なくてもパターンを認識するだろう程度に考えて作った。  

　一応、活性化関数をsigmoidにしたりしたが、-300℃というすごい結果が出てしまった。機械学習って不思議。と、思ったが、人間でも-273.15℃が温度の下限界だと知っている人はそこまでいないので、そう考えると機械も人間もそう大差がない中で人間は80℃あたりだろうと推論を下すわけだから人間はすごい。

## 学習結果
　本当はlossとaccuracyの値をグラフで描画すべきだが、その辺をまだ作ってないので結果だけ見て妥当性を検討している。このあたりは今後整備するとして、今回は結果だけ明示する。

|time [min]|Temperature [℃]|prediction [℃]|error [%]|
|--:|--:|--:|--:|
|1|33.0|27.7|-16.0|
|2|49.8|56.5|13.4|
|3|67.0|67.6|0.9|
|4|82.1|85.9|4.6|

<img src="https://qiita-image-store.s3.amazonaws.com/0/371781/bcb8b60e-ebf8-9498-1fd6-19fb6806162a.png" width=70%>

　まあいい結果、なのだろうか？ 短時間加熱での温度誤差が少し大きいが、ターゲットの70～80℃がうまくいっている。

# 結論

　kerasのsequentialモデルを用いてT-falの録音音声の周波数スペクトルから温度を推測した。一応結果として近い値が出たので可能であると判断し、さらに工夫を重ねてみる。

- モデルの改良と各種指標の理解(まだkerasがよく分からん)
- loss等の学習成果の可視化。これはどこにでも資料があるのでうまくいきそう
- 最終的にリアルタイムで音声を取得して記憶したモデルに放り込むだけでリアルタイムで温度が表示されるようにしたい

　季節による初期の水道水の温度変化で学習したモデルがうまくいかなく可能性があるが、前述のようにT-falの温度変化が電力依存で直線的なら±10℃もない季節の温度変動は問題にならないはず。
  
　それより問題なのが、T-falを1L以外の容量で沸かした場合、周波数スペクトルが変化することは大いにあり得るのでそこは追加で容量と温度の2つを推定させるか、1Lでしか使えないかと割り切るしかない。

# 感想
　今回、テキトーに思いついてやってみたらできただけの本物の初心者なので、何かアドバイスやおすすめの書籍があれば教えてくれると嬉しいです。