Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

オクターブバンドの中心・下限・上限周波数のPythonでの算出と、基底に関する備忘録

オクターブバンドについて

騒音のような音信号の周波数分析では,オクターブバンドフィルタがよく使われています。

www.wizard-notes.com

周波数分析といえばフーリエ変換が思い浮かびますが、1オクターブ内(例えば、250 Hz~500Hz, 500Hz~1000Hz)では周波数解像度が異なるという性質があります。

そこで、人間の聴覚の周波数特性は等比的であることから、定周波数比でフィルタバンクを構成するオクターブバンド分析が利用されます*1

www.onosokki.co.jp

具体的には、音信号をFIRやIIRフィルタで構成するフィルタ群(フィルタバンク)に通すことで、各周波数帯域の信号を得ることができます.

Benchmark Problems for Acoustical Parameters

www.wizard-notes.com

中心周波数や下限・上限周波数の算出

定周波数比でフィルタバンクを設計する際に最低限必要なパラメタに、基準周波数と基底があります。

基準周波数は 1000 Hzがよく用いられます。

基底は、2と10の場合があります。

例えば、よく使われる1/3オクターブバンドの場合、以下のように中心周波数や下限・上限周波数を算出することができます。

公称中心周波数 (Hz) 基底2 中心周波数 基底2 下限周波数 基底2 上限周波数 基底10 中心周波数 基底10 下限周波数 基底10 上限周波数
100 99.2 88.4 111.4 100.0 89.1 112.2
125 125.0 111.4 140.3 125.9 112.2 141.3
160 157.5 140.3 176.8 158.5 141.3 177.8
200 198.4 176.8 222.7 199.5 177.8 223.9
250 250.0 222.7 280.6 251.2 223.9 281.8
315 315.0 280.6 353.6 316.2 281.8 354.8
400 396.9 353.6 445.4 398.1 354.8 446.7
500 500.0 445.4 561.2 501.2 446.7 562.3
630 630.0 561.2 707.1 631.0 562.3 707.9
800 793.7 707.1 890.9 794.3 707.9 891.3
1000 1000.0 890.9 1122.5 1000.0 891.3 1122.0
1250 1259.9 1122.5 1414.2 1258.9 1122.0 1412.5
1600 1587.4 1414.2 1781.8 1584.9 1412.5 1778.3
2000 2000.0 1781.8 2244.9 1995.3 1778.3 2238.7
2500 2519.8 2244.9 2828.4 2511.9 2238.7 2818.4
3150 3174.8 2828.4 3563.6 3162.3 2818.4 3548.1
4000 4000.0 3563.6 4489.8 3981.1 3548.1 4466.8
5000 5039.7 4489.8 5656.9 5011.9 4466.8 5623.4
6300 6349.6 5656.9 7127.2 6309.6 5623.4 7079.5
8000 8000.0 7127.2 8979.7 7943.3 7079.5 8912.5
10000 10079.4 8979.7 11313.7 10000.0 8912.5 11220.2
12500 12699.2 11313.7 14254.4 12589.3 11220.2 14125.4
16000 16000.0 14254.4 17959.4 15848.9 14125.4 17782.8
20000 20158.7 17959.4 22627.4 19952.6 17782.8 22387.2

小野測器 - FFT基本 FAQ - オクターブバンド遮断周波数

算出に用いたPythonスクリプトは以下になります。

import numpy as np
import pandas as pd

def calculate_octave_bands(_start_freq, _stop_freq, _base_freq, _fraction, _base):
    fr_inv = 1 / _fraction
    _center_freq = _base_freq
    while _center_freq / (_base**fr_inv) >= _start_freq:
        _center_freq /= _base**fr_inv

    octave_bands = {
        'center': [],
        'lower':  [],
        'upper':  []
    }
    while _center_freq <= _stop_freq:
        _lower_freq = _center_freq / _base**(1/(2*_fraction))
        _upper_freq = _center_freq * _base**(1/(2*_fraction))
        
        octave_bands["lower"].append(_lower_freq)
        octave_bands["center"].append(_center_freq)
        octave_bands["upper"].append(_upper_freq)
        
        _center_freq *= _base**fr_inv
    
    octave_bands["lower"] = np.array(octave_bands["lower"])
    octave_bands["center"] = np.array(octave_bands["center"])
    octave_bands["upper"] = np.array(octave_bands["upper"])
    return octave_bands

# 公称中心周波数
nominal_freqs = np.array([100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 10000, 12500, 16000, 20000])
start_freq, stop_freq = 99, 21000

# 基底2
base2_bands  = calculate_octave_bands(start_freq, stop_freq, 1000, 3, 2)

# 基底10
base10_bands = calculate_octave_bands(start_freq, stop_freq, 1000, 10, 10)


indices_base2  = []
indices_base10 = []

for nf in nominal_freqs:
    indices_base2.append( np.argmin(np.abs(base2_bands["center"] - nf)) )
    indices_base10.append( np.argmin(np.abs(base10_bands["center"] - nf)) )
indices_base2  = np.array(indices_base2).astype(int)
indices_base10 = np.array(indices_base10).astype(int)

data = {
    "Nominal frequency":    nominal_freqs,
    "base-2 center": base2_bands["center"][indices_base2],
    "base-2 lower":  base2_bands["lower"][indices_base2],
    "base-2 upper":  base2_bands["upper"][indices_base2],
    "base-10 center":base10_bands["center"][indices_base10],
    "base-10 lower": base10_bands["lower"][indices_base10],
    "base-10 upper": base10_bands["upper"][indices_base10],
}

df = pd.DataFrame(data)

# CSVファイルに書き出す
df.to_csv("filter_bank_frequencies.csv", index=False)

基底について

基底が2と10の場合を比べると、違いは僅かですが、どちらも公称中心周波数からのずれがあります。

では、どちらを利用するのがよいでしょうか。

以下の資料では、次のように述べられています。 https://courses.physics.illinois.edu/phys406/sp2017/Lab_Handouts/Octave_Bands.pdf

現行のIEC 61260:1995およびANSI S1.11-2004規格は、base-10とbase-2の両方を認めているが、base-10を推奨している。いくつかの規格(ISO 266-1997など)は基数-10をベースとしているが、基数-2は差異が小さいため(103/10=1.995262)、許容可能な近似値として使用できると言及している

また、小野測器の解説ページにもあるように、JIS C 1513-1では10のべきによる系が推奨されています。 kikakurui.com

*1:なお、フーリエ変換を利用し、かつ、1オクターブ内の周波数ビン数を一定にする周波数変換法として、定Q変換という手法もあります。こちらは、楽音の分析などでよく利用されています。www.wizard-notes.com