はじめに
数値計算用のプログラミング言語としては Pythonの利用が増えています.
一方で,MATLABや,MATLABに似たオープンソースの数値計算ツールである Octave も選択肢としてあります.
Python が使われている一方で,Octaveにしかない関数や,Octave (MATLAB) で書いた関数を利用したいという場面があります.
そこで,今回はPythonでOctaveの関数を呼び出せる便利なライブラリ「oct2py」を紹介します.
本記事では,PythonからOctaveの関数を簡単に使う方法,特に「oct2py」のインストール方法と利用例を詳しく説明します.
インストール方法
検証環境
Octave, oct2pyの概要
oct2py は,Pythonと 数値計算ツール Octaveを統合し,PythonからOctaveの関数を呼び出せるツールです.MATLABが有償であるのに対し,Octaveはオープンソースであり,手軽に数値計算が可能です.このライブラリを使うと,Pythonコードの中でMATLABライクな数値処理が簡単に行えます.
octaveのインストール方法
まずは Octaveをインストールします.インストーラの指示に沿って進めれば大丈夫です.
インストール後,システム環境変数にoctaveのパスを設定する必要があります.
ここで重要なのが,octave-cli.exe (コマンドラインインターフェイス版) が存在するフォルダのパスを登録する必要があります.
私の環境だと,"C:\Program Files\GNU Octave\Octave-9.2.0\mingw64\bin"でした.
ここで,"C:\Program Files\GNU Octave\Octave-9.2.0"を環境変数に設定してしまうと,oct2pyの呼び出し時に以下のようなエラーが出てしまいました.
>>> import oct2py [WinError 193] %1 は有効な Win32 アプリケーションではありません.
oct2pyの導入
次に,Pythonの環境にoct2pyを導入します.以下のpipコマンドを使って簡単にインストールできます.
pip install oct2py
また,condaも利用できます.下記を参考にしてください. blink1073.github.io
パッケージの導入
ここまでの操作だと,Octaveの基本的な機能しか利用できません.
そこで,例えば信号処理や制御システム向けのパッケージを導入したい場合は,Octave上で以下のコマンドを実行します.
pkg install -forge signal
この時,Octaveは管理者権限で実行することを推奨します.
また,上記のコマンドでうまくいかなかった場合,手動でダウンロードしてインストールすることを試してみてください.私の環境では,以下のように解凍せずにインストールできました.なお,インストールには少し時間がかかりました.
pkg install signal-1.4.6.tar.gz
動作確認
以上の導入作業終了後,例えばpythonのインタプリタを起動して,以下の文を入力し,エラーなく実行できれば導入は無事完了です.
>python >>> import oct2py >>> oc = oct2py.Oct2Py()
利用例
基本操作
oct2pyを使った最も基本的な操作は,Octaveの関数をPython内で呼び出すことです.
例えば,octave.sin(1)のように呼び出して計算を行います.
import numpy as np import oct2py oc = oct2py.Oct2Py() ans = oc.sin(np.pi/2) print(f"{ans}") # => 1.0
パッケージの利用
追加のパッケージを利用する際は,以下のように呼び出す必要がありました.以下の例では,signal を利用しています.
import numpy as np import oct2py oc = oct2py.Oct2Py() oc.eval('pkg load signal')
関数の返り値の数の指定:nout
Octaveの関数には複数の値を返すものがあります.しかし,特にnoutを指定せずに利用した場合は,1つ目の返り値のみとなるようです.
そこで,複数の値を返す関数ではnoutパラメータを指定することで,それぞれの出力を取得できます.基本的に,octaveの関数を使うときはnoctを指定する方がよさそうです.
以下は,Butterworth filterの関数 butter の利用例です.
nout を指定しない場合:
import numpy as np import oct2py oc = oct2py.Oct2Py() oc.eval('pkg load signal') ret = oc.butter(4, 0.2) print(ret) # => [[0.00482434 0.01929737 0.02894606 0.01929737 0.00482434]]
Function File: [b, a] = butter (n, wc) の bのみが返ってきています.
nout=2:
ret = oc.butter(4, 0.2, nout=2) print(len(ret)) # => 2 print(ret) # => [array([[0.00482434, 0.01929737, 0.02894606, 0.01929737, 0.00482434]]), array([[ 1. , -2.36951301, 2.31398841, -1.05466541, 0.18737949]])]
Function File: [b, a] = butter (n, wc) の b, aが返ってきています.
nout=3:
ret = oc.butter(4, 0.2, nout=3) print(len(ret)) # => 3 print(ret) # => [array([[0.00482434, 0.01929737, 0.02894606, 0.01929737, 0.00482434]]), array([[ 1. , -2.36951301, 2.31398841, -1.05466541, 0.18737949]])]
Function File: [z, p, g] = butter (…) になるため,返り値は分子・分母多項式の係数ではなく,零,極,ゲインになることに気を付ける必要があります.
Octave独自の関数を使う例:invfreqz
実は,OctaveにはPython (Scipyなど) には実装されておらず,MATLAB独自の関数が多くあります.
例えば,invfreqz 関数は周波数応答データからフィルタ係数 b, a を推定する便利な関数です.しかし,2024年9月現在では Scipyなどには実装されていません.
しかし,oct2pyを使えば,Pythonからinvfreqzを呼び出してフィルタ設計を行うことができます.
以下は,低域通過フィルタ(バターワースフィルタ)の周波数応答 H(f)から,フィルタ係数 b, a を
Octaveでの invfreqz() の利用
octave:3> pkg load signal octave:4> n = 128; octave:5> [b, a] = butter(4, 0.2); % 低域通過フィルタの設計 (バターワースフィルタ) octave:6> [H, w] = freqz(b, a, n); % フィルタの周波数応答を計算 octave:7> p = 4; % 分子の次数 octave:8> q = 4; % 分母の次数 octave:9> [bb, aa] = invfreqz(H, w, p, q); % invfreqzを使ってフィルタ係数を推定 octave:10> bb bb = 4.8243e-03 1.9297e-02 2.8946e-02 1.9297e-02 4.8243e-03 octave:11> aa aa = 1.0000 -2.3695 2.3140 -1.0547 0.1874 octave:12> b b = 4.8243e-03 1.9297e-02 2.8946e-02 1.9297e-02 4.8243e-03 octave:13> a a = 1.0000 -2.3695 2.3140 -1.0547 0.1874
Python (oct2py) で Octaveのinvfreqz() の呼び出し
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> import oct2py >>> >>> oc = oct2py.Oct2Py() >>> oc.eval('pkg load signal') >>> >>> n = 128 >>> b, a = oc.butter(4, 0.2, nout=2) # オリジナルのフィルタ設計 (バターワース低域通過フィルタ) >>> H, w = oc.freqz(b, a, n, nout=2) # 周波数応答を取得 >>> p = 4 # 分子の次数 >>> q = 4 # 分母の次数 >>> bb, aa = oc.invfreqz(H, w, p, q, nout=2) # invfreqzを使用してフィルタ係数を推定 >>> >>> print(bb) [[0.00482434 0.01929737 0.02894606 0.01929737 0.00482434]] >>> print(aa) [[ 1. -2.36951301 2.31398841 -1.05466541 0.18737949]] >>> print(b) [[0.00482434 0.01929737 0.02894606 0.01929737 0.00482434]] >>> print(a) [[ 1. -2.36951301 2.31398841 -1.05466541 0.18737949]] >>>
同じ結果になっていることが確認できました。
まとめ
oct2pyを使用することで,Pythonの環境から簡単にOctaveの豊富な関数やライブラリを活用することができます.
Python の NumPyやSciPyなどを合わせて使いながら,高度・高精度な数値計算や信号処理を実施したり,OctaveやMATLABのスクリプト・関数等の資源を有効活用するのにオススメです.