DigitalFilter-Butterworth-Chebycheff

はじめに

C++言語にてデジタルフィルタを作成した。
WAVEファイルを読み込んで、デジタルフィルタに通すようにした。
作成したフィルタは以下。

  • Butterworth
  • Chebycheff

GitHubのリポジトリと全ソースコードのダウンロードは以下URLから行える。


UML

クラス図とシーケンス図を作成した。
以下からダウンロード可能。

UMLの作成には無償のUMLモデリングツールastah communityを使用している。

クラスやメソッドの説明はdoxygenで生成した。


ビルド


コマンド

Unix系のOSでビルドするのを想定している。

以下コマンドが必要。

g++
make

make

zipファイルを解凍

コマンドラインからカレントディレクトリの移動

makeを実行

%unzip DigitalFilter-master.zip
%cd ./source
%make

実行ファイル生成

以下の実行ファイルが出来上がる。

myfilter

使用方法

使用方法は以下を参照。

%./myfilter [WAVEファイル名] [フィルタ種類]  

フィルタ種類は以下の数値を指定する。

  • 0 : Butterworth ローパスフィルタ
  • 1 : Butterworth バンドパスフィルタ
  • 2 : Butterworth ハイパスフィルタ
  • 3 : Chebycheff ローパスフィルタ
  • 4 : Chebycheff バンドパスフィルタ
  • 5 : Chebycheff ハイパスフィルタ

設定ファイル

各フィルタの設定値は以下のファイルに記載されている。

./config/ButterworthLowPassFilter.conf
./config/ButterworthBandPassFilter.conf
./config/ButterworthHighPassFilter.conf
./config/ChebycheffLowPassFilter.conf
./config/ChebycheffBandPassFilter.conf
./config/ChebycheffHighPassFilter.conf

Butterworthフィルタ

ホワイトノイズをButterworthフィルタに通した結果を周波数解析した。

ローパスフィルタ

設定

Butterworthローパスフィルタの設定値は、以下のファイルから読み込む。

./config/ButterworthLowPassFilter.conf

フィルタの設定は、デフォルトでは以下のようにした。

  • カットオフ周波数: 400[Hz]
  • 1オクターブの減衰率: -48[db/oct]

Butterworth Low-pass -48dB/oct

バンドパスフィルタ

設定

Butterworthバンドパスフィルタの設定値は、以下のファイルから読み込む。

./config/ButterworthBandPassFilter.conf

フィルタの設定は、デフォルトでは以下のようにした。

  • カットオフ周波数: 400[Hz]
  • カットオフ周波数: 2000[Hz]
  • 1オクターブの減衰率: -48[db/oct]

Butterworth Band-pass -48dB/oct

ハイパスフィルタ

設定

Butterworthハイパスフィルタの設定値は、以下のファイルから読み込む。

./config/ButterworthHighPassFilter.conf

フィルタの設定は、デフォルトでは以下のようにした。

  • カットオフ周波数: 2000[Hz]
  • 1オクターブの減衰率: -48[db/oct]

Butterworth High-pass -48dB/oct


Chebycheffフィルタ

ホワイトノイズをButterworthフィルタに通した結果を周波数解析した。

ローパスフィルタ

設定

Chebycheffローパスフィルタの設定値は、以下のファイルから読み込む。

./config/ChebycheffLowPassFilter.conf

フィルタの設定は、デフォルトでは以下のようにした。

  • カットオフ周波数: 400[Hz]
  • 1オクターブの減衰率: -48[db/oct]

Chebycheff Low-pass -48dB/oct

バンドパスフィルタ

設定

Chebycheffバンドパスフィルタの設定値は、以下のファイルから読み込む。

./config/ChebycheffBandPassFilter.conf

フィルタの設定は、デフォルトでは以下のようにした。

  • カットオフ周波数: 400[Hz]
  • カットオフ周波数: 2000[Hz]
  • 1オクターブの減衰率: -48[db/oct]

Chebycheff Band-pass -48dB/oct

ハイパスフィルタ

設定

Chebycheffハイパスフィルタの設定値は、以下のファイルから読み込む。

./config/ChebycheffHighPassFilter.conf

フィルタの設定は、デフォルトでは以下のようにした。

  • カットオフ周波数: 2000[Hz]
  • 1オクターブの減衰率: -48[db/oct]

Chebycheff High-pass -48dB/oct


参考情報

ホワイトノイズ

ホワイトノイズを周波数解析した。
ホワイトノイズは全ての周波数に対して同じ強度となる性質を持っている。
その為、ホワイトノイズをフィルタに通すことによって、フィルタの性能を確認することができる。
whitenoise

ホワイトノイズのファイルは、以下のサイトから借用した。
High Quality White Noise | Play & Download .wav .mp3 Audio Files

周波数解析

周波数解析には音声編集ソフトWavePadというアプリケーションを利用した。
以下のサイトからダウンローが可能。
WavePad 音声編集ソフト

デジタルフィルタ

サイト

デジタルフィルタに関しては以下サイトの実用ディジタル信号処理講座 第3章 デジタルフィルタの基礎を参考にした。
音響情報研究室

書籍

以下の書籍を参考にした。
「デジタルフィルタ (ビギナーズ)」 中村 尚五 (著)

ライフゲーム(C++版)

C++にてライフゲームを作成した。
全ソースのダウンロード

ビルド方法

Unix系OSにてビルドすることを想定している。
以下のコマンドが必要。

  • g++
  • make

以下コマンドを実行することによってビルド可能。

%cd ./LifeGame/C++/source  
%make 

ビルドが成功すると以下のバイナリファイルが出来上がる。

  • LifeGame

実行方法

コマンドラインから以下を実行する。

%./LifeGame

実行すると以下のような画面となる。  
ライフゲーム実行

このLifeGameはcursesを利用している。
このLifeGame内でのコマンドを以下に示す。

q: LifeGame終了
s: LifeGameスタート
p: LifeGame一時停止
i: セルの生死を設定(LifeGame一時停止状態の場合有効)
k: カーソルを上へ移動
j: カーソルを下へ移動
h: カーソルを左へ移動
l: カーソルを右へ移動

※カーソルの移動はviと同じ

プログラムソース

このプログラムはデザインパターンのオブザーバーパターンを利用している。
doxygenにてプログラムソース内のコメントからドキュメントを作成した。

UML

クラス図とシーケンス図を作成した。

UML作成にはastah* communityを利用した。

オブザーバーパターン(デザインパターン)適用例

オブザーバーパターン適用例(TinyClock GUI版)

概要

  • デザインパターンのオブザーバーパターンを時計アプリへの適用例をPythonコードで示す。
  • デジタル時計とアナログ時計を表示するアプリを作成した。 GUIで表示することとする。
  • このアプリをTinyClockと呼ぶこととする。
  • TinyClockはMVC(Model-View-Controller)で作成することとする。(実際にはModel-View)

実行

実行方法

  • 実行方法は、コマンドラインから以下を実行。
    • %python TinyClockMain_gui.py

実行イメージ

  • TinyClockMain_guiを実行すると以下のように表示される。
    TinyClock(GUI版)実行イメージ

TinyClock(GUI版) Python全ソースコード

以下URLに全ソースコードを保存している。
TinyClock(GUI版)

ディレクトリ構成

ソースコードのディレクトリ構成を以下に示す。

.
└── sources // ソースコードファイルを保存したディレクトリ
├── Lib
│ └── Observer.py // Observerパターン Pythonソースコード

├── Model
│ ├── Lib -> ../Lib // シンボリックリンク(1つ上のディレクトリのLib)
│ └── TinyClockModel.py // 時計本体部 Pythonソースコード

├── View
│ ├── GUI // GUI mainwindow.ui以外使用しない
│ │ ├── GUI.pro // Qt Creatorファイル
│ │ ├── GUI.pro.user
│ │ ├── main.cpp
│ │ ├── mainwindow.cpp
│ │ ├── mainwindow.h
│ │ └── mainwindow.ui // GUI メインウィンドウ XML(Qt Creatorで自動生成される)
│ │
│ ├── Lib -> ../Lib // シンボリックリンク(1つ上のディレクトリのLib)
│ ├── TinyClockView.py // 時計表示部(データ保持)
│ ├── TinyClockViewGUI.py // 時計表示部(GUI)
│ └── mainwindow.py // mainwindow.uiをPythonソースコードへ変換したもの

└── main_gui.py // GUI用 main関数(本ファイルをpythonで実行するとデジタル時計とアナログ時計をGUI表示する)

UML

クラス図とシーケンス図を以下に示す。

クラス図

TinyuClock(GUI版)クラス図

シーケンス図

TinyClock(GUI版)シーケンス図

TinyClockModel Pythonソースコード(一部抜粋)

  • TinyClockModelクラスは、MVCモデルのModel部である。
  • TinyClockModelクラスは、Sujectクラスを継承する。
  • TinyClockModelクラスのset_timeメソッドで以下を行う。
    • 現在時刻取得
    • Subjectクラスから継承しているnotifyメソッドを呼ぶ
  • notifyメソッドを呼ぶことによって、登録されている全Observerへ通知を行う。
  • ソースコードの詳細はTinyClockModel.pyを参照。

TinyClockModelクラスのソースコード一部抜粋を以下に示す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TinyClockModel(Subject):
"""
@brief 時計本体部 クラス.
@note Subjectクラスを継承.
時刻を取得し, 表示部へ通知する.
"""


# (中略) #

def set_time(self):
"""
@brief 現在時刻を設定.
@return なし.
@note 現在時刻をobserverへ更新を通知.
"""

self._now = datetime.datetime.today()
self.notify(self)

TinyClockView Pythonソースコード(一部抜粋)

  • TinyClockViewクラスは、MVCモデルのView部である。
  • TinyClockViewクラスは、Observerクラスを継承する。
  • TinyClockViewクラスは、表示データを保持するクラスである。
  • TinyClockViewクラスのupdateメソッドでは、以下を行う。
    • Subjectクラスからの通知を受け取る
    • 表示用データの保存メソッドであるset_timeを呼ぶ
  • ソースコードの詳細はTinyClockView.pyを参照。

TinyClockViewクラスのソースコード一部抜粋を以下に示す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TinyClockView(Observer):
"""
@brief 時計表示部(表示データ保持).
@note Observerクラスを継承.
"""


# (中略) #

def update(self, modifier=None):
"""
@brief Subjectから通知を受け取るメソッド.
@param modifier 更新情報.
@note Observerクラスのメソッドをオーバーライド.
"""

self.set_time(modifier)

TinyClockViewGUI Pythonソースコード(一部抜粋)

TinyDigitalClockView

  • TinyDigitalClockViewクラスは、デジタル時計のGUI表示部である。
  • TinyDigitalClockViewクラスは、メンバー変数としてTinyClockViewクラスを持つ。
  • TinyDigitalClockViewクラスのdraw_viewメソッドは、デジタル時計を描画する。
  • ソースコードの詳細はTinyClockViewGUI.pyを参照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class TinyDigitalClockView(QtGui.QWidget):
"""
@brief デジタル時計 GUI表示部 クラス.
@note 以下クラスを継承.
TinyClockView
QtGui.QWidget
"""

def __init__(self, parent=None):
"""
@brief 初期化.
"""

QtGui.QWidget.__init__(self)
self.m_TinyClockView = TinyClockView()

def draw_view(self):
"""
@brief デジタル時計を描画.
"""

#時間を設定.
theTime = QtCore.QTime(self.m_TinyClockView.hour,
self.m_TinyClockView.min,
self.m_TinyClockView.sec)
self.m_DateTimeEdit.setTime(theTime)

# (中略) #

TinyAnalogClockView

  • TinyAnalogClockViewクラスは、アナログ時計のGUI表示部である。
  • TinyAnalogClockViewクラスは、メンバー変数としてTinyClockViewクラスを持つ。
  • TinyAnalogClockViewクラスのdraw_viewメソッドは、アナログ時計を描画する。
  • ソースコードの詳細はTinyClockViewGUI.pyを参照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class TinyAnalogClockView(QtGui.QWidget):
"""
@brief アナログ時計 GUI表示部 クラス.
@note 以下クラスを継承.
TinyClockView
QtGui.QWidget
"""

def __init__(self, parent=None):
"""
@brief 初期化.
"""

#スーパークラスを初期化.
QtGui.QWidget.__init__(self, parent=parent)

self.m_TinyClockView = TinyClockView()

def draw_view(self):
"""
@brief アナログ時計を描画.
"""

#クリア.
self._draw_clear()
#長針を描画.
self._draw_hour_needle(self.m_TinyClockView.hour)
#短針を描画.
self._draw_min_needle(self.m_TinyClockView.min)
#秒針を描画.
self._draw_sec_needle(self.m_TinyClockView.sec)
#日付を更新.
self._draw_date()
#選択を解除.
self.m_DateEdit.setCurrentSectionIndex(self.m_DateEdit.NoSection)

#再描画指示(再描画イベントを発行)
self.repaint()

# (中略) #

mainwindow.py Pythonソースコード

  • GUI部分はQtを利用している。Qt Creatorを利用している。
  • Qt Creatorでフォームをデザインするとmainwindow.uiが作成される。
  • mainwindow.uiはXMLである。
  • mainwindow.uiからmainwindow.pyのPythonソースコードに変換した。
  • Mac OSXでは以下のコマンドで変換可能。
    • %/Library/Python/2.7/site-packages/PyQt4/uic/pyuic.py -o mainwindow.py mainwindow.ui

TinyClockMain_gui Pythonソースコード

  • Subjectクラスのattachメソッドで、時計本体部と表示部を接続している。
  • タイマーを設定し、以下を実行する。
    • 時刻設定
    • デジタル時計再描画
    • アナログ時計再描画
  • ソースコードの詳細はTinyClockMain_gui.pyを参照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class ClockViewWidget(QtGui.QMainWindow, Ui_MainWindow):
"""
@brief TinyClock GUI版を表示する為のウィジェット.
"""


def __init__(self, *args, **kw):
"""
@brief 初期化.
"""

#スーパークラスの初期化.
QtGui.QMainWindow.__init__(self, *args, **kw)
self.setupUi(self)

#時計本体部を生成.
self.ClockModel = TinyClockModel()

#デジタル時計表示部を生成.
self.DigitalClock = TinyDigitalClockView()
self.DigitalClock.setup_ui(self.dateTimeEdit)

#アナログ時計表示部を生成.
self.AnalogClock = TinyAnalogClockView(self.widget)
self.AnalogClock.setup_ui(self.dateEdit)

#時計 本体部 と 表示部(データ保持部) を接続
self.ClockModel.attach(self.DigitalClock.m_TinyClockView)
self.ClockModel.attach(self.AnalogClock.m_TinyClockView)

#タイマーを設定.
self.timer = QtCore.QTimer(parent=self)
self.timer.setInterval(1*1000)

#タイマーを設定(時計本体部と接続. 1000msec毎に時刻を設定).
self.timer.timeout.connect(self.ClockModel.set_time)

#タイマーを設定(デジタル時計時計表示部と接続. 1000msec毎に時刻を表示).
self.timer.timeout.connect(self.DigitalClock.draw_view)

#タイマーを設定(アナログ時計時計表示部と接続. 1000msec毎に時刻を表示).
self.timer.timeout.connect(self.AnalogClock.draw_view)

#タイマースタート.
self.timer.start()


def main():
"""
@brief TinyClock GUI版 main処理.
"""

app = QtGui.QApplication(sys.argv)

panel = ClockViewWidget()

main_window = QtGui.QMainWindow()
main_window.setGeometry(0, 0, panel.width(), panel.height())
main_window.setWindowTitle("TinyClock")
main_window.setCentralWidget(panel)
main_window.show()

app.exec_()

オブザーバーパターン(デザインパターン)適用例

オブザーバーパターン適用例(TinyClock Console版)

概要

  • デザインパターンのオブザーバーパターンを時計アプリへの適用例をPythonコードで示す。
  • デジタル時計とアナログ時計を表示するアプリを作成した。
  • このアプリをTinyClockと呼ぶこととする。
  • TinyClockはMVC(Model-View-Controller)で作成することとする。(実際にはModel-View)

実行

実行方法

  • 実行方法は、コマンドラインから以下を実行。
    • %python TinyClockMain_console.py
  • プログラムは無限ループになっているので、C-cで強制終了。

実行イメージ

  • TinyClockMain_consoleを実行すると以下のように表示される。
    TinyClock(console版)実行イメージ

TinyClock(console版) Python全ソースコード

以下URLに全ソースコードを保存している。
TinyClock(Console版)

ディレクトリ構成

ソースコードのディレクトリ構成を以下に示す。

.
└── sources // ソースコードファイルを保存したディレクトリ
├── Lib
│ └── Observer.py // Observerパターン Pythonソースコード

├── Model
│ ├── Lib -> ../Lib // シンボリックリンク(1つ上のディレクトリのLib)
│ └── TinyClockModel.py // 時計本体部 Pythonソースコード

├── View
│ │
│ ├── Lib -> ../Lib // シンボリックリンク(1つ上のディレクトリのLib)
│ └── TinyClockView.py // 時計表示部(データ保持)

└── TinyClockMain_console.py // コンソール用 main関数(本ファイルをpythonで実行するとコンソールに時刻を表示する)

UML

クラス図とシーケンス図を以下に示す。

クラス図

TinyuClock(console版)クラス図

シーケンス図

TinyClock(console版)シーケンス図

TinyClockModel Pythonソースコード(一部抜粋)

  • TinyClockModelクラスは、MVCモデルのModel部である。
  • TinyClockModelクラスは、Sujectクラスを継承する。
  • TinyClockModelクラスのset_timeメソッドで以下を行う。
    • 現在時刻取得
    • Subjectクラスから継承しているnotifyメソッドを呼ぶ
  • notifyメソッドを呼ぶことによって、登録されている全Observerへ通知を行う。
  • ソースコードの詳細はTinyClockModel.pyを参照。

TinyClockModelクラスのソースコード一部抜粋を以下に示す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TinyClockModel(Subject):
"""
@brief 時計本体部 クラス.
@note Subjectクラスを継承.
時刻を取得し, 表示部へ通知する.
"""


# (中略) #

def set_time(self):
"""
@brief 現在時刻を設定.
@return なし.
@note 現在時刻をobserverへ更新を通知.
"""

self._now = datetime.datetime.today()
self.notify(self)

TinyClockView Pythonソースコード(一部抜粋)

  • TinyClockViewクラスは、MVCモデルのView部である。
  • TinyClockViewクラスは、Observerクラスを継承する。
  • TinyClockViewクラスは、表示データを保持するクラスである。
  • TinyClockViewクラスのupdateメソッドで以下を行う。
    • Subjectクラスからの通知を受け取る
    • 表示用データの保存メソッドであるset_timeを呼ぶ
  • ソースコードの詳細はTinyClockView.pyを参照。

TinyClockViewクラスのソースコード一部抜粋を以下に示す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TinyClockView(Observer):
"""
@brief 時計表示部(表示データ保持).
@note Observerクラスを継承.
"""


# (中略) #

def update(self, modifier=None):
"""
@brief Subjectから通知を受け取るメソッド.
@param modifier 更新情報.
@note Observerクラスのメソッドをオーバーライド.
"""

self.set_time(modifier)

TinyClockMain_console Pythonソースコード

  • TinyClockMain_consoleは、以下クラスをインスタンス化し、制御する。
    • TinyClockModel
    • TinyClockView
  • 時計本体部(TinyClockModel)を以下でインスタンス化
    • theModel = TinyClockModel()
  • アナログ時計及びデジタル時計をインスタンス化している。
    • theAnalogClockView = TinyClockView()
    • theDigitalClockView = TinyClockView()
  • Subjectクラスのattachメソッドで、時計本体部と表示部を接続している。
  • 時計表示用にスレッドを生成し、各時計独立で表示するようにしている。
  • ソースコードの詳細はTinyClockMain_console.pyを参照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def main():
"""
@brief TinyClock console版 main処理
@note 以下を別スレッドを生成して時刻を表示する.
アナログ時計
デジタル時計
スリープを使用してスレッドを切り替えている為,
スレッドの同期はとっていない.
"""

#時計本体部を生成.
theModel = TinyClockModel()
#アナログ時計表示部を生成.
theAnalogClockView = TinyClockView()
#デジタル時計表示部を生成.
theDigitalClockView = TinyClockView()

#時計 本体部と表示部接続.
theModel.attach(theAnalogClockView)
theModel.attach(theDigitalClockView)

#アナログ時計表示部のスレッドを生成.
theAnalogClockViewThread= threading.Thread(target=refresh_view, name="AnalogClock", args=[theAnalogClockView])
theAnalogClockViewThread.setDaemon(True)
theAnalogClockViewThread.start()

#デジタル時計表示部のスレッドを生成.
theDigitalClockViewThread = threading.Thread(target=refresh_view, name="DigitalClock", args=[theDigitalClockView])
theDigitalClockViewThread.setDaemon(True)
theDigitalClockViewThread.start()

while 1:
theModel.set_time()
#1秒スリープ.
time.sleep(1.0)

オブザーバーパターン(デザインパターン)

デザインパターンのオブザーバーパターンのメモ

  • オブザーバーパターンを使用すると疎結合なアプリケーションを作成可能。
     (GUIのアプリケーションでよく使用されている。)
  • オブザーバーパターンは、「通知者」から「観測者」に状態を通知する。
  • オブザーバーパターンのメリットとしては、観測者は通知を受け取った場合に動作する。
     (ポーリングしなくともよい。)
  • 通知者をSubjectクラス、観測者をObserverクラスとする。
  • Subjectクラスは、Observerクラスを持つ。
  • Subjectクラスは、Observerクラスを複数持ってもよい。この場合、SubjectクラスはすべてのObserverクラスへ通知を行う。

Observerパターンのクラス図

ObserverPattern クラス図

ObserverクラスのPythonソースコード

  • Observerクラスは、Subjectクラスから通知を受け取る。
  • 抽象クラスの為、インスタンスは作成しないこと。
  • Subjectクラスからの通知は、updateメソッドで受け取る。
  • updateメソッドは、継承したクラスでオーバーライドする。
  • ソースコードの詳細はObserver.pyを参照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Observer(object):
"""
@brief オブザーバークラス.
更新があった場合, Subjectから通知を受け取るクラス.
@note 抽象クラス. インスタンスは作成しないこと.
"""


def update(self, modifier=None):
"""
@brief Subjetから通知を受け取るメソッド.
@param modifier 更新情報.
@note 本メソッドは継承したクラスでオーバーライドすること.
"""

raise NotImplementedError

SubjectクラスのPythonソースコード(一部抜粋)

  • Subjectクラスは、登録されているObserverクラス全てに通知をする。
  • Observerクラスを登録するには、attachメソッドを使用する。
  • Observerクラスに通知するには、notifyメソッドを使用する。
  • ソースコードの詳細はObserver.pyを参照。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Subject(object):
"""
@brief サブジェクトクラス.
更新があった場合, Observerへ通知するクラス.
"""


def __init__(self):
"""
@brief 初期化.
@param メンバー変数 self._observerList 登録されたオブザーバーリスト.
"""

self._observerList = []

def attach(self, observer):
"""
@brief Observerを登録する.
@param observer 登録するオブザーバー.
@return なし.
"""

if not observer in self._observerList:
self._observerList.append(observer)

def notify(self, modifier=None):
"""
@brief Observerへ更新を通知するメソッド.
@param modifier 更新情報.
"""

for observer in self._observerList:
if observer != modifier:
observer.update(self)

参考文献

17.Observer パターン | TECHSCORE(テックスコア)