デジタルオーディオあれこれ

半田ごての人。紙と鉛筆だけではちょっと。

DSMの実際の周波数特性を、NTFから計算する。そこそこ実際の値に近い。

 今はもうDSMの計算には幾つかのライブラリーが用意されている筈で、これを一から自分で作る人はまずいない。アルゴリズム自体はほぼ完成されていて、初期のSACDで使っているのに比べると、随分と良くなっている。良いというのは、入力がゼロの時に変なアイドリングパターンを出さないとか、同じ次数やOSRでノイズレベルが低いという意味。SACDはあんまり良くない。

 

 しかしFPGAに実装する場合は少し違う。ソフトウエアと違ってリソースが限られているので、用途に合わせて限りなく特化する必要がある。金に糸目を付けないのならば、大きなサイズのFPGAで解決する手もあるが。デジタルフィルターにしろDSMにしろ、ハードウエア化にはそんな問題が常にある。

 

 参考書籍はあるけれど、中々自分に必要な所を見つけ出すのは難しい。ネット情報も当たり外れが大きい。ここはとても凄い。

PlayPcmWin / Wiki / PCMtoSDM

必要な情報は全てある。MATLABでの計算結果も出ている。本にはそこまで出ていない。結果が欲しければ、MATLABは高いのでpythonで計算するしかない。でも最終的な定数に辿り着くまでには些かの計算が必要。

 

 自分で計算して履歴も残っているけれど、暫くしてから見直すとサッパリ意味が分からない。一日位考えてやっと思いだす。という訳で、備忘録の積りの覚書。

f:id:xx3stksm:20181016194033j:plain

 これがDSMの基本の基本。定数の計算もこれが元になっている。入力信号はそのまま出力に出るようにして、量子化誤差に対するNTFというのを音声帯域で小さくなるようにする。NTF=1/(1-L1(z))

MATLABはsynthesizeNTFで、この関数の零と極を計算してくれる。ここにある。

PlayPcmWin / Code / [r740] /PlayPcmWin/WWOfflineResampler/NTFHzcoeffs.cs

どちらも複素数になる。

 

 この零と極をもつ関数と、実際の回路の係数を一致させれば良い。一番簡単な二次の場合はこうなる。

f:id:xx3stksm:20181213212028j:plain

%o126がL0(z)で、%o131がL1(z)。

f:id:xx3stksm:20181213213045j:plain

 z0,r0,j0,が、MATLABが計算してくれる零と極。次数が上がるとこれが増えてくる。

という按配で最終的に必要なg0,a0,a1が出て来る。ここまで自分でしなくても、g0,a0,a1も出ているので、そのまま有難く使わせて貰って問題はない。

 

 但し、gとaが出ているのは五次までなので、それ以上の七次が欲しければこの計算が必要。七次ともなると、とんでもない数式になるが、maximaが計算するので、二次の延長で数式をほり込んでやればよい。そのために、二次で流れ作業の手順を覚える必要がある。

 

 これを計算するのにはもう一つ意味がある。このNTFの周波数特性を確認したい。これが所謂ノイズシェービングというものなので、どの程度にノイズが抑えられるのかを確かめる。NTFは共にzの二次の分母と分子で出来ている。このzにe^(jωT)を代入すると、その複素数の絶対値が周波数特性となる。

f:id:xx3stksm:20181213214752j:plain

分母の実数が%o3で虚数が%o4。分子の実数が%o13で虚数が%o14。これの絶対値をエクセルで計算させてグラフ化するとこうなる。

f:id:xx3stksm:20181213215015j:plain

 横軸はサンプリング周波数を1として表示。x64のOSRだと、1が3.072MHzで0.1が307.2KHz、0.001が3.072kHzになる。二次の場合、0.1ぐらいまでノイズは上がり続ける。g0で出来る共振点が、0.005(15kHz)あたり。g0という局部帰還を入れると、ない場合の赤に較べると、ノイズシェービングの効きが良くなる。なので入ってる。

 

 けれどもこれは、グラフにあるように直流分に対しての減衰量がゼロにはならない。g0=0の赤ならば、そんな問題は起きない。偶数次の場合にはこの問題があるので、四次であれば二つの局部帰還のうち一つはゼロにした方が良い。それでも十分にノイズは落とせるので。赤の傾きは、二次の理論通り40db/decとなっている。

 

 実際に使う場合、二次ではノイズレベルが高すぎる。計算方法は同じなので、maximaを使って五次で計算させる。昔はこれを手計算でしていたので大変。間違える可能性はあるし、グラフ化するのも大仕事。今は簡単に出来る。これが五次の時の分母。

f:id:xx3stksm:20181214145718j:plain

こっちが分子。

f:id:xx3stksm:20181214145745j:plain

五次なので係数は分母にr0,j0,r1,j1,r2。分子にg0,g1。これを代入してグラフにするとこう。

f:id:xx3stksm:20181214145921j:plain

 五次の場合は、傾きが30dB/octになる。g0とg1で共振点を作ると、共振点なしの緑よりも落ち具合は良くなる。但し、零をDCに持つ項が一次となるので、共振点から上がってきた後は、緑よりも落ちが悪い。FPGAで実装する場合、リソースに余裕がないならば緑の方が遥かに簡単。現実論として、十分なノイズ特性は稼げるので、共振点の必要もない。

 

 シミュレーションは所詮仮説に過ぎないので、実物で確かめる必要がある。これは一ビットの出力なので、実際のデジタルデータをそのままFFTしてしまえば、その特性が分かる。一ビット以外であれば、DACのアナログ出力をアナログフィルター無しで入れるしかない。測れなくはないが、50Ωのプローブが使えないのでS/Nが悪化する。一ビットは楽。

f:id:xx3stksm:20181214151111j:plain

 これはg0とg1がゼロなので緑の特性。下の5MHzスパンが全体像で上が拡大図。シミュレーションでのNTFは、100kHzぐらいで平坦な特性になる。実物もそのあたりで少し飽和し始め、そこに至る間は理論通りに30dB(6dBx5)/octで上がってる。元のデジタル信号は3Vppぐらい。これを50Ωの関係で16dBぐらい落としている。

 

  3Vppは1Vrmsで120dBuVだから、この時に出している12kHzはアッテネーターなしだと120-16-6=98dBuV。実物との差は主にDAC側でのアッテネーター。一ビットは、100%の変調を掛けると必ず発振するので、幾らかのアッテネーターが必ず入る。-6で50%に落とすのは必須。普通は更に2dBぐらい落とす。残りはDAC内のフィルターでの減衰とか誤差。

 

  シミュレーションとの違いは、誤差のEかと思う。これが定数ではないので差が出るのでは。1Mから2Mにかけての成分もそこら辺りから来るのだと思う。でもL0(z)とL1(z)での解析は、相当に正確で十分に実用的。

 

 これは5MHzのスパンになっているけれど、その周期性は明らか。分母と分子の複素数がサインとコサインなので、言うまでもない話ではあるけれど、実物を見ないとこの周期性には気が付かないもの。分数の形になっているIIRであっても、言うまでもなく周期性を持つ。デジタルのシステムは離散システムと言うが、周期性システムと言った方が思い込みは防げる。

 

 アナログのような落ちっ放しのLPFなんてものは、決して実在しない。無限に高いサンプリング周波数を使わない限り。sinc関数はこれを暗黙の裡に想定している。なので現実世界で使おうとすると、思いもよらない所で足をすくわれる。デジタルとは、因果応報の輪廻の如く、必ず繰り返す周期性システム。

 

 おまけにSACDFFT。傾きからして五次ではないと思う。でも少し五次よりも上がり始めが早い感じ。もうずいぶんと昔の規格なので、変調のかけ方がまだ完璧でなかったんだと思う。

f:id:xx3stksm:20181214153441j:plain