デシベル計算の高速化

前回記事でべき乗(pow)や対数(log)の演算は遅いということが分かりました。デジタルエフェクターではデシベル計算をよく使うため、これらの演算を高速化することを考えます。(以下、C言語を前提とした記述となっています。)



< dB x → 電圧比(倍率) y >

通常の計算は y = powf( 10.0f, x / 20.0f ) ですが、500サイクル程度かかります。そこでテーブル引きという方法を使います。あらかじめ表(ルックアップテーブル)を用意しておき、そこから値を取り出して計算する方法です。

今回テーブルは-128dB~+128dBの範囲で1dBステップとしました。小数点以下の部分については線形補間(2点間を一次関数に当てはめる)で近似します。コードは下記の通りです。dbtovolTable.hファイルはGitHubに置いています。

#include "dbtovolTable.h"

float dbtovol(float x)
{
x += 128.0f;
uint8_t xi = (uint8_t) x;
return dbtormsTable[xi] + (dbtormsTable[xi+1] - dbtormsTable[xi]) * (x - xi);
}

xiにはuint8_tの0~255が入るので、テーブル配列のサイズは257にすればよいです。もちろん入力値が範囲外の場合は正しい値が出力されません。誤差は最大0.015dBで、実用には充分だと思います。サイクル数は約30となり大幅に高速化できました。



< 電圧比(倍率) x → dB y >

通常の計算は y = 20.0f * log10f( x ) ですが、230サイクル程度かかります。こちらもテーブル引きを利用したいところですが、等比級数的なテーブルを準備する方法がわかりませんでした。膨大な量の配列を準備している例もありますが、メモリが少ない場合には無理があります。

今回はsqrtf演算(=1/2乗)が高速なことを利用することにしました。以下のように式を変形します。
log x
= log ( x1/2 )2
= 2 log x1/2
・・・
= 32 log x1/32
あとは x1/32 とdBの関係を三次関数で近似します。コードは以下の通りです。

#include <math.h>

float voltodb(float x)
{
x = sqrtf(sqrtf(sqrtf(sqrtf(sqrtf(x)))));
return - 559.57399f + 995.83468f * x
- 591.85129f * x * x + 155.60596f * x * x * x;
}

使用範囲は0.00001(-100dB)~1(0dB) 推奨、最大誤差0.016dBです。電圧比というより音量変換を見据えた範囲としています。範囲を超えると誤差が増えますが、極端に外れた値にはなりません。サイクル数は約90で、効果はそれなりでした。

他にもいろいろな方法を試したのですが、条件分岐を入れると意外とサイクル数が増えてしまう等、なかなかこれといった方法が見つかりませんでした。場合によっては通常のlog10fを使うことになりそうです。

コメントの投稿

非公開コメント

管理人

管理人

自己紹介のページ
記事一覧
Twitter
GitHub

ブログ内検索
カテゴリー
タグ

自作エフェクター   レイアウト   回路図   歪み   PureData   周波数特性   マイコン   波形・倍音   RaspberryPi   エレキギター   アンプ   エレキベース   エフェクター自作方法   歪率   真空管   コーラス   ピックアップ   静音ギター   ヘッドフォンアンプ   擬似ギター出力   市販エフェクター   アコースティックギター   ブースター   コンデンサ   ソロギター   ポールピース   イコライザー   コンプレッサー   ビブラート   フェイザー   トレモロ   TAB譜   ディレイ   DIY_Layout_Creator   ワウ   オートワウ   バッファー   

最近の記事
最新コメント
Twitter
RSS
メールフォーム
当ブログに関するお問い合わせはこちらからお願いします。 ※FAQ(よくある質問)もお読みください。

お名前
メールアドレス
件名
本文

アクセスカウンター