常用算法 之 牛頓迭代法求解PT100溫度(高階方程求解)

問題

  在最近的工作中用到了PT100鉑電阻,它適用於醫療、電機、工業、溫度計算、衛星、氣象、阻值計算等高精溫度設備,應用範圍非常之廣泛。類似的還有PT1000。
  PT後的100即表示它在0℃時阻值爲100歐姆,在100℃時它的阻值約爲138.5歐姆。它的工作原理:當PT100在0攝氏度的時候他的阻值爲100歐姆,它的的阻值會隨着溫度上升它的阻值是成勻速增長的。
  在國家標準《GBT 30121-2013 工業鉑熱電阻及鉑感溫元件.pdf》中(下載見附件),PT100的分度表如下圖所示:
PT100
溫度與阻值的計算公式,在標準文檔中也是有的,如下:
PT100Func
以上公式涉及到高階方程的求解問題!

方法

  一般可使用牛頓迭代法求近似解!關於該方法,網友馬同學高等數學 寫了一篇非常棒的文章如何通俗易懂地講解牛頓迭代法?來進行了非常詳細的介紹。由於沒有作者的授權,這裏不方便轉載,感興趣的可以點擊以上鍊接去看看!需要很強的數學知識哦!!!突然感覺,當初的高等數學白學了,唉。。。

源碼

  從溫度獲取阻值非常簡單,重點在於從阻值獲取溫度!用二階導數切線法,根據電阻接近零度電阻程度,用1到3次計算可得到較爲精確的溫度值:

  1. 先用線性公式得到一個粗略的溫度:
    t1 = (Rt / R0 - 1) / A
    計算t1的阻值:
    0度以上用公式:Rt1 = R0 * (1 + A * t1 + B * t1 * t1);
    0度以下用公式:Rt1 = R0 * [1 + A * t1 + B * t1 * t1 + C * (t1 - 100) * t1 * t1 * t1];
    如果 |Rt1 - Rt| < 0.001,t1 就是所要的溫度,反之繼續進行下面的計算:
  2. 計算一階導數和二階導數:
    如果 Rt ≥ R0
    t1’ = 1 / [R0 * (A + 2 * B * t1)]
    t1’’ =-2 * B * R0 * t1’ * t1’ * t1’
    如果 Rt < R0
    t1’ = 1 / [R0 * (A + 2 * B * t1 - 300 * C * t1 * t1 + 4 * C * t1 * t1 * t1)]
    t1’’=- R0 * (2 * B - 600 * C * t1 + 12 * C * t1 * t1) * t1’ * t1’ * t1’
  3. 基於 Rt,t1,Rt1 計算近似溫度 t2:
    t2 = t1 + t1’ * (Rt - Rt1) + 0.5 * t1’’ * (Rt - Rt1) * (Rt - Rt1),再計算出 t2 對應的電阻 Rt2。
  4. 如果 |Rt2 - Rt| < 0.001,t2 就是所要的溫度,反之再從第二步開始計算 t2 的一二階導數,最終得出精確的溫度值。
#include <stdio.h>
#include <math.h>
#include <stdbool.h>

#define A 3.9083e-3
#define B -5.775e-7
#define C -4.183e-12


/**
 * @brief 從溫度獲取阻值
 * @param[in] temp		溫度值
 * @param[out] resist	阻值
 * @retval  是否成功
 */
bool GetResistanceFromTempereture(double temp, double* resist)
{
	double fT, fR;
	bool ret;

	if(resist == NULL)
	{
		return false;
	}

	if (temp >= -200 && temp < 0)
	{
		*resist = 100 * (1 + A * temp + B * temp * temp + C * (temp - 100) * temp * temp * temp);
		ret = true;
	}
	else if (temp >= 0 && temp <= 850)
	{
		*resist = 100 * (1 + A * temp + B * temp * temp);
		ret = true;
	}
	else
	{
		*resist = 0;
		ret = false;
	}
	return ret;
}

/**
 * @brief 從阻值獲取溫度
 * @param[in] resist	阻值
 * @param[out] temp		溫度值
 * @retval  是否成功
 * @note 用二階導數切線法,根據電阻接近零度電阻程度,用1到3次計算可得到較爲精確的溫度值:
 *	1. 先用線性公式得到一個粗略的溫度:
 *		t1 = (Rt / R0 - 1) / A
 *
 *		計算t1的阻值:
 *			0度以上用公式:Rt1 = R0 * (1 + A * t1 + B * t1 * t1);
 *			0度以下用公式:Rt1 = R0 * [1 + A * t1 + B * t1 * t1 + C * (t1 - 100) * t1 * t1 * t1];
 *
 *		如果 |Rt1 - Rt| < 0.001,t1 就是所要的溫度,反之繼續進行下面的計算:
 *
 *	2.  計算一階導數和二階導數:
 *		如果 Rt ≥ R0
 *			t1' = 1 / [R0 * (A + 2 * B * t1)]
 *			t1'' =-2 * B * R0 * t1' * t1' * t1'
 *		如果 Rt < R0
 *			t1' = 1 / [R0 * (A + 2 * B * t1 - 300 * C *  t1 *  t1 + 4 * C *  t1 *  t1 *  t1)]
 *			t1''=- R0 * (2 * B - 600 * C *  t1 + 12 * C *  t1 *  t1) * t1' * t1' * t1'
 *
 *	3. 基於 Rt,t1,Rt1 計算近似溫度 t2:
 *		t2 = t1 + t1' * (Rt - Rt1) + 0.5 * t1'' * (Rt - Rt1) * (Rt - Rt1),再計算出 t2 對應的電阻 Rt2。
 *
 *	4. 如果 |Rt2 - Rt| < 0.001,t2 就是所要的溫度,反之再從第二步開始計算 t2 的一二階導數,最終得出精確的溫度值。
 */
bool GetTemperetureFromResistance(double resist, double* temp)
{
	bool ret;
	double fT, fT0;
	short i;

	if(temp == NULL)
	{
		return false;
	}

	/* 1. 先用線性公式得到一個粗略的溫度 */
	fT0 = (resist / 100 - 1) / A;
	/* 計算t1的阻值 */
	if (resist >= 18.52 && resist < 100) /* -200℃ ~ 0℃ */
	{
		for (i = 0; i < 50; i++)
		{
			fT = fT0 + (resist - 100 * (1 + A * fT0 + B * fT0 * fT0 - 100 * C * fT0 * fT0 * fT0 + C * fT0 * fT0 * fT0 * fT0)) /
						   (100 * (A + 2 * B * fT0 - 300 * C * fT0 * fT0 + 4 * C * fT0 * fT0 * fT0));
			if (fabs(fT - fT0) < 0.001) /* 如果 |Rt1 - Rt| < 0.001,t1 就是所要的溫度 */
			{
				break;
			}
			else
			{
				fT0 = fT;
			}
		}
		*temp = fT;
		ret = true;
	}
	else if (resist >= 100 && resist <= 390.481) /* 0℃ ~ 850℃ */
	{
		for (i = 0; i < 50; i++)
		{
			fT = fT0 + (resist - 100 * (1 + A * fT0 + B * fT0 * fT0)) / (100 * (A + 2 * B * fT0));
			if (fabs(fT - fT0) < 0.001) /* 如果 |Rt1 - Rt| < 0.001,t1 就是所要的溫度 */
			{
				break;
			}
			else
			{
				fT0 = fT;
			}
		}
		*temp = fT;
		ret = true;
	}
	else
	{
		ret = false;
	}
	return ret;
}

/* 測試 */
int main(int argc, char const *argv[])
{
	double temp = 0;
	double resist = 68.33;

	if(GetTemperetureFromResistance(resist, &temp))
	{
		printf("Temp = %f\r\n", temp);
	}
	else
	{
		printf("Temp = Error!\r\n");
	}
	return 0;
}

附件

  1. GBT 30121-2013 工業鉑熱電阻及鉑感溫元件.pdf
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章