はっくはっくキッチン
Hack Hack Kitchen

MAX31855の温度データーの補正

 2022/02/06

背景

MAX31855 のデーターシート (日本語版) によると、このデバイスでは熱起電力 $E$ から温度を求める際、 $$\begin{align} E = C (t_\mathrm{R} - t_\mathrm{AMB}) \end{align}$$ ($C$ は熱電対の種類ごとの定数 (sensitivity), $t_\mathrm{R}$ は測温接点 (remote) の温度、$t_\mathrm{AMB}$ はデバイス (環境, ambient) の温度) という関係を仮定して計算しています。 しかし実際には、熱起電力と温度差はこのような線形関係ではなく、とくに氷点下においては大きなズレが生じます。

これに対する議論は Adafruit のフォーラム でかなり以前からされており、Pete (heypete) 氏が同フォーラム及び 同氏のブログ にて詳細を記述しています。 補正の手順については、同フォーラムに投稿された MAX31855 Linearized Thermocouple Temperature (PNG ファイル) に説明されており、具体的なコードは、上記フォーラムに投稿された Jeff (jh421797) 氏、及び Pete (heypete) 氏による実装 (本質的にはいずれもほぼ等価) についてまとめた記事 Maxim 31855 Thermocouple Linearization (Adafruit) にあります。 しかし、

  • 全体的に見通しが悪く、何をやっているか分かりにくい

  • pow() 関数を使っているため、遅く、また、バイナリーのサイズがやや大きい

  • .ino (Arduino 用ファイル) として書かれているため、汎用性に欠ける

という短所があります。

そこで、熱起電力・温度間の変換の関数を Library for Thermocouple based on NIST ITS-90 Database として再実装しました。 このライブラリーには MAX31855 固有の処理は含まれませんが、以下で説明するように非常に簡単に対応できます。 また、NIST のデーターベースから変換するスクリプトにより自動生成するようにしたため、 NIST ITS-90 database に含まれる全ての熱電対に対応しています。 多項式の計算にはホーナーの方法を使用しました。 これらにより、記述がすっきりし、バイナリーサイズや実行時間も大幅に短縮されました。

MAX31855から得られるデーターの補正

ライブラリー自体の使用方法は Library for Thermocouple based on NIST ITS-90 Database を参照して下さい。

以下では温度の単位は $\degree\mathrm{C}$, 熱起電力の単位は mV です。

K型の場合は次のように書くことで、MAX31855 から得られた Thermocouple Temperature (測温接点の温度) rawTemp と Cold-Junction Temperature (冷接点の温度) internalTemp から補正した (より正確な) 温度を計算できます。

correctedTemp = emf2temp_K((rawTemp - internalTemp) * 0.041276 + temp2emf_K(internalTemp));

emf2temp_K() 及び temp2emf_K()Library for Thermocouple based on NIST ITS-90 Database により提供される関数です。

なお、K 型以外の場合は、関数名を対応する熱電対 (emf2temp_B など) に変更し、定数 (上では 0.041276) を MAX31855 のデーターシートに載っている値に変更します。

この式と上に挙げた手順 MAX31855 Linearized Thermocouple Temperature との対応は次のようになっています。

$$\begin{align} t_\mathrm{corr} = \underbrace{ \mathrm{emf2temp}( \underbrace{ \underbrace{ \underbrace{(t'_\mathrm{R} - t_\mathrm{AMB})}_\text{step 1} \cdot C}_\text{step 2} + \underbrace{\mathrm{temp2emf}(t_\mathrm{AMB})}_\text{step 3} }_\text{step 4} )}_\text{step 5} \end{align}$$ ここで、

$t_\mathrm{corr}$

補正後の温度

$t'_\mathrm{R}$

MAX31855 から得られた Thermocouple Temperature (測温接点の温度) (rawTemp)。 あまり正確ではない (補正されるべき) という意味合いで $t_\mathrm{R}$ に $'$ を付けています。

$t_\mathrm{AMB}$

MAX31855 から得られた Cold-Junction Temperature (冷接点の温度) (internalTemp)

$C$

MAX31855 で使用されている sensitivity (式 (1) 参照)

です。

Mike 氏 (zike) のポスト にあるように、$t_\mathrm{AMB}$ (internalTemp) を EMF に直す計算に線形の式を用いたければ、

correctedTemp = emf2temp_K((rawTemp - internalTemp) * 0.041276 + internalTemp * 0.04073);

とします。(使用している定数については MAX31855 のデーターシート参照)

比較

参考までに、Arduino において、 Library for Thermocouple based on NIST ITS-90 Database を用いた実装 (下表では TPKato)、及び HeyPete 氏の MAX31855-Linearization (下表では heypete) におけるバイナリーサイズ及び実行時間を比較してみました。

比較に使用したコードは https://github.com/TPKato/arduino-max31855-nist を参照して下さい。

環境

  • gcc version 11.2.0 (+ Arduino IDE 1.8.19)

  • Arduino libraries

    • SPI at version 1.0

    • Wire at version 1.0

    • Adafruit_MAX31855_library at version 1.3.0

    • Adafruit_BusIO at version 1.10.3

  • Arduino Nano

結果

バイナリーサイズ (K型熱電対, 時間計測のコードは含まず)

TPKato 8490 bytes
heypete 9386 bytes

実行時間 $\tau_\mathrm{exec}$

約1秒毎、10回測定の平均。

$\overline{\tau_\mathrm{exec}} / \mathrm{\mu{}s}$ $\overline{t_\mathrm{raw}}/\degree\mathrm{C}$ $\overline{t_\mathrm{int}}/\degree\mathrm{C}$ $\overline{t_\mathrm{corr}}/\degree\mathrm{C}$
TPKato $\phantom{0}619.6$ $25.75$ $26.19$ $25.73$
heypete $6654.2$ $25.75$ $26.14$ $25.74$

本質的な違いは pow() の変わりにホーナー法を使っていることだけですが、性能がかなり向上していることが分かります。 また、関数として書き直すことで、メインのコードも非常にすっきりし、処理の本質的な部分が分かりやすくなっています。

補遺: 式の導出

一般論

一般に熱電対を使った温度の測定では、ゼーベック効果による熱起電力 $E$ と基準接点側の温度 $t_\mathrm{AMB}$ を測定します。 熱起電力 $E$ を両接点の温度 $T_1$ と $T_2$ の関数として $E(T_1, T_2)$ と書くと、 $$\begin{align} E(T_1, T_2) = \int_{T_1}^{T_2} \left( S_\mathrm{B}(T) - S_\mathrm{A}(T) \right) \mathrm{d} T \end{align}$$ と書けます (ここで、$S_\mathrm{A}(T)$、 $S_\mathrm{B}(T)$ はそれぞれ熱電対を構成する金属 A, B のゼーベック係数)。 従って、 $$\begin{align} E(T_1, T_2) &= E(T_1, T_3) + E(T_3, T_2) \\ E(T_1, T_2) &= -E(T_2, T_1) \end{align}$$ が成立します (積分区間の分割, 積分区間の入れ替え)。 このことから、$T_1$, $T_2$, $T_3$ をそれぞれ 測温接点の温度 $t_\mathrm{R}$, 基準接点の温度 $t_\mathrm{AMB}$ 及び $0\,\mathrm{\degree{}C}$ とすれば、 $$\begin{align} E(t_\mathrm{R}, t_\mathrm{AMB}) &= E(t_\mathrm{R}, 0\,\mathrm{\degree{}C}) - E(t_\mathrm{AMB}, 0\,\mathrm{\degree{}C}) \end{align}$$ 従って、 $$\begin{align} E(t_\mathrm{R}, 0\,\mathrm{\degree{}C}) &= E(t_\mathrm{R}, t_\mathrm{AMB}) + E(t_\mathrm{AMB}, 0\,\mathrm{\degree{}C}) \end{align}$$ となります (あるいは $T_1 = t_\mathrm{R}$, $T_2 = 0\,\mathrm{\degree{}C}$, $T_3 = t_\mathrm{AMB}$ として式 (4) を適用してもよい)。

$0\,\mathrm{\degree{}C}$ を基準とした 熱起電力 $E(t, 0\,\mathrm{\degree{}C})$ から温度を求める関数を $t^0_\mathrm{TC}(E)$ とすると、 $$\begin{align} t_\mathrm{R} & = t^0_\mathrm{TC}(E(t_\mathrm{R}, 0\,\mathrm{\degree{}C})) \\ &= t^0_\mathrm{TC}( \underbrace{E(t_\mathrm{R}, t_\mathrm{AMB})}_\text{measured} + E( \underbrace{t_\mathrm{AMB}}_\text{measured}, 0\,\mathrm{\degree{}C}) ) \end{align}$$ により、求めたい温度 $t_\mathrm{R}$ が得られます。

実際には $E(t, 0\,\mathrm{\degree{}C})$ 及び $t^0_\mathrm{TC}(E)$ は未知なので、 対応表もしくは近似式を用いて算出します。

例として、K 型熱電対の熱起電力表を抜粋したものを以下に載せます。 (熱起電力の単位: mV。NIST の all.tab を元に作成)

$t/ \mathrm{\degree{}C}$ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9
0 0.000 0.039 0.079 0.119 0.158 0.198 0.238 0.277 0.317 0.357
10 0.397 0.437 0.477 0.517 0.557 0.597 0.637 0.677 0.718 0.758
20 0.798 0.838 0.879 0.919 0.960 1.000 1.041 1.081 1.122 1.163
30 1.203 1.244 1.285 1.326 1.366 1.407 1.448 1.489 1.530 1.571
40 1.612 1.653 1.694 1.735 1.776 1.817 1.858 1.899 1.941 1.982

例えば、

  • $t_\mathrm{AMB} = 24\,\mathrm{\degree{}C}$ のときに、

  • 測定した熱起電力が $0.529\,\mathrm{mV}$ だった

とすると、式 (9) とこの表から、 $$\begin{align*} t_\mathrm{R} &= t^0_\mathrm{TC}( \underbrace{0.529\,\mathrm{mV}}_{E(t_\mathrm{R}, t_\mathrm{AMB})} + \underbrace{0.960\,\mathrm{mV}}_{E(t_\mathrm{AMB}, 0\,\mathrm{\degree{}C})} ) \\ &= t^0_\mathrm{TC}(1.489\,\mathrm{mV}) \\ &= 37\,\mathrm{\degree{}C} \end{align*}$$ と求まります。

つまり $E(t, 0\,\mathrm{\degree{}C})$ は表の対応する温度から熱起電力を求め、 $t^0_\mathrm{TC}(E)$ は表から一致する熱起電力を探してそこから対応する温度を求める、という操作に対応します。

このような表はコンピューターでの処理には不便なので、近似式として表したものを使用します。

線形仮定

ゼーベック係数が温度に依存しないと仮定すると、式 (3) は、 $$\begin{align} E(T_1, T_2) = C (T_1 - T_2) \end{align}$$ ($C = - S_\mathrm{B} + S_\mathrm{A}$) となり、再び $T_1$, $T_2$ をそれぞれ $t_\mathrm{R}$, $t_\mathrm{AMB}$ とすれば、 $$\begin{align} E(t_\mathrm{R}, t_\mathrm{AMB}) &= C (t_\mathrm{R} - t_\mathrm{AMB}) \end{align}$$ となるので、これより $t_\mathrm{R}$ を求めれば、 $$\begin{align} t'_\mathrm{R} &= \frac{1}{C}E(t_\mathrm{R}, t_\mathrm{AMB}) + t_\mathrm{AMB} \end{align}$$ となります。 ここで式 (12) では線形仮定 (つまりあまり正確ではない) という意味合いで $t_\mathrm{R}$ に $'$ を付けています。

式 (11) がまさにデーターシートに載っている式であり、このようにして計算された $t'_\mathrm{R}$ が MAX31855 の出力として得られるデーターとなります。 しかし、この仮定はかなりラフな (限られた温度範囲内のみでの) 近似としてしか成立しません。

補正

そこで、

  1. MAX31855 から得られた $t'_\mathrm{R}$, $t_\mathrm{AMB}$ をもとに熱起電力 $E(t_\mathrm{R}, t_\mathrm{AMB})$ を逆算し、

  2. この値 (と $t_\mathrm{AMB}$) を用いて、改めて式 (9) を適用する

ことによって、より正確な測温接点温度を求めることができます。

そのために、式 (11) を式 (9) を代入すると、 $$\begin{align} t_\mathrm{R} & = t^0_\mathrm{TC}(C (t_\mathrm{R} - t_\mathrm{AMB}) + E(t_\mathrm{AMB}, 0\,\mathrm{\degree{}C})) \end{align}$$ となり、これが上に述べた式となります。 $t^0_\mathrm{TC}(E)$ が emf2temp() と、$E(t, 0\,\mathrm{\degree{}C})$ が temp2emf() と対応しています。