SSブログ

PWM+ローパスで擬似D/A [Pi Pico]

Pi PicoのPWM信号をローパスに通して擬似的なD/A変換に使っている。ところがローパスの半田付けが面倒なので次数の低いローパス、つまり1次のローパスにしていると、結構な分量の基本波成分の漏れがある。1次ではローパスのカットオフをPWMの基本波の一桁下にすると基本波成分は1/10だけ漏れることになる。

これが気になってきた。つまり単純なPWMではなくて、なにかビットパターンを考えて基本波成分を減らす工夫はないか、と考えてみた...

具体的に考えてみる。Pi PicoのPWMのデフォルトのクロック125MHzを使って、PWMのwrap(すなわち何クロックで基本波にするかという値)を12ビットぶん、つまり4096にする。そうすると基本波は$125 \times 10^6 / 4096 \approx 30.5 \times 10^3$Hzとなってカットオフを一桁下、つまり3kHzの場合を考えてみる。

PWMデューディ50%の矩形波をFourier展開するとその定数成分$A_0$と基本波成分$A_1$は \begin{align*} A_0 &= \int_{-\pi/2}^{\pi/2}dx = \pi \\ A_1 &= \int_{-\pi/2}^{\pi/2} dx \cos x = 2 \end{align*} なので、ローパスで$A_0$はそのまま、$A_1$は1/10になったとすると、必要な値に対して \begin{align*} \frac{A_1/10}{A_0} = \frac{2}{10\pi} \approx 0.063 \end{align*} となってつまり、約6%のさざなみが信号に乗ることになる(実際にはこの場合さらに奇数次が乗る)。具体的に言えば、例えば0〜3.3Vのアナログ信号をPWMと基本波の1/10をカットオフの1次ローパスで作ったとき、1.65Vを出力するつもりが1.55〜1.75Vで揺らぐ、ということになる。絵に描いてみると
1026tithe.png
てな感じになる。

これを大きいとみるかどうかは、アプリケーション次第である。しかし、Pi Picoは本家Raspberry PiのハードウェアPWMに比べると5倍以上クロックが高いけど、もう少しS/Nも帯域も欲しい場合がある。

というか、100Hzぐらいまでの狭帯域なら本家Raspberry Piでもなんとかなる。それより帯域が必要なら外付けのMCP4922(500ksps)みたいな使いやすいDACから、もっと必要ならアナデバの高級なやつになるけど、それだとそもそもPWMじゃないので急に500kHz〜10MHzぐらいの帯域にできる。その中間ぐらい、帯域として10kHzぐらいのがあるといいな、と思った。

PWM+ローパスでの基本波の漏れだしでS/Nが劣化するのが嫌なら、ローパスをもっと高い次数にしたり、ノッチと組み合わせるとか、カットオフをずっと下げればいい。しかし次数を上げるのは回路が複雑になって半田付けが面倒になる。ノッチフィルタは基本波の周波数ぴったりの定数があれば効果的なんだけど、なんにしても外付け回路はできるだけ少なくしたい(目もしょぼくなって2.54mmピッチさえチカチカする)。またカットオフを下げるのは分解能と帯域の兼ね合いがあるので、できればなるべく高いほうがいいに決まっている。

そもそもPWM信号はローパスに通してアナログにするには基本波成分が多すぎる、という気がしてきた。つまり0と1の時間方向の比率でアナログにしているのに、PWMでは0ばっかり1ばっかりが続くのでそりゃ基本波成分ばっかりになってあたりまえだわな、ということである。

もっと賢い$\Delta \Sigma$でPDMを使えばいいのかもしれないけど、原理的にはアナログフィードバックループなので結構難しい。Pi PicoのPIOで実装している猛者がいるけどPIOの使い方が難しくて勉強しないとわからないのと、そもそもアナログフィードバックをどうやってPIOのクロック(それはPi Picoのシステムクロックと同じ)に同期させるのかというあたりが僕には難しくて敷居が高い。

そこでちょっと違うことを考えたい。

2  基本波成分を減らす

PWMで基本波成分がなんで多いか、というと、1の数が同じならどんな並びでも原理的には同じなのに、PWMでは基本波の中に1回しかレベル反転がなくて1と0が連続するパターンになっているから。

簡単のために16クロックで1周期になっているPWMを考える。例えば基本波成分が一番多いデューティ比50\%の場合を考えると下の絵の一番上のように8クロックHで8クロックLというような波形になる。デューティ比25%の場合はその下の4クロックHで12クロックLとなって、デューティ50%の場合よりは基本波成分は減ってその代わり2倍の高調波成分が増えるけど、やはり基本波成分が支配的になる。

これはFourier展開すれば定量的にもわかる(前回やったのでもうやらないけど)。
1026pwmduty5025.png
1周期の中になるべくたくさんの反転を入れてやれば同じデューティ比で(同じ0と1の比率で)基本波成分を減らして、基本波より高い(クロックに近い)方へ高調波のエネルギーを寄せることができて、ローパスは楽になるはずである。

しかし、デューティ比(1の出現確率)は同じで違うパターンが複数個ありえる。例えば同じ値が連続するとき、つまりローパス後はずっと一定の値になっているのが理想的なんだけど、違うパターンが現れると基本波よりもさらに低い成分が出てしまう。従って一つの値に対していつも同じパターンになるのが望ましい。1周期16クロックぐらいだったら手で割り振ってもいいけど、それでは分解能が少なすぎて汎用性が低い。なにかアルゴリズミックに生成する方法はないか考えてみた。

これは続く。
nice!(0)  コメント(7) 

nice! 0

コメント 7

snowhawk

例えば、16bit分解能で40000出したい場合、
MSBから4bit分解能の9を出力して、
次のPWM周期の出力を計算する際に、足りない出力:
 40000 - 9*4096 = 3136
を偏差として足していく、という処理を
ずっと繰り返していけば、時間平均としては所望の出力になるはずです。
by snowhawk (2021-11-01 11:50) 

decafish

コメントありがとうございます。

でもよく理解できません。
収束するまでドリフトするように思うのですが。それともビット幅が短いので基本波よりずっと短い時間で収束するということでしょうか。

このお話の場合は基本波の周波数はどんなふうに計算すればいいのでしょうか。
by decafish (2021-11-01 18:21) 

snowhawk

基本波が65536の時より、基本波が16の方がローパスがよくかかると考えたのですが、偏差ドリフトは常にしているかもしれません、すみません。
by snowhawk (2021-11-02 09:19) 

snowhawk

例えば、20MHzのマイコンで200kHzのPWMを使うと、0~100までの値しかとれません。
これで16bitの数値を表現しようとすると、1/660くらいの表現力しかありませんが、40000を表現するために、これを第一周期では、
660*{60+(400/660)}
と考えて整数分の60幅を出します。
次の周期では前周期で出力できなかった400を足した、40400を
660*{61+(140/660)}
と考えて整数分の61幅を出します。

こうやって帯分数として考え、除数以内の繰り越しを繰り返すという、ディジタルのピクセルに線分を描くようなアルゴリズムです。

搬送波は200kHzと比較的高速なので、カットオフの低いローパスフィルタでも高周波ノイズは抑えられるだろう、という考えです。

整数分が0か100に飽和すると、見かけの搬送波が数分の1に落ちるので、必ず反転するようにしたほうがよいかもしれません。

ここまで書いて気付いたのですが、この方法は長い単位時間あたりのパワー密度を厳密にコントロールでき、MSB側の成分を高周波に持っていけるのですが、LSB側は収束せずに循環しそうです。

それが大きいか小さいかは… よく考えてみます。
by snowhawk (2021-11-03 01:09) 

decafish

ちょっとだけわかったような気がします。

たとえば20MHzで16ビット分解能を得ようとすると単純には基本波の周期は300Hzになりますが、それよりずっと高い200kHzでこのアルゴリズムを使えば低分解能でも単純16ビットより十分速く収束して帯域を確保できるのではないか、ということですよね。

割り切れる値の場合はそのままなので帯域を喰うことはない、割り切れない場合は最終的に振動する(PWMのパルス幅が揺れる)ことになって、その周期のぶんだけ帯域を喰うけど、たとえ振動の周期が長くてもパルス幅の揺らぎなので200kHzより低い成分はかなり小さいはず、ということですよね。

なるほど。これは面白いです。
なんだか劇的に低い周波数成分が減らせそうな気がします。
by decafish (2021-11-03 12:06) 

snowhawk

そうです!
割り切れない成分はジッターみたいになるので、
搬送波のスプリアスになるんじゃないかなと思ってます。
by snowhawk (2021-11-04 14:02) 

decafish

なるほど、まさしく「スプリアス」ですね。PWMの長さの揺らぎなのでジッタによるスプリアスを考えるのと全く同じ計算が使えます。

普通ジッタは符号間干渉とランダムノイズなんかを仮定しますが、意識的にある規則で振ったジッタによるスプリアスのスペクトルがどうなるかを計算すればいい、ということですね。

面白いです。やってみよ。
by decafish (2021-11-04 15:40) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。