DSD to PCM

PDM信号をPCMに変換

アナログ信号からデルタ一次シグマ変調(ハードウェアでの変換例)されたビットストリーム信号を得て、これをサンプリング周波数fsのPCMに変換を試みます。

変換方法には幾つかバリエーションがありそうで、正直どれが一番正解なのか微妙なのです、理由は、再生しようとしている手に入れたDSDデータはどのような方法で変換したものなのか?

現実には殆ど詳細が判らないものが大半ではないかと思います。 例えばある録音はBurrBrown製のADCで録られてていて、その石は4次のデルタシグマ変換器で構成されていたり、また別の石でCurrusLogic製だったり、あるものは七次という高次の変換器で録られてていたという具合で、実際の所殆ど判らないのですが、これら全てを同じ方法でデコードして正しく元に波形に戻るとは到底思えないからです。

具体的には、冒頭で示した一次の変換であればいつでもプラスマイナス1の変化しかしないので44.1kHzの128倍である5.6MHzでサンプリングしたとしても44.1kHz PCMでの1サンプリング周期である22.67uSの間全てが同じ値(全て1or0)だったとしても最大振幅が128peak-peakの矩形波しか再生することができないので高域端ではたった7ビット相当の酷い音質でしか再生することができないからです。 しかし高次のデルタシグマ変換であれば量子化された値で同じ値(例えばずっとHighとかLowとかの値)が続くと波形の傾きはアダプティブ・デルタ変換のようにどんどん急になっていく筈なので、符号化されたPDMは一定の差分を表しているものと考えて、単純に積分していっただけでは元の波形に戻らないのは当然のことなのではないのでしょうか?

実際のSACDテストディスクに収録されているsin波のスイープ信号は、7bitよりも遥かに大きいレベルでかつ低歪に再生されるので、高次のAD変換器で作られたデータであることは間違いありません。 つまり何が言いたいのかというと、どういう変換を経て作られたPDMデータストリームであるのか判らない限り、積分していく方法では決して元の信号に忠実な再生なんて出来っこ無いはずだということなのです。 同様に単純にCとRでアナログ積分しても全く同じことでしょう。

このように逐次積分してデコードしていく方法とは別に、1ビットPDM波形を±mの値しか取れない特殊なPCMの波形だと考えてFIRフィルターにかけて帯域制限することでPDMに含まれる低域側のオーディオ信号をPCM化し、これをデシメーション処理(間引く)ことで例えば5.6MHzのPDM波形から44.1kHzのPCM波形に変換することが可能です。 この方法なら前者の方法のように悩む必要もなく諦めがつくというか、他に方法も無いからお手上げというか、妥協するしか無いという心境になるというか、このあたりの気持ち悪さが私がDSDが大嫌いな理由でもあります。 市販のDSD再生をするためのDAコンバーターにはアナログでFIRフィルターを掛けている代物などあって、全くもっていい加減な仕様というかアバアウトなマインドが鼻につくHi-Fi(高忠実)とは縁遠い技術だと思います。

〜〜閑話休題〜〜

エンコードした方法が判っているのであれば、正しい演算をすることで元の波形に再現することができるのは先ほど述べた通りですので、積分演算で一次のデルタシグマ変換されたPDMからPCMへ変換してみます。

積分による変換

次のようなステップで処理を行ってみます。

1) Clock 45.1584MHzでサンプルしビットストリームを得ます。(PCMのfsを44.1kとすると、PDMパルス1024個ごとに次のPCM波形のサンプル周期となります。)

2) 上記で量子化されたPDMストリームで変換後のPCMでの1サンプリング区間に存在するビットのすべてを加算します。

3) 上記の値を今周期のPCM値の変化分とし、前ピリオドのPCM値に加算します、次の区間でも同様に得た変化分を一回前の値に積算していきます。

これは、次のようなコードになります。

input CLOCK_45M1584;

input DATAIN_BITSTREAM;

output reg LATCHED_OUT_BITSTREAM;

reg [1023:0] bit_streams;

always@(posedge CLOCK_45M1584) begin

bit_stream = (bit_streams << 1) | DATAIN_BITSTREAM;

LATCHED_OUT_BITSTREAM = DATAIN_BITSTREAM;

end

reg [23:0] DATA_PCM;

reg [23:0] latched_pcm;

reg [9:0]counter_44k1;

always@(negedge CLOCK_45M1584) begin

DATA_PCM = DATA_PCM + bit_streams[0];

counter_44k1 = counter_44k1 + 1;

if (!counter_44k1) begin

latched_pcm = DATA_PCM;

DATA_PCM = 0;

end

end

上記のlatched_pcmにPCMデータが格納されます。 但し1ビットの値が±1として処理がされていないので要改善ですね。

上記の各波形:

上から、counter_44k1, DATIN_BITSTREAM, latched_pcm