電子回路わからん日記

にゃーんと言いながら電子回路いじってます

リアルタイムDSDコンバータのシミュレーション

前回の続きです。

audio-diy.hatenablog.com

 

今回は前回作成した関数を用いてPCMからDSDへの変換のシミュレーションを行います。


シミュレーションの流れ

前回でもお伝えしたかと思いますが、ここで改めてシミュレーションの流れを伝えます。

  1. 浮動小数点数で正弦波を作る
  2. 正弦波を浮動小数点数から符号付き整数(リニアPCM)へ変換
  3. リニアPCMを0次ホールドで64倍に補間(I2SのBCLKを模擬するため)
  4. 補間したデータを1次ΔΣ変調
  5. 変調したデータをローパスフィルタに通しリニアPCMの正弦波と比較

ざっとこんな感じです。


シミュレーションプログラム

シミュレーションプログラムは下記GitHubにアップロードしています。

github.com

 

実行して得られた画像は下の通りです。振幅は[-1, 1]の区間に正規化しています。

最初DSDを通すローパスフィルタは実回路を模すためにIIRで試したんですが、発散してしまいグチャグチャになったので今回は簡単のため10タップの移動平均フィルタです。このあたりもしっかり勉強しなくちゃですね・・・・

f:id:AUDIY:20211227001422p:plain

10タップと次数が小さいのでアレですが、平均化されたデータとPCMデータの振幅値はほぼ一致していますね。

 

1次ΔΣ変調はちゃんと機能していそうです。


ということで、次回からこの「リアルタイムDSDコンバータ」FPGA内部の回路として落とし込んでいきます。

 

実は低次のΔΣ変調であればシミュレーションプログラムをコーディングするよりもFPGAに落とし込む方が簡単だったりします。

 

もちろん、FPGAに落とし込むために作成したVerilogコードもGitHub上で共有できればと思います。

 

I2Sを受けることができるようになったので・・・

電子回路主体のブログのはずなんですが、だんだんと組み込み一辺倒になってしまっています。良くない良くない・・・・

 

FPGAの開発の模様も記事にしていけたらと思います。

 

実はAUDIY、FPGAもやっていまして、

ちゃんと評価ボードも持っています。ちなみに愛用している評価ボードはDE10-Liteです。いずれはXilinxの開発知識も身につけたいですね。

www.marutsu.co.jp


何を開発しようか

もともと自作オーディオに興味を持ち、そのために回路の勉強の報告をしていくのが当ブログのモチベーションですから、やはりここはオーディオ関係でいきたいと思います。

 

ここは最も単純なものとして、低次(~2次)のΔΣ変調を利用したPCM-DSD変換から始めてみたいと思います。

 

DSD変換を選んだ理由として

  • 基本的に加算、減算、遅延(フリップフロップ)、ビットシフト、ビット選択の要素だけで作ることができる(シンプル)。
  • PCMサンプリング周波数の64倍のDSDサンプリング周波数であればI2Sのビットクロックに同期してリアルタイムに変換可能(I2SのBCLK周波数がLRCK周波数の64倍であるため)。
  • 音質や特性はさておき、DSD変換後はカップリングコンデンサとアナログフィルタを通せば音声出力可能(DA変換自体は容易)。

 

たとえばこれがDSD→PCM変換だと

  • DSDの高周波ノイズを抑え込んでPCMに変換するには高性能なデジタルフィルタが必要
  • デジタルフィルタの性能を高めるために周波数の高いマスタークロックが必要
  • FPGAのロジックを圧迫しないためにRAM IPなどを上手く組み合わせる必要がある

と、長期化と入念な検討が必要になるのでこれはまたの機会とします。


まずはシミュレーション

そうと決まれば、FPGAに実装する信号処理をまずはソフトウェアに落とし込んでシミュレーションします。

 

こういうときに結果をすぐにプロットできるPythonは便利です。

余談ですが、AUDIYはPythonエンジニア認定基礎試験合格者の資格を持っています。持ってて損はないと思いますので興味のあるかたはぜひ挑戦してみてください。

www.pythonic-exam.com


シミュレーションの流れ

大まかに以下の流れでPCM→DSD変換をシミュレーションします。

  1. 区間[-1, 1]の浮動小数点数で正弦波を作成
  2. 任意の量子化ビット数を持つ符号付き整数(PCM)に変換
  3. PCMに変換した信号をΔΣ変調(パルス密度変調)の計算で使用できるように0次ホールドでアップサンプリング
  4. 0次ホールドした正弦波をΔΣ変調する
  5. 変調して得られたPDM波形にローパスフィルタをかけて正弦波が得られるか確認する

この流れをPythonプログラムに落とし込んでいきます。


作成した関数の説明

今回は一次ΔΣ変調のシミュレーションを紹介したいと思います。

今回のシミュレーションに伴い、以下3つの関数を作成しました。

  1. 浮動小数点数リニアPCMに変換する関数
  2. リニアPCMを0次ホールドで整数倍アップサンプリングする関数
  3. アップサンプリングされた信号を一次ΔΣ変調する関数

この3つの関数について以下説明です。

1. リニアPCM変換関数LPCM(x, nbits)

浮動小数点の信号配列xを任意の量子化ビット数nbitsを持つリニアPCMに変換します。

変換の数式は、現在の離散時間における入力をx[i]、出力をy[i]、所望の量子化ビット数をnとすると

 

f:id:AUDIY:20211216145032p:plain



となります。ここで、はxの床関数を表します。

 

これをPythonの関数にするのは比較的容易です。numpyを利用して配列全体に計算を適用できるので高速です。

import numpy as np
 
# float to Linear PCM Conversion
def LPCM(x, nbits):
    xmax = np.max(x) # Maximum float Amplitude
    xmin = np.min(x) # Minimum float Amplitude
   
    # Quantization
    x_LPCM = np.floor(((x - xmin)/(xmax - xmin)) * (2 ** nbits - 1) + 0.5) \
        - (2 ** (nbits-1))
   
    return x_LPCM.astype(int)

2. 0次ホールド関数ZeroOrderHold(xPCM, OSR)

「0次ホールド」は、内挿するサンプルの数値をもとからあったサンプルに維持する内挿方法です。

これはScipyのsignal内にあるupfirdn関数を使えば高速に実行可能です。

docs.scipy.org

import numpy as np
import scipy.signal as signal
 
# Zero-order Hold Linear PCM Upsampling
def ZeroOrderHold(xPCM, OSR):
    y = signal.upfirdn(np.ones(OSR), xPCM, OSR)
   
    return y

3. ΔΣ変調関数PDM(x, nbits)

こればかりは自作になります。

しかも都度誤差を更新しないといけないので、ループを回すしか方法はないと思われます。

関数はこちらを参考にします。

ja.wikipedia.org

技術系のブログにWikipediaというのも気が引けますが、まずは手を動かすための情報としてこちらを参考にしました。

基本的にはWikipedia内の擬似コードそのままですが、フィードバックの量子化誤差計算で1bitのDSD信号をPCM信号xの振幅nbitsまで最大化して計算するように変更しています。

import numpy as np
 
# 1st-order Pulse Density Modulation
def PDM(x, nbits):
    qe = 0 # Quantization Error
    y = np.zeros(np.shape(x)[0]) # Return Array
   
    # Modulation
    for i in range(np.shape(x)[0]):
        if x[i] >= qe:
            y[i] = 1
        else:
            y[i] = 0
         
        # Maximize the Modulated Signal to PCM max Amplitude
        yi_Analog = np.floor((((y[i]*2 - 1) + 1)/2) * (2**nbits - 1) + 0.5) \
            - (2 ** (nbits-1))
       
        # Calcurate the Quantization Error
        qe = qe + (yi_Analog - x[i])
       
    return y.astype(int), qe

 


と、関数を紹介していたら記事が長くなってしまいました。

シミュレーションそのものは次回としたいと思います。

 

 

AUDIY、STM32マイコンを始めるってよ

お久しぶりです。

 

突然ではありますが、STM32マイコンの評価ボードの一種であるNUCLEO-F411REを秋月電子から購入しました。

akizukidenshi.com

 

もともとマイコンにも興味があったんですが、最近は特にマイコンプログラミングの必要性を感じずにはいられませんでした。

 

というのも、

  • オーディオ用DAコンバータの殆どは設定をI2CまたはSPIで行う
  • FPGAでアップサンプリングなどの信号処理を実装し、動作確認としてDAコンバータと接続したい
  • 確認用のDAコンバータの設定にI2CやSPIでの制御が必要になる

 

というのが理由です。


探すのに一苦労

で、探し始めるわけですがこれがなかなか難しかったです。

求める条件としては

  1. I2C/SPIが出せるもの
  2. デバッガが一体となっていること
  3. PCと接続してプログラムするもの

といったところです。

 

常々マイコンを使っているという方であればPICやAVRマイコンのICを単体で購入して・・・という手順を踏むのだと思いますが、何もしたことがないAUDIYからしたらデバッガやライタなどを別途揃えるというのも不安でした。

 

また、I2Cが出せるのかというのも、明確な記載がされているものが少なく(「そこが組み込みプログラマの腕の見せどころ」ということでしょうか?)、目星をつけても決定打に欠けるという印象です。

 

また、条件3の時点でラズベリーパイは無し。

 

・・・とまぁそんなこんなで調べて行き着いた候補が

の2つとなりました。


STM32を選んだ理由

最終的にArduinoかSTM32-NUCLEOかに決めるわけですが、

  1. ペリフェラルの数が最も一般的なArduino Unoより豊富
  2. Arduinoより安価
  3. 開発環境含めArduino互換
  4. Arduinoより実務より(?)

という理由からSTM32に決定しました。

最後の理由はAUDIYの偏見が入っていますが、Arduinoが実際の家電に入っているという例は聞いたことがありません(まぁマイコンIC自体はAVRですから・・・)。

 

「ひょっとしたら実務でも扱われているような開発環境で勉強しておけば今後役立つときが来るかもしれない」という淡い期待です。


注文

で、このSTM32-NUCLEOボードなんですが、

どのマイコンICが載っていても大きな価格差がありません。

 

akizukidenshi.com

 

秋月だと1500円~2000円で購入できます。

ということで、本来であれば秋月の取り扱いの中で最も高性能なNUCLEO-F446REが欲しかったですが、在庫切れとのことでその次に高性能なF411REを購入しました。

www.st.com


開封

シンプルです。本体と簡単な説明書きのみです。

f:id:AUDIY:20211212161757j:plain

 

USBケーブルすら入っていないというシンプルさ。

 

そして本体も想像より小さかったです。

f:id:AUDIY:20211212162102j:plain

Raspberry Piより長さが少し短くなり、若干幅広になった感じです。

 

ボード上にスリットがありますが、それより上の部分がデバッガ/ライタとなっています。

 

USBケーブルはUSB Mini-Bとなっているので要注意です。

AUDIYもまんまとやられました・・・


早速試してみる

STM32純正の開発環境(STM32CubeIDE)でさっそくプッシュスイッチに連動するLチカの実践動画があったので試してみました。

もともと学生までずっとプログラミングしていた人間だったのですが、組み込みソフトウェアというのは本当に初めてなもので、ソースコードの内容を未だ全ては理解できていませんが、なかなか新鮮で刺激がありました。

 

開発環境のSTM32CubeIDEですが、ECLIPSEベースのIDEらしく、「ECLIPSEベース」から想像していたのとは裏腹に軽快に動作していました。

 

また、ピンアサインをGUIで決定できるというのはとても直感的でわかりやすいと感じました。


Arduinoスケッチでも動作させてみる

Arduino IDEでもSTM32用の設定をすれば開発可能とのことで、正弦波をPWMで出力してLEDを点滅させてみました。

 

Arduino IDEの設定はこちらを参考にしました。

ameblo.jp

 

const int pwmpin = 10;
const double pi = 3.14159265;

void setup() {
  // put your setup code here, to run once:
 
}

void loop() {
  // put your main code here, to run repeatedly:
  int led_value = 0;
  for (int i = 0; i < 1000; i += 1 ) {
    led_value = (int)(255 * (sin(2*pi*(double)i/1000)/2 + 0.5));
    analogWrite(pwmpin, led_value);
    delay(1);
  }
}

 

Arduinoスケッチ、記法からして明らかにC言語派生ですが基本的なプログラムならライブラリのincludeが不要など、比較的優しい仕様になっていると感じます。

ただ、Arduino IDEからの書き込みは数分待つ必要があるので、早いところSTM32CubeIDEに慣れてしまったほうが良いかもしれません。


以上、STM32マイコンの購入報告と、「組み込みプログラミング界のHello World (?)」であるLチカを試してみたという報告でした。

 

STM32マイコンそのものはARMなので、知識さえ身につければかなり高度なプログラミングが楽しめるかと思います。

 

電子工作のかたわらマイコンプログラミングの技術も少しずつ身に付けて行きたいです。

 

 

自作リニアレギュレータの正電圧側の謎をLTspiceで解析してみる

前回は正電圧側のドロップ電圧が大きすぎることがわかりました.

audio-diy.hatenablog.com

 

この原因を定電圧源にテスターを当てて観察する前に,LTspiceで原因が推測できないか見てみました.

 

全く同じではないですが,最低限必要な部品で構成したシミュレーション回路で見てみます.

f:id:AUDIY:20211121135226p:plain

 

まず気になってたのは,正電圧側に発生した2V周辺での急激な出力上昇.

f:id:AUDIY:20211005014827p:plain

 

これはLTSpiceでも観測されました.

f:id:AUDIY:20211121135329p:plain

0.4~0.5Vあたりに急激な出力電圧の上昇が見えます.

 

まずはダイオード単体の電圧を見ます.

出力と同様の曲線を描いています.(青色がダイオード,緑色が出力)

f:id:AUDIY:20211121135537p:plain

次に,ツェナーダイオードに電流を供給するトランジスタ(2SA1312)のベース・コレクタ間電圧(シアン色の曲線)と,ベース電流を決定する10kの抵抗の電圧(赤色の曲線)を見ます.

 

急激にベース・コレクタ間電圧が下がると同時に出力電圧が上昇している様子がわかります.

f:id:AUDIY:20211121140029p:plain

また,出力が5Vに安定してからはこのベースとコレクタの間の電圧降下が上昇するのもわかりますね.

 

次に,同じくツェナーダイオードに電流を供給する2SA1312のベース・エミッタ間電圧.(マゼンタ)

f:id:AUDIY:20211121140401p:plain

なるほど.トランジスタの動作が始まる(ベース・エミッタ間電圧がおよそ0.6V)ポイントでこれが起きているようです.

 

最後に,同じトランジスタのコレクタ・エミッタ間電圧(マゼンタ)とベース・エミッタ間電圧(緑)を見るとなんとなく理由がわかってきます.

f:id:AUDIY:20211121141425p:plain

ツェナーが出力を開始するまでトランジスタのコレクタ・エミッタ間電位差が上昇しています.

 

おそらくはこういうことかと思います.

では負電圧側はなぜこの盛り上がりが発生しないのでしょう?


負電圧出力も見てみる

同様に2SC3324側のコレクタ・エミッタ間電位差の推移も見てみました.

f:id:AUDIY:20211121143215p:plain

なるほど.2SA1312側は電位差が増えていくのに対し2SC3324は能動領域に近づくにつれ電位差が減少していくようです.

 

なので正電圧側の急激な出力電圧の変動は負電圧側では起きないということでしょう.


今回はコンプリメンタリでも遮断領域→能動領域での遷移でベース・エミッタ間電圧とコレクタ・エミッタ間電圧の関係が異なるという事例をシミュレーションベースではありますが掴むことができました.

 

正電源側も不電源側も同じトランジスタで定電流源を作ることができれば解決しそうですが,電源電圧を遷移させて動かす回路でもないのでその必要はなさそうです.

 

ちなみに,正電源側のドロップ電圧が大きい理由はシミュレーションではつかめませんでした.いよいよテスターで当たり直す必要がありそうです.

 

今回も最後までお読みいただきありがとうございます!

自作リニアレギュレータの入出力電圧特性の計測

久々にリニアレギュレータの話題です.

 

audio-diy.hatenablog.com

 

実際に直流安定化電源とAnalog Discovery 2を使って,(ほぼ)無負荷で入出力電圧特性を計測してみました.

 

で,計測した結果をグラフにしたんですが,

 

こちら正電源側.

f:id:AUDIY:20211005014827p:plain

 

そしてこちらが負電源側.グラフを視覚的に比較しやすいよう,こちらは符合を反転させています.

f:id:AUDIY:20211005015016p:plain

 

負電源側の入出力電圧差が1V前半なのは,エミッタ出力でダーリントンのフォロワを最終に入れているので「こんなもんかな」と納得がいきますが,正電源側の入出力電圧差が3V近いのは電源レギュレータとしてはあまりにも不便すぎる特性です.

 

いちおう9V以上で安定動作することを目標としていたのでそこはクリアできていますが,正負でこれだけの差があるというのも不思議です.全てコンプリメンタリトランジスタで構成していますし.

 

今回のレギュレータは全帰還をかけているため,最も怪しいのはツェナーダイオードに電流を供給する定電流源かと思われます.(ツェナーダイオードの電圧が固定されるまでの十分な電流が供給されていないと予想しています.)

 

次回はツェナーダイオード直近の入出力電圧差を計測し,ここが本当に原因なのかを探っていきたいと思います.

IP2721-MAX12を入手した

ちょっと気になっていたICがあり,価格も安かったため入手しました.

このIC一個でUSB PDの固定電圧を取り出せます.

pdqc.net

pdqc.net

 

似たような機能のICはRohmから出たりもしていますが,外部電源からの給電が必要だったり,制御が必要だったり周辺部品が多かったりします.

www.rohm.co.jp

 

今回購入したICはIC本体と周辺部品10点未満でPD給電環境を構築可能なので,当ブログ管理者のようなド素人にはうってつけです.

 

早速基板も描きました.

IP2721のシンボルやフットプリントの登録があったので,今回はいつものKiCadではなくEasyEDAで描きました.

f:id:AUDIY:20210903025545p:plain

これどう考えてもUSBコネクタのハンダ付けはリフローじゃないと実装できそうに無いですね・・・・

 

IC買った,基板描いたはいいですがどないしましょ・・・・

 

通信部分でのクロストークを軽減するためにちゃんとGNDを挟んでます.(ちょっと幅が狭い気もしますが・・・・)

f:id:AUDIY:20210903025947p:plain

給電専用のUSB Type-C オスコネクタがあれば良いんですが見つけることができませんでした・・・

 

とりあえず基板を発注したいと思います.

 

やらかしレギュレータ基板設計

やらかしカテゴリ2回目,今回は,現在シリーズで進捗を報告している「自作リニアレギュレータ」です.

audio-diy.hatenablog.com

基板が上がってきて

実装し,

いざ,評価!

 

・・・・

 

・・・・・・

 

・・・・・・・・

 

これではオシロスコープを使うのもちょっと怖いです.


さっそく改良する

で,早速改良しました.

ピンヘッダの間隔を広げたはいいんですが,いざ届いたものを確認すると・・・・

・・・・

・・・・いや,おい!w


3度目の正直なるか・・・?

次に発注するときこそは成功させたいです.

失敗した基板を使わないのももったいないので,どうにかこうにかしたいと思います.

 

みなさま,基板を注文するときはくれぐれもお気をつけください.