おひさしぶりです
最近、音楽を聴くために小型USB DACを使用してスマホで聞くことが多くなってきましたが、個人的にこれがちょっとだけ不満です。スマホを充電しながら聞くことができないからですね。たとえば寝ながらイヤホンで音楽を聴きたいとき、スマホの充電を犠牲に朝を迎えなければいけないのです。これはよろしくない、ということで音楽鑑賞用のステーションを手に入れようとなりました。
しかし、最近の小型PCは安いですね~ 3万出せばそこそこのスペックのPCが手に入ります。
例) Bmax N5095搭載PC ¥29980 https://amzn.asia/d/05zies62
ただ、これを買ってDACを買って終わり...じゃ芸がない。ということでみんな大好き、Raspberry Piを使ってミュージックステーションを作ってやろうとなりました。
あ、このプロジェクトは時間がかなりかかる予定のため、ゆっくり更新していくシリーズ形式にしようと思います。リアルで時間がない。この記事は実機を試作段階まで完成させた状態で書いているため、今後基板実装やら改良やらでちょくちょく今後の記事との齟齬が出ることがあります。ご注意を。
制作開始!
使用するPiはRaspberry Pi zero2 Wです。Piシリーズの廉価版であるzeroの後継版ですね。512MBのメモリという制限付きで5000円で購入できるため、今回のような負荷の軽いアプリケーションでは最適です。
で、このプロジェクトではI2Sを使用しません。PCを切り捨ててPiを使うってなったのだから、せっかくなら芸に振り切って、GPIOからのPWM出力を採用します。音質悪そ~って思ったそこのあなた、これはお遊びです。
音楽再生に使うOSはmoOde Audio。Volumioの方が有名で使いやすいとは思いますが、機能的に(Hardware PWMを使用する関係で)moOdeを選択。Volumioでもできるかもしれませんが、moOdeはPWM mode選択によりΔΣ変調を使用したPWMを出力できるため、普通のPWMより高音質です。
注意!
Piから出るPWMをイヤホンに直結すると壊れ(る可能性があり)ます!
絶対にアッテネータを使用してください!
大音量で鼓膜とイヤホンが壊れ(る可能性があり)ます!!!
次は試作段階でのソフトウェア系の設定です。moOdeの設定はかな~り詳細に設定できます。Config.txtでの設定、ネットワーク関連の設定、MPDの設定などなど...
moOdeのインストールはいろんなサイトで紹介されているのでスキップして、とりあえずconfigの設定から行きましょう。あ、モニターレスで設定する場合はSSHできるようにちゃんとWiFi設定してSSH許可してくださいね(1敗)。
config.txt
micro SDカードに直接書き込む設定ですね。Win PCにmicro SD to USBなどして認識させ、その中のconfig.txtを開くことで編集できます。もしくは、SSHなどで接続して直接書き換えることもできます。
ここでは設定した、設定するべきものを羅列します。
dtparam=audio=on
dtoverlay=audremap,pins_18_19
これを記述することで、(たぶん)初期設定であるPWM Audioの出力をGPIOのpin12(GPIO18), pin35(GPIO19)に設定できます。Pi4のようなデフォルトでイヤホンジャックがついているならこの設定はいらない?のかもしれませんが、のちの高音質化のためにもこの設定は必須です。
audio_pwm_mode=2
PWM modeを変更する設定です。helpを見るとデフォルトでのmodeは2になっているようですが、勝手に変更されたりしないようこの設定で固定します。
ちなみに、modeについては0が通常のPWM、1がちょっと音質の上がったPWM(詳細不明)、2はΔΣ変調を用いてノイズシェーピングをかけたPWMのようです。
PWMと言いながら本質的にΔΣ方式の1bit DACに近づいている気がしますが、気のせいです。
arm_freq=1000
arm_freq_min=1000
core_freq=400
core_freq_min=400
これはPiのコアクロック周辺の設定です。arm_freqはメインコアの周波数を設定でき、core_freqはGPU周辺のコアの周波数を設定できるようです。それぞれ_minと付いているのはその名の通り下限を設定できるようです。
PiのPWMはcore_freqをもとに分周したクロックを参照して出力しているようで、デフォルト設定での「負荷によってクロック周波数を変化させる」、よくある挙動はオーディオにとって巨大なジッタになります。ここでクロックを固定するとジッタを軽減できるわけです。
disable_audio_dither=1
ディザーをOFFにする設定です。ΔΣ変調PWMを生成するため、ディザーは必要ない...はずです。ノイズシェーピングしてSNを稼ぐのに、ノイズフロアを上げる必要はないですからね。しかも12bit精度のためノイズフロアを上げるのはさすがに抵抗があります。
pwm_sample_bits=12
PWMの精度を変更する設定です。デフォルトで11bitありSNは68dB程度ありますが、ちょっと物足りない。12bitにすることでSNを74dBまで稼げるためこの設定を採用していますが...
この設定、音源のサンプリングレートを48kHzだと仮定して、12bit精度のPWMを生成するためには、2*48000*2^12 = 393,216,000 ≃ 393MHzのクロックを要求されます。core_freq 400MHzをそのまま使っているとするなら大丈夫ですが、しっかり動作しているか不安なラインです。プラシーボでの効果を期待する設定です(笑)
設定するべきものはこんな感じになります。これらを# General settingsの下に記述していくだけなのでかんたんですね。
オーディオ出力設定
moOdeからPWMを出力するための設定たちです。
1. 出力設定
初っ端から難関です。ホーム画面右上の[m]からConfigure、Audioと開くと設定画面が出ます。上記のdtparamとdtoverlayをconfigへ記述していて、なおかつ再起動されているなら、OUTPUT Device一覧に [Pi Headphone jack] という項目が見つかると思います。これを選択して完了ですが、なぜか出てこないときがあります。そういうときは再起動やconfigへの記述ミスなどを確認し、だめならchatGPTにぶん投げましょう。
Named I2Sやor DT Overlayの設定は無視で大丈夫です。適当にNoneにしても問題ないです。
次にちょっと下の方にALSA Optionsというものを探し、そこのOutput modeをDirectにしましょう。オーディオのコンバート回数が減るため高音質化が期待できますが、まぁ知覚できないと思われるためプラシーボ効果に期待しましょう。
2. MPD設定
moOdeに同梱されている音楽再生モジュールであるMusic Player Daemon、公式略でMPDの設定ができます。[m]→Configure→MPDから遷移でき、ここではSoX ResamplingやらReplay Gainやらその他音楽再生に関わる設定ができます。
個人的にはリサンプリングはOffでいいです。一応ΔΣPWMは時間軸方向への分解能が高いため事前にアップサンプリングしたときの高音質化は見込めますが、これも知覚できないためいりません。なんなら、ただでさえカツカツなCPU負荷とメモリ使用量を増やしてしまうため非推奨です。
逆に、Replay Gainは超推奨します。人間の耳は1dB音が大きくなっただけで高音質化した、1dB小さくなっただけで悪化したと錯覚してしまうほど軟弱なセンサのため、リプレイゲインによる音量の均一化は有用です。PC側での作業が増えますが、まぁ...
して、もっと重要なのがReplay Gainの一個下、Resource allocationです。オーディオバッファの設定ですが、これをちゃんと設定しないとプツプツとノイズが乗ります。一度長めの時間音楽を流してみて、ノイズが乗らない程度にバッファを増やすことをお勧めします。SoXをONにするならこの調整は必須です。
3. System設定
[m]→Configure→Systemから遷移できる設定で、ここではシステムの設定ができます。小泉構文みたい(笑)
Startup optionsのPerformance、その中のWorker ResponseとCPU Governorが重要な設定です。Worker Responceはlocal UIやWeb UIのレスポンス向上の設定で、私はDefaultにしていますがBoostedにしてもよさそう。CPU使用量は増えると思われるので、その辺の調整は必要だと思います。
CPU GovernorはPerformance一択です。先に設定したarm_freqやcore_freqを、負荷によって変動させなくするという設定です。configで設定しているため不要かもしれませんが一応。
4. Camilla DSP
moOde内蔵DSPの設定で、 [m]→Configure→Camilla DSPから遷移できます。私はDSPを使用しないタイプの人間なのでほとんど知見がありません。DSPがないと生活できないよって方はchatGPTに丸投げしてみてください。
お疲れさまでした。これでいったんソフト関連の設定は終了です。
アナログ回路
残念でした。これからもっと長いお話です。
高音質なPWM再生にはいろいろ考えなければいけないことがありますが、基本的によく言われる高音質化の要素は、
・低ノイズ
・低ひずみ率
・過渡応答のきれいさ
・周波数特性のフラットさ
などなどあると思います。個人的な指標の話をするとDACは基本的に音質の違いはなく.... などと書くと荒れそうなので下の方で...
話を戻して、PWMは原理的に直線性がよく、ひずみ率は低いことが多いです。ただしそれは理想的な話であり、現実はキャリアノイズ周波数とその逓倍周波数のスペクトル、デューティー比の変化による変調ノイズ、SoCからのノイズ、WiFiモジュールからのノイズ、コンセントやACアダプタ、DCDCからのノイズ、PWM波形のリンギング... ノイズに関してを軽く挙げるだけでここまで文章量がかさみます。これらと他にもいっぱいあるノイズ源やひずみ源のせいで、ひずみ率やそれにノイズを含むTHD+Nは市販品よりかな~り悪くなります。つまり設計による変動が大きいってことです。
ということで、試作として組んだ回路のブロック図がこちら。

電源入力やら音楽入力やらを省いた、単純なブロックとしてはこんな感じです。M78シリーズの5V1A DCDCを使用してACアダプタ―からの電圧を5Vに降圧、それを直接Piにかけるほか、NR1640という日清紡から販売されている超高性能LDO ICに流し、高精度な3.3Vを生成します。その電圧は74シリーズの高出力バッファへ入力してPWMを成形、その出力を4次サレンキー型アクティブローパスフィルタへと入力し、そのオペアンプを出力バッファとしても機能させている、といった感じです。
このブロックで気を付けたいのは3点、DCDCのノイズ、論理バッファのノイズと出力インピーダンス、アクティブフィルタのオペアンプ選定です。
1. DCDCの選定
このプロジェクトをするにあたってDCDCを2つ用意しました。Minmax社製 M78AR05-1 と、Rohm社製 BP5293-50 です。どちらも5V1A出力のものですが、同じ条件で100mA流してノイズを測定したところ、どうにもBP5293-50のノイズが大きすぎる。M78AR05-1が優秀過ぎる可能性もありますが、今回のプロジェクトではM78AR05-1を採用します。もし秋月電子で部品を調達する方は参考にしてください。
2. 論理バッファの選定
TC74HC541APは古いICですが、±35mAまで流せる優秀な論理バッファです。これ以外にもいろいろ論理バッファはありますが、入手性、価格、DIPであることなどを考慮して試作品にはこれを使いました。ただし、バッファICを使用する上で2つ注意しなければならないのが、出力インピーダンスと電源のインピーダンスです。
出力インピーダンスが低くとも50Ω程度あります。先にあるLPFのオーディオ帯域の入力インピーダンスが低いとノイズをよく拾ってしまいます。ついでに出力の直線性を失ったりひずみ率が高くなったりします。ご注意を。
もう一つは電源のインピーダンスです。内部でFETを高速でスイッチングする都合、大きめのノイズを撒きます。NR1640のロードレギュレーションはかなり高水準のためそこまで心配する必要はありませんが、電源ラインのインピーダンスとデカップリングは注意したほうがいいです。PWM波形がそのままオーディオ波形になるため、ここでノイズが発生するとそれがそっくり出力に出ます。
3. アクティブフィルタ用オペアンプの選定
アクティブフィルタ用オペアンプにはISL28290を選定しました。これは
・SR 50V/us
・GBW 170MHz
・en 1nV/√Hz
・Io 135mA
・Vos 240uVtyp
・tset 45ns @1Vpp Cl1.2pF
とまぁ~高いスペックを持つRenesas製CMOSオペアンプです。まぁ製造終了しちゃったんですけどね。
ここで重要なのがGBWとセトリングタイムですかね。サレンキーはその性質上GBWが性能に直結します。GBW以上の高周波がフィルタを貫通してゲインが上がる(0dBを超えることはない)ため、発振気味にならない程度でなるべく高いGBWが欲しいわけです。3.3Vinでそれが実現できる唯一といっていいほどのオペアンプだったんですが、EoSで新しいものを探さなきゃいけない現状です。
一応、3PEAKという中国メーカーのTPH2502というオペアンプがSR200V/us、GBW120MHz、en6.5nV/√HzとISL28290には及ばないものの張り合える程度のスペックがあります。
ちなみに面白い小ネタ?ですが、ISL28290のデータシートのAbsolute Maximum Ratingsの一番上、Supply Voltage の単位がmAになってます。おもしろいね。
最後は簡単。ブレッドボードに組んで終わりです。

めっちゃ長いブレッドボードにすべてのコンポーネントを配置して配線するだけです。部品選定の100倍楽です。
ここで注意することはいくつかあります。
1. DCDCはなるべくPiの近くに、 LDOは74HCのなるべく近くに。
Piは基本3.3Vで動作するため基板にVin to 3.3VのDCDCが乗っています。ここからのノイズが結構大きいため、なるべくLDO側にそのノイズが飛ばないようDCDCを最短距離を目指します。
また74HCは先に言った通りノイズに敏感なため、なるべくLDOの近くに配置してインピーダンスを下げます。また積セラコンを配置してノイズをセラコン側に吸収してもらいましょう。また、今回使用したNR1640 LDOはかなりCのESRに敏感なようで、1uFのセラコン1つでは全く足りません。なるべくコンデンサを複数並列に接続してESR・ESLを下げ、発振を抑制します。ついでにラインのインピーダンスが下がるため一石二鳥です。
2. ACアダプタからのノイズ抑制
ACアダプタは回路で使われてるDCDCの100倍くらい(盛った)ノイズが大きいです。まだボード側からの伝播ノイズも大きめです。ACアダプタのコードにはフェライトコアを装着し、DCジャックのそばには1uF程度のフィルムコンデンサを載せることをおすすめします。
3. 74HCからフィルタへは最短距離で
これは当たり前かもしれませんが、74HCとフィルタ入力のラインはノイズが乗りやすいです。このラインをなるべく短くすることがノイズを減らすうえで重要です。
4. Piへのジャンパ線はツイストで
PiのGPIOは2列のためブレッドボードにそのまま差し込めません。そのため電源線やらPWM出力はジャンパ線での接続となりますが、電流が流れるジャンパ線(はほぼ1つしかないけど)はGNDのジャンパ線とツイストさせましょう。GPIOに5V入力は2つあるため、インピーダンスを下げるためにどちらにもジャンパ線を繋げることを忘れずに。また、GNDは8pin出てるので、それらすべてにジャンパ線を接続、またはツイストペアの意味を最大化するためにGNDを2本に絞るなど、各個人で工夫してください。
測定
せっかくここまで詰めたので、測定もしましょう。測定にはArturia Minifuse 2のFront XLR入力のLow Impiedanceを使用します。XLR - 3.5mm Lch Balanceケーブルを自作して、ホットにLch、コールドにGND、グランドにシールドを接続し、仮想的なバランス入力を形成します。
ということで結果をドン。

Perfect.
THDは0.08%(-62dB)と11bit精度を出せています。しかしTHD+Nは0.22%。とんでもなくノイズが大きいですね。ちなみに再度測定してわかったのですが、これグラウンドループによるノイズが思いっきり出ているようです。たしかにPCに接続したMinifuseと、PCと同じ延長コードから電源を取っているPiでループが形成されるのは理解しますが、XLRでバランス接続してGNDを切り離した意味isどこ?
モバイルバッテリーならTHD+N0.08%まで落ちるため、完全にグラウンドループが原因です。もうちょっと精度よく検証するなら、ADCを絶縁させるしかなさそうです。
ここからは画像なしですが、検証した特性を羅列します。
・SNR(モバイルバッテリー駆動) 66dB
・2nd Harmonic 0.054%
・3rd Harmonic 0.045%
・IMDpower 16kHz/17kHz(モバイルバッテリー駆動) 0.04%
全体的にPWMとは思えない特性です。ノイズに関しては電池駆動や絶縁電源による駆動を検証できていないため未知数ですが...
音については、まぁ他のDACと比較してどっちがいい!とかわかってしまったらそれは特性がよくないというのがわかるだけでして...
一応気づいたポイントとしては、音のアタックが鋭い気がします。次は矩形波出力してリンギングやらスルーレートやらを測ってみたい。
知見共有
このプロジェクトを進めるうえで気になったポイントをいくつか。
・ジッタが大きい
400MHz(core_freq)を分周してPWM用のクロックを生成しているようなので、44.1kHz/48kHz系の逓倍周波数を作るのに小数分周を使っているはずです。そのためとてつもなくジッタが大きいです。これはPWMに限った話ではなくI2S用のBCKを生成するのにも関係しているようで、さまざまなブログやツイート(現ポスト)で確認できます。私のほうでも、PWMのキャリア周波数が798kHzから800kHzまでパラパラと変化するのが見えてるため、小数分周をするうえでスペクトラム拡散しているのはほぼ確実です。クロックの外部入力も公式で対応していないため注意が必要です。性能についても天井が下がってしまいます。
・コア温度
コア温度が結構上昇します。といっても45℃程度のため小さいヒートシンク1つで事足りるとは思いますが、zero2のSoCの上にはRAMが載っています。はんだクラックが発生しないよう、温度管理をしっかりすることをお勧めします。
・音量
こんな下の方に書くな!という話ではあるのですが、PiからのPWMをそのまま出力すると音量がバカです。とんでもなく大きいです。フルスケール0.8Vrmsくらいあるんでしょうか。16Ω負荷だと40mWくらいになります。そのままイヤホンに接続したら壊れます。音量を下げればいいじゃんという話ですが、ソフトボリュームを使用するとビット落ちやSN悪化が発生するため、なるべく可変抵抗やアッテネーターによるハードウェアボリュームを実装しましょう。ちなみにアッテネータには最低でも-20dB、おすすめは-40dBです。私は-40dBのアッテネータを使っています。それでも感度123dB/Vrmsのイヤホン(Moondrop Kato)で、ソフトボリューム80%でちょうどいい音量です。
本当に耳にダメージが入ると修復不可ですから、注意してください。イヤホンならお金を出せばまた手に入りますけど。
・音質
上の方でちょっとだけ書きましたが、個人的な考えとしてはDACそれぞれに音質の違いは基本的になく、設計段階での電源の精度、出力インピーダンス、過渡応答、IMDとマルチトーン...この辺の値が悪いと音質が悪くなると考えています。というか、音質は引き算でして、最高音質は原音です。そこからひずみやノイズが加算されて音質は引き算されるという状態と考えると、例えばAよりBのほうが音質がいい!というのはBの回路が優れているわけではなくAが劣っているとなるわけです。で、今回のPWMオーディオは音自体はかなり好きな部類ではあるのですが、市販32bit USB DACと比べてしまうとさすがに市販品のほうが音がいいとなってしまいまして、つまりPWMオーディオは劣っているわけです。残念!
次への展望(備忘録)
今後の展望ですが、まず基板化です。ブレッドボードでは特性の限界が近すぎて、測定どころじゃないというのが本音です。
また、特性評価の項目を増やしたい。今のところひずみ率とフロアノイズ特性くらいしか測定していません。ということで次回測定の備忘録として、
・THD+N
・IMDpower
・SNR
・SINAD
・フルスケール(Vrms)
・直線性(dB)
・インパルス応答
・マルチトーン(60~240Hz 12tone, 100~10kHz 48/64tone)
・矩形波応答(1kHz, 10kHz, Reflected square)
このあたりを測定しましょう。忘れなければ。
ということで、ここまでお付き合いありがとうございます。次回の予定は未定です。ま~1年後くらい?(笑)












定電流はなにがいいか吟味した結果、一番右がもっともPSRRが高かったです。さきほどのPNP出力形に組み込みます。











