lyricalmagicalのアイコン画像
lyricalmagical 2024年05月02日作成
セットアップや使用方法 セットアップや使用方法 閲覧数 1101
lyricalmagical 2024年05月02日作成 セットアップや使用方法 セットアップや使用方法 閲覧数 1101

[Arduino UNO]pulseIn()のパルス幅測定精度を調べてみた

[Arduino UNO]pulseIn()のパルス幅測定精度を調べてみた

ArduinoのpulsIn()関数はどのくらいの精度で測定してくれるのかを調べてみました。
ターゲットはArduino UNO(SWITCH SCIENCE純正)です。

やりたいこと

上記に書いた通りですが、pulsIn()関数がどのくらい正確なのかを調べてみたいと思いました。
公式のリファレンスによると、10μ秒から3分までを1μ秒単位で測定してくれることになっています。
しかし本当に1μ秒単位できちんと測定してくれるんですかね、というところを調べたかったです。

やるべきことは1μ秒単位で正確にパルスを出力できるものを作って、Arduinoに入れるだけです。
ではどうやってそのパルスを作るかというところですが、対向もArduinoだとさすがに検証にならないです。
シグナルジェネレータとかがあると簡単にできるとは思いますが、残念ながら持っていないので、水晶発振を分周してFPGAで作りました。
FPGAであれば1μ秒単位でのパルス幅の調整は容易に可能です。

実験風景

というわけでこんな感じになります。

実験ソース

Arduinoは単純なパルス幅測定です

Arduinoのパルス幅測定例

int pin = 19; unsigned long duration; void setup() { Serial.begin(9600); pinMode(pin, INPUT); } void loop() { duration = pulseIn(pin, HIGH); Serial.println(duration); }

FPGAのほうは可変の分周回路です。uart処理などは大きいので割愛しました。

FPGA(抜粋)

reg [4:0] counter_24;//基準は24MHzクロック always @(posedge CLKI or negedge resetn) if (resetn==1'b0) counter_24<=0; else if (counter_24==0) counter_24 <= 11; else counter_24<=counter_24-1; reg [19:0] sigtime; always @(posedge CLKI or negedge resetn) if (resetn==1'b0) sigtime<=100000;//UARTから受けて増減する else if (rx_en==1'b1 && rxdata==8'h20) sigtime<=100000; else if (rx_en==1'b1 && rxdata==8'h61) sigtime<=sigtime-1; else if (rx_en==1'b1 && rxdata==8'h62) sigtime<=sigtime+1; reg [19:0] counter_M; always @(posedge CLKI or negedge resetn) if (resetn==1'b0) counter_M<=0; else if (counter_24 == 0 && counter_M==0) counter_M <= sigtime-1; else if (counter_24 == 0) counter_M<=counter_M-1; reg sig; always @(posedge CLKI or negedge resetn) if (resetn==1'b0) sig<=1'b0; else if (counter_24==0 && counter_M==0) sig<=~sig; reg sig2; always @(posedge CLKI or negedge resetn) if (resetn==1'b0) sig2<=1'b0; else if (counter_24==0 && counter_M==0 && sig==1'b0) sig2<=~sig2; assign SIGO=sig2; //出力信号

結果(生値)

実際に測定したベタ値になります。測定は1μ秒~100000μ秒(=0.1秒)まで行いました。

真値:理論値。FPGAで出力したパルス幅。単位μ秒。
平均:Arduinoで測定したパルス幅。約50回の測定値の平均。単位μ秒。
最大:Arduinoで測定したパルス幅の最大値。
最小:Arduinoで測定したパルス幅の最小値。
振れ幅:最大と最小の差
誤差率:真値との誤差率

真値 平均 最大 最小 振れ幅 誤差率
100000 99569.20 99574 99568 6 -0.431%
99999 99568.22 99574 99567 7 -0.431%
99998 99567.26 99573 99566 7 -0.431%
99990 99559.31 99564 99558 6 -0.431%
90000 89612.18 89613 89606 7 -0.431%
80000 79654.21 79658 79651 7 -0.432%
70000 69698.20 69702 69695 7 -0.431%
60000 59741.51 59746 59739 7 -0.431%
50000 49784.55 49790 49784 6 -0.431%
40000 39826.71 39829 39822 7 -0.433%
30000 29871.14 29874 29867 7 -0.430%
20000 19914.09 19918 19911 7 -0.430%
10000 9957.32 9962 9955 7 -0.427%
9000 8961.88 8967 8960 7 -0.424%
8000 7965.90 7971 7964 7 -0.426%
7000 6970.39 6976 6969 7 -0.423%
6000 5974.70 5980 5973 7 -0.422%
5000 4978.79 4985 4978 7 -0.424%
4000 3974.76 3981 3974 7 -0.631%
3000 2965.16 2972 2963 9 -1.161%
2000 1976.81 1984 1976 8 -1.159%
1000 988.26 996 988 8 -1.174%
950 939.08 946 938 8 -1.149%
900 889.90 896 887 9 -1.123%
850 840.25 852 837 15 -1.147%
800 792.00 802 788 14 -1.000%
750 742.20 752 737 15 -1.040%
700 693.00 702 687 15 -1.000%
650 647.98 652 645 7 -0.310%
600 594.22 602 587 15 -0.963%
500 494.79 502 487 15 -1.041%
450 445.35 451 437 14 -1.032%
400 397.33 401 387 14 -0.668%
350 349.06 351 345 6 -0.267%
300 299.42 301 295 6 -0.193%
250 249.51 251 244 7 -0.196%
200 200.00 201 195 6 0.000%
100 99.93 101 94 7 -0.070%
90 90.05 91 84 7 0.057%
80 80.25 81 75 6 0.318%
70 70.24 71 64 7 0.339%
60 60.16 61 54 7 0.259%
50 50.38 51 44 7 0.759%
40 40.31 41 35 6 0.776%
30 30.28 31 24 7 0.926%
20 20.47 21 20 1 2.358%
10 10.37 11 10 1 3.684%
9 9.56 10 4 6 6.238%
8 8.37 9 2 7 4.661%
7 7.36 8 7 1 5.195%
6 6.33 7 0 7 5.556%
5 5.57 6 5 1 11.429%
4 4.35 5 4 1 8.772%
3 3.46 4 3 1 15.254%
2 2.52 3 2 1 25.833%
1 1.00 2 0 2 0.000%

※10μs未満は公式には非対応です。
1μsを測定したとき、偶然かライブラリの都合かはわかりませんが、測定値「1」が返ってくることはありませんでした。

結果(グラフ)

1μs~100000μs

5000μ秒以下あたりから誤差大きくなっているのでその部分の拡大が下記となります。

10μs~5000μs

さらに1000μ秒以下以下を拡大したのが下記になります。

1μs~1000μs

結論

・0.1秒~5000μ秒くらいまでは誤差-0.4%程度で、若干早く測定される傾向があるようです。これはライブラリの都合な気がします。
・1000μ秒以下あたりから誤差が大きくなってきます。
・100μ秒以下あたりは正直使い物にならないレベルと思います。

というわけで、短いパルスを測定しようとする場合は、あまり測定結果を過信してはいけないということが解りました。
また、測定結果も数μ秒レベルでブレがあるようです。
pulseIn()で短いパルスを測定したいときは、このあたりも考慮して設計する必要がありそうですね。

lyricalmagicalのアイコン画像
電子デバイスはとってもりりかるなの
ログインしてコメントを投稿する