前回、NTC サーミスタで温度を計測するための式を載せた。
今回は、式をプログラムとして実装し、Arduino Nano を使って、実際に測れるのかを確認する。
サーミスタは、3つのパラメータを持つので、それを構造体として表すことにした。
(クラスとしたらいいんだろうけども、利便性よく、ただしくまとめる能力がないので、
C++でなく、C言語で記述した。)
実験に使った、以下にプログラムを示す。
/* * Thermistor test program for Arduino Nano. * (C)flapper @ decentdress.blogspot.com */ #include <math.h> #define AD_PIN 23 #define AD_REF_VOLT 5 #define CONV_AD_TO_VOLT(x) ((x)*AD_REF_VOLT/1023) #define CONV_AD_TO_VOLT_F(x) (((float)x)*((float)AD_REF_VOLT)/1023.f) // NTC Thermistor typedef struct ntc_thermistor_st_ { const int B; // Constant number B [-]. const float To; // Temp [Deg]. const float Ro; // Resistor in To [kOhm]. } NTC_THERMISTOR_ST; // Calculate resistor of NTC thermistor in the degree T. float calc_tnp_thermitstor_resistor_k(NTC_THERMISTOR_ST *st, const float T) { float result; result = st->Ro * exp((float)st->B * ( 1./(T+273.15) - 1./(st->To+273.15) )); return result; } // Calculate temperature of NTC thermistor in the Resistor R. float calc_ntc_thermistor_temp_deg(NTC_THERMISTOR_ST *st, const float R) { float result; result = 1 / ((log(R / st->Ro) / (float)st->B) + (1/(st->To + 273.15))); return result - 273.15; } // R2_k[kOhm]: Resistor of voltage dividing circuit in nearby GND. // div_volt[V]: divided voltage. // Return : R1_k[kOhm] (Resistor of voltage dividing circuit float calc_resistor_k_divided_volt(const int R2_k, const float div_volt) { const float src_volt = AD_REF_VOLT; // float R1_k; // R1_k = (float)R2_k * (AD_REF_VOLT - div_volt) / div_volt; // return R1_k; return (float)R2_k * (AD_REF_VOLT - div_volt) / div_volt; // R1_k } void setup() { // put your setup code here, to run once: Serial.begin(19200); } void loop() { // put your main code here, to run repeatedly: NTC_THERMISTOR_ST ntc_thrm = { 3380, 25.0f, 10.0f }; Serial.println("TNP Thermistor test.\n"); Serial.print("AD[-],ADV[V],R[kOhm],Temp[deg.],Time[us]\n"); for(;;) { int ad_value; float ad_volt; unsigned long start_time, finish_time, diff_time; float ntc_temp; ad_value = analogRead(AD_PIN); ad_volt = CONV_AD_TO_VOLT_F(ad_value); float ntc_r = calc_resistor_k_divided_volt(10, ad_volt); start_time = micros(); ntc_temp = calc_ntc_thermistor_temp_deg(&ntc_thrm, ntc_r); finish_time = micros(); diff_time = finish_time - start_time; Serial.print(ad_value); Serial.print(","); Serial.print(ad_volt); Serial.print(","); Serial.print(ntc_r); Serial.print(","); Serial.print(ntc_temp); Serial.print(","); Serial.print(diff_time); Serial.print("\n"); delay(1000); } }
プログラムについて
サーミスタの構造体名は NTC_THERMISOTR_ST である。B 定数、温度To、温度 To における抵抗Ro がメンバですべて定数として定義した。
(B 定数は温度によって、補正するなどすると温度がより精度よく計測できるようだが構造体では定数とした。)
宣言方法は、以下のようになる。
NTC_THERMISTOR_ST ntc_thrm = { 3380, 25.0f, 10.0f };
初期化時に、B 定数[-]、温度 To[deg] 、抵抗 Ro[kΩ] をとる。
実験では、この記事で書いた特性不明の NTC サーミスタ(s103du8)を使うため、推定値として上のような初期値を与えた。
別のサーミスタを使用するときには、データシート上の値に変更しないといけない。
また、AD 変換器の電源電圧は 5V 、ビット数は 10 bit である。これと異なる場合は、define の値を変更しないといけない。なお、分圧に使用した抵抗は、10kΩとした。
実験方法
室温に置く、指で触る、体温で温めるなどを行った。結果
結果
グラフは実験より得られた値をそのままプロットした。
それらしい値が出た。各値をロギングし、再計算させてグラフを作ってみても
間違いではないみたい。
ただし、低温や高温域においてサーミスタの特性上、特に誤差が大きくなるため、
本当のところはわからない。その温度域での環境を用意しなければいけない。
また実験では、温度を計測すると同時に、遅くなるだろう loge の演算速度も出力させてみたが、約 255us ほどかかる。
合計で2個は使う予定だから、AD 変換、分圧計算なども考慮すると演算時間は 0.6 ms くらいだろうか?
ただ、デジタルフィルタも使ってみたいから、それも含めて、1 ms くらいにはおさまってほしい(単純移動平均だから大丈夫だと思うが)。
NTC サーミスタの温度算出式の変更や自己発熱による温度上昇、回路の改良や
熱拡散による熱損失等を検討すれば、より高精度に計測できると考えられる。
より正しく測るには?
検索すると以下のサイトがヒットした。正確な温度を測れるように、詳しく実験・考察されている。
(B 定数を温度の一次関数で補正,各環境下での熱拡散係数の算出,比較,補正など)
http://seppina.cocolog-nifty.com/blog/2015/02/--r0b-c072.html
物理的な温度誤差は以下が詳しい(一部の図がリンク切れ?になっている)。
http://www.comb.kokushikan.ac.jp/lecture/envmeasure/node31.html
余談
市販の体温計
画像は OMRON HPより
1年を通してほぼ体温計を使うことがないし、壊れないので買わないために知らなかったが、
最近の腋に挟む体温計は、温度上昇を推定して短時間(15秒程度)で測ることができらしい。
また、耳に入れるタイプの体温計では、赤外線センサを利用して鼓膜の温度を1秒程度でセンシングが可能なようだ。
長い時間、腋で固定するのはめんどくさいと思っていたが、プログラムによって短縮されているみたいだ(もちろん別の要因等によっても改善されているのかもしれないが)。
腋に挟む体温計は耳に入れるタイプに比べ時間が遅いが、配線を通して熱が逃げていくためか、サーミスタの温度が上昇が遅い。
グラフを信じれば、体温とセンサが平衡温になるまで10分も!かかる。