Pythonでスペクトログラムからピーク値を任意数抽出する方法

  • このエントリーをはてなブックマークに追加

スペクトログラムは時間×周波数×振幅と数多くの情報を得ることが可能な便利な分析手法です。ここでは信号処理の技術でスペクトログラムのピークを自動検出するPythonコードを紹介します。

こんにちは。wat(@watlablog)です。ここではスペクトログラム(カラーマップ)から任意個数のピークを抽出する方法を紹介します

スペクトログラムの概要とピーク検出方針

スペクトログラムとは?

本記事ではスペクトログラム(Spectrogram)という信号処理分析手法を扱います。

スペクトログラムとは、横軸に時間、縦軸に周波数、奥行き(色成分)に振幅レベルをとったプロットの事で、一度に信号の時間変化、周波数変化、振幅レベル変化を読み取ることができ、特に振動騒音分野で重宝されています(以下に参考図を示します)。

スペクトログラムの説明

スペクトログラムの概要や、Pythonでスペクトログラムをプロットする方法の詳細は「Pythonで音のSTFT計算を自作!スペクトログラム表示する方法」に記載していますので、是非ご覧下さい。

ピーク自動検出のメリット

周波数分析をするとある周波数で卓越するピーク(峰と呼ぶ人も)が出てくる事が多く、このピークの変化を追う事で計測された情報から様々な現象を分析する事が可能です。

当WATLABブログでは「PythonでFFT波形から任意個数のピークを自動検出する方法」で単純な周波数波形からピークを自動検出する方法をPythonコードで書いてみました。

ピーク検出のイメージ

基本的なメリットはこちらの記事で紹介している内容と同じで、ピークを手動で読み取るよりは自動でリスト化してくれた方が生産性が向上するというものです。

しかしながらスペクトログラムは周波数波形の時間変化を表しているため、手動でピークを読み取ろうとするとかなり大変な作業になるはずです。

そこで、本記事では周波数波形だけでなく、スペクトログラムにおいてもピーク自動検出機能を実装してみようと思い書き始めました。

スペクトログラムのピーク検出方針(大きい順に抽出する方法)

ピークを検出する目的は様々ですが、ここではスペクトログラムから大きい順にピークを抽出する方法を考えていきます。

他にも、N番目のピークのみを抽出し、回転パルス無しにトラッキング解析をしたり…とか、ピーク活用は目的に応じて色々ありますね。

既存のピーク検出アルゴリズムを使う

スペクトログラムからピークを検出する…といっても基本的には先に紹介した記事にあるように、既存のピーク検出アルゴリズムをそのまま流用します。

既存のピーク検出アルゴリズム(ここではscipyのargrelmax等)はorderの指定が可能でノイズ対策がとれていたり、任意個数を指定できたり、自分で微分計算から作るとやらなければならない手間を大幅に削減できるというのが最大の理由です。

スペクトログラムは以下の図のように縦方向に時間成分でスライスすれば単一の周波数波形になるので、この形にすることができれば既存のピーク検出アルゴリズムを適用することが可能です。

スペクトログラムからピークを検出する方針

ピーク情報をストックする

単一の周波数波形のみを検出しただけではスペクトログラムのピーク検出をしたとは言えません。

そのため、下図に示すように初期時間\(t_{1}\)から順番に\(t_{2}\)…そして最終時刻\(t_{m}\)までピーク検出を行います。

検出したピークは振幅レベル(Peak), 周波数(Freq), 時間(t)の情報としてそれぞれ2次元配列に格納していきます(下図を参考のこと)。

ピーク情報をストックする

ピーク情報を平坦化する

上記方法でピーク情報をストックしていくと、非常に大量のピークが検出されてしまうことがあります。ピーク検出アルゴリズムは重要なピークのみを抽出する事が必要です。

ここでは振幅レベルでソートできる形にするため、先ほどの2次元配列を平坦化(1次元配列)にする方針をとります(以下参考図)。

ストックしたピーク情報を平坦化する

ソートして任意個数を抽出する

ここまでできれば、あとは振幅レベル(Peak)でソートし、周波数(Freq)、時間(t)情報も並べ替えした指標で抽出してくれば、それぞれの配列の先頭から任意個数を抽出するのは簡単になります。

スペクトログラムからピーク検出するPythonコード

ピーク検出の関数

今回メインとなるスペクトログラムからピークを検出するPythonコードをdef関数として以下に示します。考案したアルゴリズムは上記説明の通りですので、コード内コメントを参照して頂ければおそらく読み解けると思います。

全コード(コピペ用:単一ピークを検出)

以下にコピペしてすぐに動かせるように全コードを示します。.pyファイルのあるディレクトリに「sample.wav」(ここでは5[s]のデータ)というwavファイルを置くことでそのまま動きます。

その他の関数群は「Pythonで音のSTFT計算を自作!スペクトログラム表示する方法」で使っていたものと同じですので、もし詳細で不明な所があればこの記事を参照下さい。

上記コードを実行すると、スペクトログラム内で最も最大振幅となる点を教えてくれます。

グラフとしては以下のようなプロットがでます。

単一ピークの検出

コンソールには以下のようにピーク情報が表示されます。

複数ピークを検出する方法

先ほどは単一のピークでしたが、max_peaksの値を変更することで複数ピークをスペクトログラム全体から振幅レベルの大きい順に検出することが出来ます。

以下はmax_peaks=10, 50の比較です。数値を増やしていけば検出するピークも増えていきます(もしピークが無かった場合のエラー処理は入れていません)。

max_peaksの比較

コンソールには検出したピーク情報が配列で表示されます。

まとめ

本記事では過去に当WATLABブログで紹介したスペクトログラムの概要を再度説明し、スペクトログラムからピークを自動検出することの有用性を紹介しました。

記事の中盤では考案したピーク検出アルゴリズムを図解で説明しました。

最後に考案したアルゴリズムをPythonコード化し、サンプルのwavファイルを使って実際にピーク検出を行い、パラメータ違いで任意個数のピークを検出できることを確認しました。

本ピーク検出アルゴリズムは一例に過ぎません。是非各自の目的に合わせてカスタマイズしてみて下さい(特に当ブログのコードをコピペして使ったり2次利用するのに使用許諾とかは必要ありません)。

スペクトログラムという2次元データから任意個数のピークを抽出することが出来ました!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

SNSでもご購読できます。

コメントを残す

*