アナログシンセ掲示板ログ閲覧所
Library of BBS for DIYers of Analog Synth

[ トップページへ / 一覧表示 / 最新記事 / 管理用 ]
[ to Top Page / Title List ]


雑談 LFOのスピードを変化させるためのソフトウエアアンチログのまとめ
#8924
この記事の投稿者にメールを送信 takeda (2008年04月28日19時48分)
スピードを変えるパラメーターとしてADコンバーターからの0から255までの出力を使う予定だけど、このリニアな変化に対して、周波数もリニアに変わると、発振器としてはえらく使いにくい。つまみの回し具合と周波数の変化を聴感上リニアにするには、つまみのリニアな変化を指数カーブに変換してやらなきゃいけない。ソフトウエアアンチログ変換。

指数カーブを得たいのなら普通には y=exp(x)。yが5から255まで変化するxは、log(5)=0.698、log(255)=2.406。
エクセルで計算するとこんな数字がでるけど、これは、10を底としたときの数字。指数関数の逆関数が対数対数なのだけど、基準と成る底が違ったらそりゃ結果も違う。エクセルで動作をチェックするときには、指数関数のかわりに、log(n,x) pwoer(n,x)(それぞれnが底)という関数に置き換える。底は10でも2.718でもカーブの形は変わらない。

底を2にしたときの5と255の対数は、2.321と7.99。この間をリニアに変化する数字をy=exp(x)に突っ込んで出てきた数字をスピードの設定値として、リニアに変化する発振器に突っ込めばいい。まずはADコンバーターの出力を2.321から7.99にマッピングしなきゃいけない。ADコンバーターの出力をNとすると..

(N X (7.99-2.321) / 256) + 2.321
http://www.aleph.co.jp/~takeda/radio/parm/software/exp-curve1.gif

エクセルのBの列。Cの列がそれを指数関数に突っ込んで得た結果。思ったとおり、あのカーブが出ている。この計算が面倒くさいかなーということで、256個のデータのテーブルにしたのが、先日のバージョン。
ただ、小さなCPUには相対的に巨大なこのテーブルを持たせるのはのどーよ、ということで、C言語で安価に計算する手がないかな、と。

指数関数の性格として分割することができるので、計算の比較的簡単な整数部分と、面倒げな小数点以下のぶぶんとに分ける。
整数部分は普通に掛け算で得られる。しかも、2を底とするとさらにお得なボーナスがついて計算はシフトで済ませられる。小数点乗部分はやっぱ面倒だからテーブル化しちゃえは竹プランと、実際計算してグラフ化してみるとほとんど直線ジャン!そのまま行ってもばれねえよの梅プラン、それぞれ、Chuckさんと、RJBさんが実装されている。
http://www.aleph.co.jp/~takeda/radio/parm/software/exp-curve2.gif

小数点以下の数字と整数の部分とを分けて計算する方向ということでここで固定小数点による演算を検討する。
簡単に言えば、
A X B = C
だったら、
A X B X D = C'
でC'を計算して後から、Dで割りゃ良いんじゃん?ということ。Dが2の乗数ならば、シフトだけで済む。ADコンバーターの0から255までの出力を固定小数点の数字にマッピングするわけだ。Dをどんな値すれば良いかの検討がミソ。

いまここでターゲットにしている数字は、2.321から、7.99までの値。普通に引き算すると5.669。8ビットでこの値を表現しようとすると5.669/255で0.022。1ビットの重みが0.022なら、1は、(1/0.022=)45.5。とりあえず6ビット必要。
というわけで、小数点を6ビット目にするのなら、最小単位は、(1/64=)0.0156となり、この系で7.99を変換すると(7.99/0.0156=)512.17。同様に最小値は、2.321は(2.321/0.0156=)148.782。
まずは0から、255の値Nを、149から512にマッピングしなきゃいけない。

(N X (512-149) / 256) + 149

これで得た数字の6ビット目以上は整数部分。以下は、小数点以下部分となる。
ただ、問題が一つ。perlなどで、アルゴリズムのチェックはOKでも、C言語で書くと16ビットの整数でという制限が掛かって、(512-149)=363に入力の最大値255を掛けると、16ビットを超えちゃう。どうせ後で、256で割るんだから、先に定数を2で割っとけ作戦へとシフト。

(N X ((512-149)/2) / 128) + 149

ターゲットの数字を6ビット右にシフトして得た整数部分で2を左にシフト。これにテーブルから持ってきた小数点以下の指数を掛け算。最終的に得た数字を6ビット右にシフトして小数点以下を切り捨てて整数化。割り算はすべてシフトで済むので本気で掛け算は2回だけ。
シミュレーターでチェックすると、この関数、8MHzで走らせて47uSぐらい。このLFOの最小タイミングが122usなので、処理的には収まりそうだ。

プログラム全体の評価としては、テーブルメソッドで
Program: 846 bytes (41.3% Full)
http://www.aleph.co.jp/~takeda/radio/parm/software/2313LFO-A.zip
計算メソッドで
Program: 768 bytes (37.5% Full)
http://www.aleph.co.jp/~takeda/radio/parm/software/2313LFO-B.zip

プログラムそのものは、テーブルサイズしか小さくならない。
このアプリのようにスピードだけしか変えないのであればシンプルにテーブルを見るのが高速で且つシンプル。
計算アルゴリズムで持つ小数点以下の乗数のテーブルは一種の定数として使えるので、LFOのほか、音量や、違うタイミングの計算などに共通で使える。プログラムサイズのがパンクしかけな場合には検討に値するかもしれない。

さらに直線近似メソッドで2の0乗(1)から、2の1乗(2)まで変化する、6ビット目が小数点とする数字に0から64まで変化する入力をマッピングするんだけど、ふと気がつけば、単純に64を足すだけで済む。
Program: 692 bytes (33.8% Full)
http://www.aleph.co.jp/~takeda/radio/parm/software/2313LFO-C.zip

さらにシミュレーターで同様のチェックすると、8MHzで走らせて21uS。早い、安い!さらに、プログラムメモリから、配列データそのもののほか、配列のデータを引っ張る関数がなくなるので、思いがけず小さくなる。精度は、Zipファイルにエクセルにしてグラフを入れておいたけど、ほとんどわかんない状態。いいんでねーの?

[この記事の元になった記事]

Re:ローコストLFO実装 : takeda (2008年04月23日22時02分)

[この記事に対する返事]

返事はありません。