ArduinoのA/DコンバータをMATLABで評価する（準備編）

## はじめに
　A/Dコンバータの特性と言ってもいろいろあります。ここではダイナミックテストについて述べてみたいと思います。ダイナミックテストとは、音声のような変化する信号に対する性能評価です（ビデオ信号も変化する信号ですが、周波数が高すぎて今回の対象には入りません）。Arduinoのテキストによく載っているポテンショメータの値を読むようなスタティックな（変化のない）信号ではありません。
　本記事は、準備編として、環境構築：PCのライン端子から取り込んだ信号をPC内部のA/Dコンバータでディジタル信号に変換し、MATLABに信号を取り込み、評価するところまでをまとめました。

## １．まずは信号源から
　とりあえず、手元にはヘッドホンジャックのあるタイプのiPadがあり、ヘッドホンジャックに差し込めるステレオミニプラグが両端についたケーブルがあり、そして、ステレオミニプラグでライン入力ができるパソコンがあるとします（我田引水）。
　iPadを信号源に使ってダイナミックテストを行うためには、iPadから正弦波を出せるものが必要です。ここではApp Storeから『標準信号発生器』を入手しました。
![Fig01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/86735913-ad47-bc0e-51a3-a11dac3f5f9b.png)
　Android系は音量を最大にしても0.4Vpp程度（もしくはもっと小さい）しか出ないので（iOS系だと2Vpp程度出ます）、レベルがやや足らないですが、実験はできると思います。使うとしたらこの辺かも。
![Fig02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/529b160a-c4c2-e311-010b-e16881d63d08.png)


## ２．MATLABで信号をPCに取り込む

　iPadから出力した正弦波信号をケーブルを介して、PCのライン端子に入れます。
MATLABを起動し、
`info = audiodevinfo`
で、オーディオデバイスの情報が得られます。

```
info = 

  フィールドをもつ struct:

     input: [1×2 struct]
    output: [1×3 struct]
```

上記の表示では入力デバイスが２つあることがわかり、入力デバイス１の詳細は、

`info.input(1)`


で、表示され、

```
ans = 

  フィールドをもつ struct:

             Name: 'プライマリ サウンド キャプチャ ドライバー (Windows DirectSound)'
    DriverVersion: 'Windows DirectSound'
               ID: 0
```
デバイスID=0で入力できることがわかります。
音声入力を取り込むプログラムは下記のとおりとなります。

```matlab
Fs = 44100 ; %サンプリング周波数[Hz]
nBits = 16 ; %ビット数
nChannels = 2 ; %チャンネル数
ID = 0; % Windows DirectSound を音声入力デバイスに指定

%オーディオレコーダオブジェクトを生成
recObj = audiorecorder(Fs,nBits,nChannels,ID);

disp('Start of Recording.')

recordblocking(recObj,1);%録音時間を指定（ここでは1秒）
disp('End of Recording.');

%オブジェクトからデータ取り出し
doubleArray = getaudiodata(recObj);

%波形表示
figure(1);
plot(doubleArray);
title('Audio Signal (double)');

%1ch分の信号の500点分を拡大
Signl=doubleArray(10001:10500,2);
t=(1:500)/Fs;
figure(2);
plot(t,Signl);
xlabel('time[sec]');
ylabel('Amplitude');

```
300Hzの正弦波を2Vppで入力したときの波形は、下のようになります。
![Fig03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/d8a9d812-ff13-3c7e-0668-2972facc25ba.png)
振幅に関してはフルスケールを±１で正規化しているようです。
ちなみに±1のフルスケールになる振幅を調べてみると、約3.6Vppとなっています。
入力信号をこれ以上大きくすると下記のようにクリップしてしまいます。
![Fig06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/0ba10ea0-61a3-79f8-f3ff-f181cd54918e.png)
A/Dコンバータの性能をきちんと調べるためには入力振幅を調節して、飽和しないようにしつつ、できるだけ大きな振幅で入力します。一般には[フルスケール－1dB]（だいたい９割の振幅）で入力します。

## ３．信号の評価指標とは

　こうしてA/D変換した信号には大きく分けて３つの要素があります。
入力信号成分（正弦波）、入力信号の歪成分（高調波）、その他のノイズです。信号をフーリエ変換した周波数スペクトラムで見ると、下記のようになります。
![Fig15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/1ba3a928-5e85-c915-2395-c2ad79776745.png)
次に、入力信号以外の成分が生成される原因について説明します。
まず、無限の階調を持つアナログ信号を、ディジタル信号にすることで誤差が生じます。
例えば43.25というアナログ値を43というディジタル値に変換すれば、0.25だけの誤差が生じ、誤差はノイズとなります。また、許容される入力範囲も制限されるので、ダイナミックレンジが限定されます（10bitのA/Dコンバータなら1024段階の出力に制限されます）。
![Fig16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/b265c854-8af8-b98f-db33-3b706c22b619.png)
その上に、A/Dコンバータはハードウェアですから、１ビットあたりの幅が異なるとか、全体的に特性がゆがんでいるというような劣化要因があります。前者に関する指標が微分非直線性（DNL）、後者は積分非直線性（INL）です。
![Fig017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/20f044a4-b5ee-1900-e4c7-9b6d7b9e770b.png)
![Fig018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/5c25f2ed-76a2-20ed-cd4b-b4f13ec20fa0.png)
積分非直線性が悪いと、入力した正弦波が歪んで変換されるので、高調波歪が増えます。

A/Dコンバータ自体の特性劣化以外にも例えば、周辺のディジタル回路のノイズが混入してくるとか、あるいは、急激な電圧変動などでパルス状のノイズが混入してくるなどの信号劣化もあります。
![FIG019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/26c1aa92-2183-78c6-ae34-af0cd8e0a25b.png)
　信号品質の評価方法はヒストグラム法やカーブフィッティングなどが知られていますが、今日行なわれることが多いのは高速フーリエ変換（FFT）によるものです。
　MATLABのsignal processing toolboxにはFFTによる信号品質の評価関数が用意されています。
signal processing toolboxがない場合において、スペクトラムを算出するには、だいたい下記のようなプログラムとなります。今、変数Sigに入力信号があるとします。

```matlab
Fs=44.100;%サンプリング周波数[kHz]
N=numel(Sig);%データ点数

%Kaiser窓　kaiser(N,Beta)
Beta=38;
n=0:N-1;
WK=besseli(0,Beta*sqrt(1-((n-N/2)/(N/2)).^2))/besseli(0,Beta);

Sig0=WK'.*Sig;%窓関数をかける
Sig0=Sig0/(N/6.94);%ポイント数と窓関数による減衰分の補正
Sdum=20*log10(abs(fft(Sig0)));%Kaiser窓での減衰分補正

Spc=Sdum(1:(N/2));%グラフ表示分
Fq=(1:(N/2))/N*Fs;%周波数
Fq=Fq-Fq(1);%Fq(1)を0Hzに

%グラフ作成
figure(7);
plot(Fq,Spc,'b');
ylim([-180 10]);
xlim([0 Fq(end)]);
grid on;
title('周波数成分表示');
xlabel('Freq[kHz]');
ylabel('[dB]');
```

### 3-1 SNRとSINAD
　SNR(Signal-Noise-Ratio）は正弦波成分と、その他のノイズ成分のパワー比をデシベルで表したものです。SNRにおいては、正弦波の高調波をノイズに含みません（正確に言うと、低次の高調波をノイズから除外します）。
　これに対してSINAD（SIgnal-to-Noise-And-Distortion）においては、正弦波成分（基本波成分のみ）と高調波およびその他のノイズ成分のパワー比となります。高調波（Distortion）をノイズに含めるのでSNRに比べて厳しめの値となります。
SNRとSINADの違いを下の図に示します。
![Fig015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/8b54ea57-fb08-9c2c-6e3c-a37261165014.png)

MATLABにおけるSNRの引数（の一例）は、 `SNR(A,Fs,n)` で、Aが信号データ、Fsがサンプリング周波数、nは何次までの高調波を除外するかで、デフォルトでは６次までになっています。
直流成分については自動的に差し引いているようです。
1kHzを44.1kHzでサンプリングしたデータSigからSNRを求める（高調波は９次までで計算しました）と　`snr(Sig,44100,9)`  で、
下記のようなグラフが描出され、SNRも81.63dBと算出してくれて非常に便利です。
![Fig12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/ef1d91ef-ff35-443d-b3ca-724687e432bf.png)
ただし、これは、下記のような振幅が±0.7のときの信号とノイズの比なので、フルスケールでのSNRはもっとよくなります。
![Fig11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/8c146722-d054-ec8a-eb2b-73b4bc819814.png)
下記のような感じで、約1dB上がりました。
![Fig020A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/406ad723-37ab-e77c-9996-cae9e75054d0.png)
普通、A/DコンバータのSNRはフルスケールの正弦波とノイズの比率になります（フルスケールより1dB小さい信号を入れた場合には信号成分を1dB分、あとで補正します）。
MATLABにおけるSNRコマンドはフルスケールは関係なく、そのデータにおいて信号成分とノイズ成分の比率を求めている点に注意が必要です。

_ちょっと思ったのですが、MATLABの場合、”フルスケール”という概念がないのかもしれません。PCの中というバーチャルな世界においての信号やノイズなので、相対的な大きさはあっても、絶対的な大きさの定義がないのでは？と思いました。_

　MATLABにおけるSINADの引数（一例）は `sinad(A,fs）` で、Aは信号データ、fsはサンプリング周波数です。同様に、 `sinad(Sig,44100)` を実行します。左がSNR、右がSINADです。
![Fig021A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/8184d345-56d8-1121-d61f-a4fcd72d8b6e.png)


### 3-2 THD 
　THD(Total Harmonic Distortion)は全高調波歪で、基本波に対する、全ての高調波の比率を表したものです。 `thd(Sig,Fs)` で、このように表示されます。
![Fig023A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/00c85c6f-952a-77cf-1d54-0c8a0be4da9e.png)

### 3-3 SFDR
　SFDR（Spurious Free Dynamic Range）は、基本波成分と、最もレベルの大きい高調波の比率をデシベルで表したものです。SFDRという指標は無線において信号の干渉のしやすさなどを示すのに用いられます。 `sfdr(Sig,Fs)` で、このように表示されます。
![Fig024A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/fd2afe5a-ab31-8755-47b8-f31538a555a2.png)
### 3-4 ENOB
　ENOB（Effective Number Of Bits）：有効ビット数は、
　　`ENOB [bit] = ( SNR [dB] - 1.76 ) / 6.02` 
で求めることができます。MATLABにおいてENOBの関数はなく、上記の式で求めます。
SNRが 82.65[dB] である場合、ENOB は、
　 `ENOB = ( 82.65 -1.76 )/ 6.02 = 13.44 [bit]`  となります。
　既に述べたように、理想的なA/Dコンバータというものは存在しません。積分非直線性や微分非直線性がありますし、場合によっては微分非直線性が悪すぎてある出力が出ない（ex. 217の次が219になってしまい、218は出力されない。これをmissing bitと言います）というようなこともあります。
　また、AD変換器そのものがアナログ－ディジタル混在回路なので、ディジタルノイズのアナログ回路への混入もあります。
　このようにA/Dコンバータの性能は、単に「ディジタル出力のビット数」だけでは表現できないため、より実際に近い指標として有効ビット数で性能を表します。

　
予備知識の説明が長くなってしまったので、ArduinoのA/Dコンバータは次回にまわすことにします。
（ということで続く）