「#7-6 DA変換器を作る」では、アナログマルチプレクサを使って、4ビットDA変換器を作りました。今回は、その、4ビットDA変換器(手作り)を使って、更に、4ビットAD変換器を作ってみます。今回作るのは、原理が簡単で、比較的作り易いと思われる逐次比較型(Successive Approximation Register)AD変換器です。
英語の方が元でしょうから、直訳すると、「漸近レジスタ型AD変換器」ですが、意訳としての「逐次比較型」の方が原理をそのまま言い表していて、解り易いです。以後本ページでは、逐次比較型(SAR-)AD変換器および、逐次比較レジスタ(SAR)と称します。
回路は、サンプル&ホールド(S&H)回路、NビットDA変換器、比較回路、NビットSAR(逐次比較レジスタ)によって構成されています。以下にブロック図を示します。
この装置で、アナログ信号AINをNビットのデジタル値として、SARから読み出すことができます。
※Arduino UNOに搭載されているAD変換器は複数チャンネル(複数のAIN)を持っています。実は、AD変換器本体回路としては1ユニットしか搭載しておらず、複数チャンネルは、アナログマルチプレクサを使って、複数端子の中の1本を選択してAD変換しているだけです。ATmega328のデータシートを眺めてみると、どうやら、S&H回路の前に、アナログマルチプレクサが配置されているみたいです(つまり、S&H回路も1個だけ搭載)。
※蛇足ですが、STM32には、AD変換器その物も2ユニット搭載されていて、2ユニットの同時変換とか、インタリーブによる高速変換等が可能な構成になっています。詳しく知りたい方は、STM32F103のデータシートやSTM32コアライブラリのソースコードを解析してみてください。
一旦、S&H回路を忘れて(無いものと考えて)、ブロック図を眺めてみてください。この回路は、アナログ入力AINと、NビットDA変換器出力を比較して、その結果をNビットSARに反映する回路になっています。つまり、参照相手のDA変換器出力をあらゆる値に変化させて、その出力と、AINが一致するデジタル値を探って行く方式です。
これって、「データベースから、入力値に一番近いデータを取り出す」作業と一緒で、所謂、探索アルゴリズムを使うことができます。一番簡単なのは、0Vから5Vまで順番に探索して行って、一番近い値を見つける「逐次探索(シーケンシャルサーチ)」という方法です。当然、全ての値と比較するので、見つかるまでに相当の時間が掛かります。
一方、データが一定の法則で整列している場合には、二分探索(バイナリサーチ)という手法が使えます。この手法を以下図で説明します。
まず、上図一番上の線分に注目していただくと、電圧値で左端にVREF、右端にGNDをとっています。以下、二分探索でデジタル値を探索する様子となります。
SAR AD変換器は、入力アナログ信号AINをN回、二分探索法によってDA変換器出力と比較しながら結果を求めます。シーケンシャル探索では、比較回数が最大で2N回となるのに対して、二分探索では、比較回数がN回と、圧倒的に少なくなります。
それでも、N回の比較を実行すると、変換を始めてから終了するまでに、それなりに時間がかかります。SAR AD変換器を全てハードウェアで構成する場合、例えば、1回の比較を1クロックで実行するような回路にすると、Nビットの変換にはNクロックを要します。
変換中にも、アナログ入力AINは刻々と変化しているので、比較K回目の入力AINと比較K+1回目の入力AIN’が異なってしまうと、正しい値を変換することができなくなってしまいます。そこで、変換を開始した時点の入力AINの電位を保持して、その後AINが変化しても、保持した電位をAD変換することができるように、サンプル&ホールド(S&H)回路が必要となります。
余談ですが、Arduino UNOに搭載されているATmega328の10ビットAD変換器も逐次比較型です。AD変換クロックをCPUクロックの1/2〜1/128の周波数から選択できるようになっています。ATmega328データシートの変換時間の解説は、ちょっと難解なのですが、おおよそ「(初期化時間(起動後最初の一回のみ))+S&H時間+変換時間(10ビット×AD変換クロック)+前後処理時間」と、なっているようです。
二分探索していく部分は、今回Arduinoのソフトウェアで作り込むのですが、考え方は上で説明した通りですので、実際のコーディングについては、完成版プログラム(test_adc_4b.ino)でご確認ください。参照すべきは、adc4_read()関数です。
※比較回路の出力をSARに反映する方法ですが、この部分をハードウェア(回路)で実現する時は、比較した順にMSB→LSBの順で、比較結果の0(AIN<Px)/1(AIN>Px)を取り込んでいくだけでOKです。二分探索は、ハードウェア化する場合にも適した手法だと考えられます。
※ソフトウェア(test_adc_4b.ino)の方は、少し違ったアプローチでコーディングしてあるのですが、原理は同じで、得られる結果も同じです。ソフトウェアとハードウェアの違いにも注目して見てください。
と、言うことで、Arduino UNOには、そもそも、AD変換器が搭載されているのですが、今回は、AD変換器の原理を知り、変換精度評価まで実施するため、敢えて外付け回路でAD変換器を作ってみます。
上に示したブロック図の構成要素毎に実現方法を検討します。
以上の検討を踏まえ、回路図を起こしてみました(下図)。
ただし、シート2/2のS&H回路は、今回同時に実現できないので、参考回路(REV.0)です。後で、今回作成した4ビットAD変換器の変換精度を評価しますが、シート1/2の回路だけを使用します。
※シート2/2の回路は評価もできていないので、お使いなる場合には、各自、設計・評価をお願いいたします。
今回は、AD変換器を作るにあたって、部品が足りず、DA変換器とS&H回路を同時には構成できないため、S&H回路を断念しました。ここで、S&H回路の原理だけ、さらっと触れておきます(以下図)。
アナログスイッチU1とコンデンサC1をボルテージフォロアU2,U3で挟み込むような構成です。原理としては、アナログスイッチでサンプリングして、コンデンサでホールドする動作となります。
ホールド中は、コンデンサC1にチャージした電荷で、AOUT電位をホールドするため、何らかの電流パス(リークパス)が残ってしまうと電荷が変化して、時間と共に電位が変わってしまいます。従って通常は、出力段を入力インピーダンスの大きなオペアンプ(ボルテージフォロア)で受けて使います。
入力段にボルテージフォロアを置くのも、同じ理由ですが、例えば上の回路なら、コンデンサC1への充放電電流しか流れないので、それが許容されるなら、入力段のボルテージフォロア(U2)は不要です。許容されない用途では、必要なので、用途によって適切に回路を構成してください。
以下図にAD変換器の理想的な特性を示します。
上図のグラフは、いずれも、横軸にアナログ電圧A(入力)と、縦軸にデジタル値D(出力)をプロットしています。左側のグラフで、赤い実線が、NビットAD変換器においてN→∞とした場合の理想特性です。一方、右側の拡大図で、緑実線で示した階段状の特性が、有限のNビットAD変換器における理想出力となります。
DA変換器の場合とは、入出力の関係が逆転していることもあるのですが、微妙に違っているでしょう?
特に、階段状の緑実線と赤実線の関係がずれています。DA変換器の時には、上図の赤破線の所が赤実線(理想特性)の位置に来るように、階段状の緑実線が存在していましたので、今回のAD変換器ではこの時点で既に0.5LSBずれている(→原理の時点でハンディキャップを持っている(※))のです。AD変換器の精度は、あくまでも赤実線(理想特性)からの偏差(誤差)で評価されるべきなので、DA変換器に比べて、シビアな結果が予想されます。
※N→∞の理想特性(赤実線)と、有限のNビットAD変換器の理想特性(階段状の緑実線)を、見比べてみると、最大で1LSBの誤差があることが解りますか?両方とも「理想特性」なので、原理の段階から、絶対精度で1LSBの誤差が発生することに留意してください。後で変換精度を評価する時に利いてきます。
さらに、変換精度の評価指標を算出する上で留意しておくべきポイントが、オレンジ実線で図示されています。オレンジ実線は、実際のAD変換器の変換特性例を示しています(従って変換誤差を含んでいる)。
横軸が入力アナログ電圧Aなので、それに対して、デジタル値Dが求まるのですが、例えば、D=2からD=3へ変化する、その境界付近の電圧値Aに対しては、ちょっとしたノイズなどの影響によって、D=…2 →2 →2 →3 →2 →3 →3 →3…(この時のAは単調増加)の様に、2と3の間を行ったり来たりする電圧範囲が存在してしまいます。
実は、DNLを計算する時、階段状特性のステップ部分の幅(上図、青色⇔)が必要なのですが、2と3の間を行ったり来たりする場合、どこをステップとみなすか?が問題となります。変化点の平均値を求めるとか、色々な方法があるのかもしれませんが、ここでは、以下の様に定義します。
この定義に従うと、上図の青色⇔が、オレンジ実線に対する、各デジタル値Dにおけるステップ幅となります。その他、DA変換器の場合と同様に、ビット数N、1LSBに相当する電圧値V10=VREF/(2N)、入力電圧xの時のデジタル値D[x]として、各指標を以下の様に求めることとします。
入力と出力の関係が逆転した分、DA変換器の精度評価式との差分となって現れます。更に、出力が離散値となるため、OE,FEも、一次回帰直線から求める必要が生じます。これらの様な差がありますが、基本的にDA変換器も、AD変換器も、同名の評価指標の考え方は、同じです。
※イヤ、同じに見えないですよね?でも、基本的な考え方は同じなのです(1^^;)。お察しの通り、DA変換器に比べてAD変換器の方が、指標の計算方法も評価そのものも、ちょっと難しくなっているのは確か、です。
いよいよ、今回のクライマックスです。ここまでの回路とソフトウェアを統合して、4ビットAD変換器を完成させ、その変換精度の評価までを一気に実行します。
評価方法ですが、AD変換器の変換精度を計測するためには、0V〜VREFまでの任意のアナログ電圧を発生できる必要があります。そこで、入力電圧を作り出す為に、12ビットDA変換器モジュール(MCP4725、以下図)を使います。
※使い方については、「#7-9 WAVファイルを再生する」にて解説済みです。
一般に、NビットAD変換器の変換精度を評価するためには、より高精度なMビットDA変換器が必要となります。ここで、M>>N (十分に大きい)です。4ビットAD変換器の評価ですから、12ビットDA変換器があれば、十分な評価が可能だと思われます。
MCP4725モジュールも、4ビットAD変換器を制御するArduinoに接続して制御すると、何と、4ビットAD変換器の変換精度評価測定を自動化できてしまいます!……かっこ良いo(1^−^)o。
では、回路をまとめておきます。まずは、4ビットAD変換器の回路図を以下に示します(上で示した回路の再掲、ただし、シート1/2のみ。S&H回路(シート2/2)は構成しない)。
次に、MCP4725モジュールとの接続ネットリストを示します。上図の回路に加えて、こちら(↓)の配線も実施してください。
Arduino UNO | 接続 | MCP4725 | 接続 | 4ビットAD変換器 |
5V | → | VCC | ||
GND | ⇔ | GND | ||
A4(SDA) | ⇔ | SDA | ||
A5(SCL) | ⇔ | SCL | ||
OUT | → | AIN |
※MCP4725は、変換精度評価用です。4ビットAD変換器の一部ではありません。
手作りした4ビットAD変換器の制御と、12ビットDA変換器を使った変換精度測定を統合した評価プログラムを以下にリンクしておきます。
評価プログラム:test_adc_4b.ino
コンパイルしてArduino UNOへ書き込んでください。シリアルモニタを開くと、以下のコマンドを受け付けるようになっています。
実験サンプル:【 】内はシリアルモニタからの送信データ
【daco,0】
OK: DAC=0(0[mV]) ADC=0(0[mV]) 0.000[LSB]
【daco,2048】
OK: DAC=2048(2500[mV]) ADC=7(2187[mV]) -1.001[LSB]
【daco,4095】
OK: DAC=4095(4998[mV]) ADC=15(4687[mV]) -0.995[LSB]
たったの3点ですが、測定してみたところ、やっぱり、−1LSB程度の誤差があるみたいです。ちゃんと変換精度を評価してみましょう。
実験サンプル:【 】内はシリアルモニタからの送信データ
【eval】
0,0
1,0
2,0
3,0
4,0
5,0
:
: (中略)
:
4091,15
4092,15
4093,15
4094,15
4095,15
OK: eval
12ビットDA変換器の出力をx=0〜4,095まで振りながら、そのアナログ出力を4ビットAD変換器で変換し、デジタル値D[x]=0〜15を測定しています。結果は、上例の様にカンマ(,)区切りでシリアルモニタに表示されるので、Excelなどにコピー&ペーストして各指標を求めます。
以下図に、測定した全4,096点の測定データと、その一次回帰直線のグラフを示します。
横軸に入力電圧x×5V/4,096、縦軸に変換結果のデジタル値D[x]をプロットしてあります。
ダメですね(1x_x)、低電圧側は良さそうなのですが、どうも、4Vを超える前後から、変換結果が正しくありません。4ビットDA変換器は「#7-6 DA変換器を作る」にて評価済みで、特に問題ありませんでしたから、疑うべきは比較回路(LM358)でしょう。
LM358のデータシートを確認したところ、「Input Common-Mode Voltage Range:0〜VCC−1.5V」が悪さしているのではないか?と考えました。今、LM358のVCC=5Vなので、入力電圧範囲は0〜3.5[V]でなくてはならない、というスペックと読めます。
単に、電圧比較したかっただけなのだけど……。手っ取り早く、昇圧電源モジュール(以下図)を使って、LM358にちょっとだけ高い電圧を供給してみようと思います。
※LM358の電源電圧だけを変更します。
LM358自体は、単一電源の場合、電源電圧32Vまで上げても使用可能なので、本当は、入力電圧が5Vまで許容されるようにVCC=5V+1.5V=6.5Vにしたいところです。しかし、これではLM358の出力電圧が、ATmega328の入力電圧範囲(5V)を超えてしまいます。LM358は、実力でVCC−1V程度までしか出力できないので、VCC=6Vとすれば、出力電圧は5V程度で収まるはずです。
LM358の入力電圧範囲(0〜VCC−1.5V)の電気的特性は満たせませんが、変換結果が不正となったのは、4V=VCC−1Vを超えた辺りなので、何とか実力で使えるでしょう。
※もし、LM358の電気的特性を満たすために、6V以上の電源電圧を印加する場合には、LM358の出力をArduinoのD2端子と繋ぐ時、間にレベルシフタを挟んでください。
以下、実験中の様子です。
もう一度、【eval】を実行して、グラフを描いてみます(下図)。
良さそうです(1^−^)v。回路図の方は修正していない(LM358の電源電圧)ので、ご注意ください。
これも、「Rail-To-Rail」がらみの特性なんでしょうか?LM358とは、意外と使い難い素子です……。
Excelに引かせた一次回帰直線(赤破線)の数式(前節グラフ中に表記)において、D=0との交点(Vofs)とD=2N−1=15との交点(Vful)を求めると、以下となります。
Vofs=0.5186/3.1663≒0.164V
Vful=(15+0.5186)/3.1663≒4.901V
ここからオフセット誤差(OE)とフルスケール誤差(FE)を計算可能です。後ほどまとめて示します。
先に、残りの指標を求めてしまいます。まず、絶対精度(AE)ですが、4,096点の測定データと理想特性の偏差(誤差)ですので、上の一次回帰直線を引かせた時のデータで表計算して求めます。結果のグラフを以下図に示します。
横軸は、評価に使用した12ビットDA変換器の出力電圧(x)[V]、縦軸は絶対精度(AE)[LSB]です。
変換結果が階段状の離散値ですので、上図の様に、ギザギザの鋸歯みたいになります。誤差は0LSBに近づく方が小さくなるので、絶対値が最大となる最大誤差はAE=−1.238LSBでした。AEは原理上、最大で−1LSBの誤差を持っているので、AE=−1.238LSBなら、そんなにひどい値ではないでしょう。
※原理上、誤差−1LSBを持っているので、実際に回路を組んだことによって発生した誤差は、実質、−0.238LSBだった、と言うことになります。
最後に、DNLとINLを求めます。
D [LSB] |
A[D] [V] |
DNL [LSB] |
INL [LSB] |
0 | 0.000 | 0.000 | |
1 | 0.337 | 0.078 | 0.078 |
2 | 0.649 | 0.000 | 0.078 |
3 | 0.941 | −0.066 | 0.012 |
4 | 1.282 | 0.090 | 0.102 |
5 | 1.603 | 0.027 | 0.129 |
6 | 1.892 | −0.074 | 0.055 |
7 | 2.205 | 0.000 | 0.055 |
8 | 2.520 | 0.008 | 0.063 |
9 | 2.865 | 0.105 | 0.168 |
10 | 3.181 | 0.012 | 0.180 |
11 | 3.466 | −0.090 | 0.090 |
12 | 3.782 | 0.012 | 0.102 |
13 | 4.138 | 0.141 | 0.242 |
14 | 4.415 | −0.113 | 0.129 |
15 | 4.731 | 0.012 | 0.141 |
全ての評価指標の算出が終わりましたので、以下にまとめておきます。
以下、考察と雑感です。
手作りのDA変換器に引き続いて、AD変換器も作ってみました。実用的、と言うより、「学習用」です。原理通りに回路を構築してAD変換動作を確認できたこと、AD変換器を設計する場合の留意点がわかったこと、が収穫です。次はアレを作ってみたいのですが、「アレ」については、また別なお話。
「次はアレを作ってみたい」の、「アレ」とは、ΔΣ型AD変換器の事でした〜。「#9-2 ΔΣ型AD変換器を作る」にて、実際に作ってみて、精度評価まで実施したので、そちらも合わせてご覧ください。