ALGO_Temperature_ATY.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /**
  2. * @file ALGO_Temperature_ATY.c
  3. *
  4. * @param Project ALGO_Algorithm_ATY_LIB
  5. *
  6. * @author ATY
  7. *
  8. * @copyright
  9. * - Copyright 2017 - 2026 MZ-ATY
  10. * - This code follows:
  11. * - MZ-ATY Various Contents Joint Statement -
  12. * <a href="https://mengze.top/MZ-ATY_VCJS">
  13. * https://mengze.top/MZ-ATY_VCJS</a>
  14. * - CC 4.0 BY-NC-SA -
  15. * <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
  16. * https://creativecommons.org/licenses/by-nc-sa/4.0/</a>
  17. * - Your use will be deemed to have accepted the terms of this statement.
  18. *
  19. * @brief functions of NTC or others temperature calc
  20. *
  21. * @version
  22. * - 1_01_230107 > ATY
  23. * -# Preliminary version, first Release
  24. * - 1_02_251120 > ATY
  25. * -# Full test
  26. ********************************************************************************
  27. */
  28. #ifndef __ALGO_Temperature_ATY_C
  29. #define __ALGO_Temperature_ATY_C
  30. #include "ALGO_Temperature_ATY.h"
  31. #define ALGO_Temperature_ATY_TAG "\r\n[ALGO_Temperature_ATY] "
  32. #define RTD_A 3.9083e-3
  33. #define RTD_B -5.775e-7
  34. #define RTD_C -4.183e-12
  35. /******************************* For user *************************************/
  36. #include <math.h>
  37. #define ALGO_LOG_DEF(v) log(v)
  38. #define ALGO_Sqrt_DEF(v) sqrt(v)
  39. // #include "ALGO_AlgorithmBase_ATY.h"
  40. // #define ALGO_LOG_DEF(v) ALGO_MATH_LogLn(v)
  41. // #define ALGO_Sqrt_DEF(v) ALGO_Sqrt_NewtonNumber(v)
  42. /******************************************************************************/
  43. // NTC -------------------------------------------------------------------------
  44. /**
  45. * @brief Calculate temperature from ntc resistance(Steinhart-Hart change)
  46. * @param Rntc Current NTC resistance value
  47. * @param R25 NTC standard resistance value at 25C
  48. * @param B B value of NTC
  49. * @return Current temperature in Celsius
  50. * @note T25: Kelvin temperature at 25C = 298.15 = ALGO_TEMP_CtoT(25)
  51. * R25: NTC standard resistance value at 25C like 10K,5K,100K...
  52. * B: B value of NTC like 3435,3950...
  53. * Rntc: Current NTC resistance value
  54. * Tn: Actual Kelvin temperature(Cn = Tn-273.15)
  55. * B = (lnR25 - lnRntc)/(1/T25 - 1/Tn)
  56. */
  57. double ALGO_ResToKelvinTemp(double Rntc, double R25, double B){
  58. if(Rntc <= 0) return 0;
  59. if(R25 <= 0) return 0;
  60. double Tn = 0.0;
  61. double Cn = 0.0;
  62. double temp_f[2];
  63. temp_f[0] = (ALGO_LOG_DEF(R25) - ALGO_LOG_DEF(Rntc)) / B;
  64. temp_f[1] = (1.0 / ALGO_TEMP_CtoT(25)) - temp_f[0];
  65. Tn = 1.0 / temp_f[1];
  66. Cn = ALGO_TEMP_TtoC(Tn);
  67. return Cn;
  68. }
  69. /**
  70. * @brief Calculate temperature from ntc resistance
  71. * @param vADC ADC voltage in mV
  72. * @param vRef NTC ref voltage in mV
  73. * @param rRefK ref resistance in kOhm
  74. * @param R25 NTC standard resistance value at 25C
  75. * @param B B value of NTC
  76. * @param rRefPos ref res psition, 1 for pull up, 0 for pull down(for ntc)
  77. * @return Current temperature in Celsius
  78. * @note T25: Kelvin temperature at 25C = 298.15 = ALGO_TEMP_CtoT(25)
  79. * R25: NTC standard resistance value at 25C like 10K,5K,100K...
  80. * B: B value of NTC like 3435,3950...
  81. * Rntc: Current NTC resistance value
  82. * Tn: Actual Kelvin temperature(Cn = Tn-273.15)
  83. * B = (lnR25 - lnRntc)/(1/T25 - 1/Tn)
  84. */
  85. double ALGO_VolToKelvinTemp(double vADC, double vRef, double rRefK, double R25, double B, uint8_t rRefPos){
  86. if(rRefPos == 1){
  87. return ALGO_ResToKelvinTemp(ALGO_VoltageToResDown(vADC, vRef, rRefK), R25, B);
  88. }
  89. else{
  90. return ALGO_ResToKelvinTemp(ALGO_VoltageToResUp(vADC, vRef, rRefK), R25, B);
  91. }
  92. }
  93. /**
  94. * @brief Calculate temperature from ntc resistance(Steinhart-Hart)
  95. * @param Rntc Current NTC resistance value
  96. * @param A A value of NTC
  97. * @param B B value of NTC
  98. * @param C C value of NTC
  99. * @return Current temperature in Celsius
  100. */
  101. double ALGO_ResToKelvinTempABC(double Rntc, double A, double B, double C){
  102. double Tn = 0.0;
  103. double Cn = 0.0;
  104. Tn = (A + (B * ALGO_LOG_DEF(Rntc)) + (C * ALGO_LOG_DEF(Rntc) * ALGO_LOG_DEF(Rntc) * ALGO_LOG_DEF(Rntc)));
  105. Tn = 1.0 / Tn;
  106. Cn = ALGO_TEMP_TtoC(Tn);
  107. return Cn;
  108. }
  109. // RTD fast(PT100) -------------------------------------------------------------
  110. /**
  111. * @brief Calculate temperature from RTD resistance(PT100)
  112. *
  113. * @param T Temperature in Degrees Celsius
  114. * @return double RTD resistance in ohms
  115. */
  116. double ALGO_Temp_RTD_T(double T){
  117. if(T >= -200 && T < 0){
  118. return 100 * (1 + RTD_A * T + RTD_B * T * T + RTD_C * (T - 100) * T * T * T);
  119. }
  120. else if(T >= 0 && T <= 850){
  121. return 100 * (1 + RTD_A * T + RTD_B * T * T);
  122. }
  123. return 0;
  124. }
  125. /**
  126. * @brief Calculate temperature from RTD resistance(PT100)
  127. *
  128. * @param rtdRes RTD resistance in ohms
  129. * @return double Temperature in Degrees Celsius
  130. */
  131. double ALGO_Temp_RTD_Res_Fast(double rtdRes){
  132. return (double)((rtdRes - 100.0) / 0.385);
  133. }
  134. /**
  135. * @brief Calculate temperature from RTD resistance(PT100) above 0C
  136. *
  137. * @param rtdRes RTD resistance in ohms
  138. * @return double Temperature in Degrees Celsius
  139. */
  140. double ALGO_Temp_RTD_Res_Above(double rtdRes){
  141. return (double)(((-1 * RTD_A) + ALGO_Sqrt_DEF((RTD_A * RTD_A)
  142. - 4 * (RTD_B) * (1 - (rtdRes / 100.0))))
  143. / (2 * (RTD_B)));
  144. }
  145. /**
  146. * @brief Calculate temperature from RTD resistance(PT100) below 0C
  147. *
  148. * @param rtdRes RTD resistance in ohms
  149. * @return double Temperature in Degrees Celsius
  150. */
  151. double ALGO_Temp_RTD_Res_Below(double rtdRes){
  152. return (double)(-242.02
  153. + 2.2228 * rtdRes
  154. + (2.5859e-3) * rtdRes * rtdRes
  155. - (4.826e-6) * rtdRes * rtdRes * rtdRes
  156. - (2.8183e-8) * rtdRes * rtdRes * rtdRes * rtdRes
  157. + (1.5243e-10) * rtdRes * rtdRes * rtdRes * rtdRes * rtdRes);
  158. }
  159. // RTD precise -----------------------------------------------------------------
  160. /**
  161. * @brief PT100 temperature calculation using second-order tangent method
  162. * @param[in] resist RTD resistance in ohms
  163. * @param[out] temp Degrees Celsius
  164. * @retval Temperature in Degrees Celsius
  165. * @note Use a second-derivative tangent method. Depending on how close the resistance
  166. * is to the zero-degree resistance, 1-3 iterations yield an accurate temperature:
  167. * 1. Use a linear formula to get a rough temperature:
  168. * t1 = (Rt / R0 - 1) / A
  169. *
  170. * Compute the resistance at t1:
  171. * For t1 >= 0C: Rt1 = R0 * (1 + A * t1 + B * t1 * t1);
  172. * For t1 < 0C: Rt1 = R0 * [1 + A * t1 + B * t1 * t1 + C * (t1 - 100) * t1 * t1 * t1];
  173. *
  174. * If |Rt1 - Rt| < 0.001, t1 is the desired temperature; otherwise continue:
  175. *
  176. * 2. Compute the first and second derivatives:
  177. * If Rt >= R0
  178. * t1' = 1 / [R0 * (A + 2 * B * t1)]
  179. * t1'' = -2 * B * R0 * t1' * t1' * t1'
  180. * If Rt < R0
  181. * t1' = 1 / [R0 * (A + 2 * B * t1 - 300 * C * t1 * t1 + 4 * C * t1 * t1 * t1)]
  182. * t1'' = - R0 * (2 * B - 600 * C * t1 + 12 * C * t1 * t1) * t1' * t1' * t1'
  183. *
  184. * 3. Compute the approximate temperature t2 based on Rt, t1, Rt1:
  185. * t2 = t1 + t1' * (Rt - Rt1) + 0.5 * t1'' * (Rt - Rt1) * (Rt - Rt1);
  186. * then compute the corresponding resistance Rt2.
  187. *
  188. * 4. If |Rt2 - Rt| < 0.001, t2 is the desired temperature; otherwise start from
  189. * step 2 to compute derivatives again and obtain the accurate temperature.
  190. */
  191. double ALGO_Temp_RTD_Res_PT100(double resist){
  192. double fT, fT0;
  193. short i;
  194. /* 1. use a linear formula to get a rough temperature first */
  195. fT0 = (resist / 100 - 1) / RTD_A;
  196. /* -200C ~ 0C */
  197. if(resist >= 18.52 && resist < 100){
  198. for(i = 0; i < 50; i++){
  199. fT = fT0 + (resist - 100 * (1 + RTD_A * fT0 + RTD_B * fT0 * fT0
  200. - 100 * RTD_C * fT0 * fT0 * fT0 + RTD_C * fT0 * fT0 * fT0 * fT0)) /
  201. (100 * (RTD_A + 2 * RTD_B * fT0 - 300 * RTD_C * fT0 * fT0 + 4 * RTD_C * fT0 * fT0 * fT0));
  202. /* If | Rt1-Rt | < 0.001, t1 is the desired temperature */
  203. if(fabs(fT - fT0) < 0.001){
  204. return fT;
  205. }
  206. else{
  207. fT0 = fT;
  208. }
  209. }
  210. }
  211. /* 0C ~ 850C */
  212. else if(resist >= 100 && resist <= 390.481){
  213. for(i = 0; i < 50; i++){
  214. fT = fT0 + (resist - 100 * (1 + RTD_A * fT0 + RTD_B * fT0 * fT0)) / (100 * (RTD_A + 2 * RTD_B * fT0));
  215. /* If | Rt1-Rt | < 0.001, t1 is the desired temperature */
  216. if(fabs(fT - fT0) < 0.001){
  217. return fT;
  218. }
  219. else{
  220. fT0 = fT;
  221. }
  222. }
  223. }
  224. return 0;
  225. }
  226. /**
  227. * @brief Calculate temperature from RTD resistance(PT1000)
  228. *
  229. * @param resist RTD resistance in ohms
  230. * @return double Temperature in Degrees Celsius
  231. */
  232. double ALGO_Temp_RTD_Res_PT1000(double resist){
  233. return ALGO_Temp_RTD_Res_PT100(resist / 10.0);
  234. }
  235. // TC -------------------------------------------------------------------------
  236. /**
  237. * @brief Thermocouple Type
  238. *
  239. * @param type
  240. * @param Temp in Degrees Celsius
  241. * @return double in mV
  242. * @note https://srdata.nist.gov/
  243. */
  244. double ALGO_Temp_TC_TempToVol(uint8_t type, double Temp){
  245. if(type == 'T'){
  246. if(Temp == 0)
  247. return 0;
  248. else if(Temp > 0){
  249. return (0
  250. + ((0.387481063640e-1) * Temp)
  251. + ((0.332922278800e-4) * Temp * Temp)
  252. + ((0.206182434040e-6) * Temp * Temp * Temp)
  253. + ((-0.218822568460e-8) * Temp * Temp * Temp * Temp)
  254. + ((0.109968809280e-10) * Temp * Temp * Temp * Temp * Temp)
  255. + ((-0.308157587720e-13) * Temp * Temp * Temp * Temp * Temp * Temp)
  256. + ((0.454791352900e-16) * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  257. + ((-0.275129016730e-19) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp));
  258. }
  259. else if(Temp < 0){
  260. return (0
  261. + ((0.387481063640e-01) * Temp)
  262. + ((0.441944343470e-04) * Temp * Temp)
  263. + ((0.118443231050e-06) * Temp * Temp * Temp)
  264. + ((0.200329735540e-07) * Temp * Temp * Temp * Temp)
  265. + ((0.901380195590e-09) * Temp * Temp * Temp * Temp * Temp)
  266. + ((0.226511565930e-10) * Temp * Temp * Temp * Temp * Temp * Temp)
  267. + ((0.360711542050e-12) * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  268. + ((0.384939398830e-14) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  269. + ((0.282135219250e-16) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  270. + ((0.142515947790e-18) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  271. + ((0.487686622860e-21) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  272. + ((0.107955392700e-23) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  273. + ((0.139450270620e-26) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp)
  274. + ((0.797951539270e-30) * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp * Temp));
  275. }
  276. }
  277. return 0;
  278. }
  279. /**
  280. * @brief Thermocouple Type
  281. *
  282. * @param type
  283. * @param voltage in mV
  284. * @return double in Degrees Celsius
  285. * @note https://srdata.nist.gov/
  286. */
  287. double ALGO_Temp_TC_VolToTemp(uint8_t type, double voltage){
  288. if(type == 'T'){
  289. if(voltage == 0)
  290. return 0;
  291. else if(voltage > 0){
  292. return (0
  293. + ((2.592800e1) * voltage)
  294. + ((-7.602961e-1) * voltage * voltage)
  295. + ((4.637791e-2) * voltage * voltage * voltage)
  296. + ((-2.165394e-3) * voltage * voltage * voltage * voltage)
  297. + ((6.048144e-5) * voltage * voltage * voltage * voltage * voltage)
  298. + ((-7.293422e-7) * voltage * voltage * voltage * voltage * voltage * voltage));
  299. }
  300. else if(voltage < 0){
  301. return (0
  302. + ((2.5949192e1) * voltage)
  303. + ((-2.1316967e-1) * voltage * voltage)
  304. + ((7.9018692e-1) * voltage * voltage * voltage)
  305. + ((4.2527777e-1) * voltage * voltage * voltage * voltage)
  306. + ((1.3304473e-1) * voltage * voltage * voltage * voltage * voltage)
  307. + ((2.0241446e-2) * voltage * voltage * voltage * voltage * voltage * voltage)
  308. + ((1.2668171e-3) * voltage * voltage * voltage * voltage * voltage * voltage * voltage));
  309. }
  310. }
  311. return 0;
  312. }
  313. // Table -------------------------------------------------------------------
  314. /**
  315. * @brief Lookup temperature from resistance table
  316. *
  317. * @param R in ohms, or voltage to Thermocouple, follow tableR
  318. * @param tableT in C
  319. * @param tableR in R
  320. * @param tableSize T/R table must be the same size
  321. * @return double
  322. * @note tableT must raise, like -10, 0, 10, 20, 30, ...
  323. */
  324. double ALGO_RT_Table_R2T(double R, const double* tableT, const double* tableR, uint16_t tableSize){
  325. // negative temperature coefficient, like ntc
  326. if(tableR[0] > tableR[1]){
  327. // check border
  328. if(R < tableR[tableSize - 1] || R > tableR[0]){
  329. return -273.15;
  330. }
  331. // cycle
  332. for(uint16_t i = 0; i < tableSize - 1; i++){
  333. if(R == tableR[i]){
  334. return tableT[i];
  335. }
  336. if(R <= tableR[i] && R >= tableR[i + 1]){
  337. double T1 = tableT[i];
  338. double T2 = tableT[i + 1];
  339. double R1 = tableR[i];
  340. double R2 = tableR[i + 1];
  341. return T1 + (R - R1) * (T2 - T1) / (R2 - R1);
  342. }
  343. }
  344. }
  345. // positive temperature coefficient, like rtd
  346. else{
  347. // check border
  348. if(R > tableR[tableSize - 1] || R < tableR[0]){
  349. return -273.15;
  350. }
  351. // cycle
  352. for(uint16_t i = 0; i < tableSize - 1; i++){
  353. if(R == tableR[i]){
  354. return tableT[i];
  355. }
  356. if(R >= tableR[i] && R <= tableR[i + 1]){
  357. double T1 = tableT[i];
  358. double T2 = tableT[i + 1];
  359. double R1 = tableR[i];
  360. double R2 = tableR[i + 1];
  361. return T1 + (R - R1) * (T2 - T1) / (R2 - R1);
  362. }
  363. }
  364. }
  365. return -273.15;
  366. }
  367. /**
  368. * @brief Lookup resistance from temperature table
  369. *
  370. * @param T in C, just follow your tableT
  371. * @param tableT in C
  372. * @param tableR in R
  373. * @param tableSize T/R table must be the same size
  374. * @return double
  375. * @note tableT must raise, like -10, 0, 10, 20, 30, ...
  376. */
  377. double ALGO_RT_Table_T2R(double T, const double* tableT, const double* tableR, uint16_t tableSize){
  378. // check border
  379. if(T > tableT[tableSize - 1] || T < tableT[0]){
  380. return 0;
  381. }
  382. // cycle
  383. for(uint16_t i = 0; i < tableSize - 1; i++){
  384. if(T == tableT[i]){
  385. return tableR[i];
  386. }
  387. if(T >= tableT[i] && T <= tableT[i + 1]){
  388. double T1 = tableT[i];
  389. double T2 = tableT[i + 1];
  390. double R1 = tableR[i];
  391. double R2 = tableR[i + 1];
  392. return R1 + (T - T1) * (R2 - R1) / (T2 - T1);
  393. }
  394. }
  395. return 0;
  396. }
  397. // Test ------------------------------------------------------------------------
  398. #ifdef ALGO_Temperature_ATY_Test_ATY
  399. uint8_t ALGO_Temperature_ATY_Test_Pass;
  400. uint8_t ALGO_Temperature_ATY_Test_Fail;
  401. double ALGO_Temperature_ATY_Test_Out[74];
  402. static int __aty_close(double a, double b, double tol){
  403. return fabs(a - b) <= tol;
  404. }
  405. static double __aty_ntc_beta_res(double T, double R25, double B){
  406. double Tk = ALGO_TEMP_CtoT(T);
  407. double T25 = ALGO_TEMP_CtoT(25.0);
  408. return R25 * exp(B * (1.0 / Tk - 1.0 / T25));
  409. }
  410. static double __aty_v_pu_from_res(double R, double vRef, double rRefK){
  411. return vRef * R / (rRefK + R);
  412. }
  413. static double __aty_v_pd_from_res(double R, double vRef, double rRefK){
  414. return vRef * rRefK / (rRefK + R);
  415. }
  416. uint32_t ALGO_Temperature_ATY_Test(void){
  417. uint32_t idx = 0;
  418. ALGO_Temperature_ATY_Test_Pass = 0;
  419. ALGO_Temperature_ATY_Test_Fail = 0;
  420. printf_ATY_D("%sSTART\r\n", ALGO_Temperature_ATY_TAG);
  421. {
  422. // [0..5] NTC Beta R->T (ALGO_ResToKelvinTemp), target temps: [100, 25, 0, -40, 150, -55] (C)
  423. // Out[i] == targetTemps[i] (+-0.5C)
  424. double R25 = 10.0;
  425. double Bv = 3950.0;
  426. double tv[6] = {100.0, 25.0, 0.0, -40.0, 150.0, -55.0};
  427. printf_ATY_D("\r\n[NTC Beta R->T] R25 = %f, B = %f\r\n", R25, Bv);
  428. for(int i = 0; i < 6; i++){
  429. double R = __aty_ntc_beta_res(tv[i], R25, Bv);
  430. double out = ALGO_ResToKelvinTemp(R, R25, Bv);
  431. ALGO_Temperature_ATY_Test_Out[idx++] = out;
  432. if(__aty_close(out, tv[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  433. printf_ATY_D(" TargetT = %fC, CalcR = %f, OutT = %fC, %s\r\n", tv[i], R, out, (__aty_close(out, tv[i], 0.01) ? "PASS" : "FAIL"));
  434. }
  435. }
  436. {
  437. // [6..17] NTC V->T (ALGO_VolToKelvinTemp), per target temps [100, 25, 0, -40, 150, -55]
  438. // For temperature index j in 0..5:
  439. // Out[12 + j*2] pull-up topology result == targetTemps[j] (+-0.5C)
  440. // Out[12 + j*2 + 1] pull-down topology result == targetTemps[j] (+-0.5C)
  441. double vRef = 2500.0;
  442. double rRefK = 10.0;
  443. double R25 = 10.0;
  444. double Bv = 3950.0;
  445. double tv[6] = {100.0, 25.0, 0.0, -40.0, 150.0, -55.0};
  446. printf_ATY_D("\r\n[NTC V->T] vRef = %f mV, rRefK = %f kOhm, R25 = %f, B = %f\r\n", vRef, rRefK, R25, Bv);
  447. for(int i = 0; i < 6; i++){
  448. double R = __aty_ntc_beta_res(tv[i], R25, Bv);
  449. double vpu = __aty_v_pu_from_res(R, vRef, rRefK);
  450. double vpd = __aty_v_pd_from_res(R, vRef, rRefK);
  451. double out_pu = ALGO_VolToKelvinTemp(vpu, vRef, rRefK, R25, Bv, 1);
  452. double out_pd = ALGO_VolToKelvinTemp(vpd, vRef, rRefK, R25, Bv, 0);
  453. ALGO_Temperature_ATY_Test_Out[idx++] = out_pu;
  454. ALGO_Temperature_ATY_Test_Out[idx++] = out_pd;
  455. if(__aty_close(out_pu, tv[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  456. if(__aty_close(out_pd, tv[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  457. printf_ATY_D(" PU: TargetT = %fC, vADC = %f mV, OutT = %fC, %s\r\n", tv[i], vpu, out_pu, (__aty_close(out_pu, tv[i], 0.01) ? "PASS" : "FAIL"));
  458. printf_ATY_D(" PD: TargetT = %fC, vADC = %f mV, OutT = %fC, %s\r\n", tv[i], vpd, out_pd, (__aty_close(out_pd, tv[i], 0.01) ? "PASS" : "FAIL"));
  459. }
  460. }
  461. {
  462. // [18..23] NTC Steinhart-Hart ABC (ALGO_ResToKelvinTempABC) with resist list [2, 10, 32, 120, 0.5, 1e6] (KR/R)
  463. // Out[18] high temp > 80C
  464. // Out[19] room temp 15~35C
  465. // Out[20] near zero -5~5C
  466. // Out[21] below zero < 0C
  467. // Out[22] very high > 120C
  468. // Out[23] very low < -100C
  469. // double A = 0.001129148;
  470. // double Bc = 0.000234125;
  471. // double Cc = 0.0000000876741;
  472. double A = 2.681e-3;
  473. double Bc = 2.886e-4;
  474. double Cc = 7.275e-7;
  475. double rv[6] = {1.2, 10.0, 30.0, 120.0, 0.5, 1000000.0};
  476. printf_ATY_D("\r\n[NTC SH-ABC] A = %.3e, B = %.3e, C = %.3e\r\n", A, Bc, Cc);
  477. double out0 = ALGO_ResToKelvinTempABC(rv[0], A, Bc, Cc);
  478. ALGO_Temperature_ATY_Test_Out[idx++] = out0;
  479. if(out0 > 80.0) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  480. printf_ATY_D(" R = %f => T = %fC, > 80 ? %s\r\n", rv[0], out0, ((out0 > 80.0) ? "PASS" : "FAIL"));
  481. double out1 = ALGO_ResToKelvinTempABC(rv[1], A, Bc, Cc);
  482. ALGO_Temperature_ATY_Test_Out[idx++] = out1;
  483. if(out1 > 15.0 && out1 < 35.0) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  484. printf_ATY_D(" R = %f => T = %fC, 15.0 < T < 35.0 ? %s\r\n", rv[1], out1, ((out1 > 15.0 && out1 < 35.0) ? "PASS" : "FAIL"));
  485. double out2 = ALGO_ResToKelvinTempABC(rv[2], A, Bc, Cc);
  486. ALGO_Temperature_ATY_Test_Out[idx++] = out2;
  487. if(out2 > -5.0 && out2 < 5.0) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  488. printf_ATY_D(" R = %f => T = %fC, -5.0 < T < 5.0 ? %s\r\n", rv[2], out2, ((out2 > -5.0 && out2 < 5.0) ? "PASS" : "FAIL"));
  489. double out3 = ALGO_ResToKelvinTempABC(rv[3], A, Bc, Cc);
  490. ALGO_Temperature_ATY_Test_Out[idx++] = out3;
  491. if(out3 < 0.0) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  492. printf_ATY_D(" R = %f => T = %fC, < 0.0 ? %s\r\n", rv[3], out3, ((out3 < 0.0) ? "PASS" : "FAIL"));
  493. double out4 = ALGO_ResToKelvinTempABC(rv[4], A, Bc, Cc);
  494. ALGO_Temperature_ATY_Test_Out[idx++] = out4;
  495. if(out4 > 120.0) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  496. printf_ATY_D(" R = %f => T = %fC, > 120.0 ? %s\r\n", rv[4], out4, ((out4 > 120.0) ? "PASS" : "FAIL"));
  497. double out5 = ALGO_ResToKelvinTempABC(rv[5], A, Bc, Cc);
  498. ALGO_Temperature_ATY_Test_Out[idx++] = out5;
  499. if(out5 < -100.0) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  500. printf_ATY_D(" R = %f => T = %fC, < -100.0 ? %s\r\n", rv[5], out5, ((out5 < -100.0) ? "PASS" : "FAIL"));
  501. }
  502. {
  503. // [24..33] RTD fast R->T group per temps [-40, 0, 25, 100, 850] (C)
  504. // For index i in 0..4:
  505. // Out[24 + i*2] fast approx (ALGO_Temp_RTD_Res_Fast) ≈ temp (+-3C for >=0, +-5C for <0)
  506. // Out[24 + i*2 + 1] exact above/below (ALGO_Temp_RTD_Res_Above/Below) == temp
  507. double tv[5] = {-40.0, 0.0, 25.0, 100.0, 850.0};
  508. for(int i = 0; i < 5; i++){
  509. double Rpt100 = ALGO_Temp_RTD_T(tv[i]);
  510. double out_fast = ALGO_Temp_RTD_Res_Fast(Rpt100);
  511. double out_above = 0.0;
  512. double out_below = 0.0;
  513. ALGO_Temperature_ATY_Test_Out[idx++] = out_fast;
  514. if(__aty_close(out_fast, tv[i], (tv[i] > 100.0 ? 100.0 : 1.0))) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  515. printf_ATY_D("\r\n[RTD FAST] TargetT = %fC, R = %f Ohm, Fast = %fC, %s\r\n", tv[i], Rpt100, out_fast, (__aty_close(out_fast, tv[i], (tv[i] > 100.0 ? 100.0 : 1.0)) ? "PASS" : "FAIL"));
  516. if(tv[i] >= 0.0){
  517. out_above = ALGO_Temp_RTD_Res_Above(Rpt100);
  518. ALGO_Temperature_ATY_Test_Out[idx++] = out_above;
  519. if(__aty_close(out_above, tv[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  520. printf_ATY_D(" Above: R = %f Ohm, OutT = %fC, %s\r\n", Rpt100, out_above, (__aty_close(out_above, tv[i], 0.01) ? "PASS" : "FAIL"));
  521. }
  522. else{
  523. out_below = ALGO_Temp_RTD_Res_Below(Rpt100);
  524. ALGO_Temperature_ATY_Test_Out[idx++] = out_below;
  525. if(__aty_close(out_below, tv[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  526. printf_ATY_D(" Below: R = %f Ohm, OutT = %fC, %s\r\n", Rpt100, out_below, (__aty_close(out_below, tv[i], 0.01) ? "PASS" : "FAIL"));
  527. }
  528. }
  529. }
  530. {
  531. // [34..43] RTD fast R->T group per temps [-40, 0, 25, 100, 850] (C)
  532. // For index i in 0..4:
  533. // Out[34 + i*2] PT100 Newton (ALGO_Temp_RTD_Res_PT100) == temp (+-0.01C)
  534. // Out[34 + i*2 + 1] PT1000 Newton (ALGO_Temp_RTD_Res_PT1000) == temp (+-0.01C)
  535. double tv[5] = {-40.0, 0.0, 25.0, 100.0, 850.0};
  536. double Rpt100[5] = {84.272, 100.0, 109.740, 138.506, 390.481};
  537. for(int i = 0; i < 5; i++){
  538. double out_pt100 = ALGO_Temp_RTD_Res_PT100(Rpt100[i]);
  539. double out_pt1000 = ALGO_Temp_RTD_Res_PT1000(Rpt100[i] * 10.0);
  540. ALGO_Temperature_ATY_Test_Out[idx++] = out_pt100;
  541. ALGO_Temperature_ATY_Test_Out[idx++] = out_pt1000;
  542. if(__aty_close(out_pt100, tv[i], 0.1)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  543. if(__aty_close(out_pt1000, tv[i], 0.1)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  544. printf_ATY_D("\r\n[RTD NEWTON] TargetT = %fC, R(PT100) = %f Ohm, OutT(PT100) = %fC, %s\r\n", tv[i], Rpt100[i], out_pt100, (__aty_close(out_pt100, tv[i], 0.1) ? "PASS" : "FAIL"));
  545. printf_ATY_D(" R(PT1000) = %f Ohm, OutT(PT1000) = %fC, %s\r\n", Rpt100[i] * 10.0, out_pt1000, (__aty_close(out_pt1000, tv[i], 0.1) ? "PASS" : "FAIL"));
  546. }
  547. }
  548. {
  549. // [44..48] Thermocouple Type-T roundtrip: Out[i] == temps[-100, 0, 25, 300, 400] (+-1C)
  550. double tv[5] = {-100.0, 0.0, 25.0, 300.0, 400.0};
  551. for(int i = 0; i < 5; i++){
  552. double v = ALGO_Temp_TC_TempToVol('T', tv[i]);
  553. double out = ALGO_Temp_TC_VolToTemp('T', v);
  554. ALGO_Temperature_ATY_Test_Out[idx++] = out;
  555. if(__aty_close(out, tv[i], 0.1)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  556. printf_ATY_D("\r\n[TC-T Roundtrip] TargetT = %fC, CalcV = %f mV, OutT = %fC, %s\r\n", tv[i], v, out, (__aty_close(out, tv[i], 0.1) ? "PASS" : "FAIL"));
  557. }
  558. }
  559. {
  560. // [49..53] Table NTC R->T endpoints: equals tNTC[-40, 0, 25, 100, 150]
  561. double tNTC[5] = {-40.0, 0.0, 25.0, 100.0, 150.0};
  562. double rNTC[5] = {401.8597, 33.6206, 10.0, 0.6975, 0.19968};
  563. for(int i = 0; i < 5; i++){
  564. double out = ALGO_RT_Table_R2T(rNTC[i], tNTC, rNTC, 5);
  565. ALGO_Temperature_ATY_Test_Out[idx++] = out;
  566. if(__aty_close(out, tNTC[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  567. printf_ATY_D("\r\n[Table NTC R->T] R = %f => T = %fC, %s\r\n", rNTC[i], out, (__aty_close(out, tNTC[i], 0.01) ? "PASS" : "FAIL"));
  568. }
  569. // [54..55] Table NTC R->T out-of-range: -273.15 (below/above bounds)
  570. double out_low = ALGO_RT_Table_R2T(rNTC[4] * 0.5, tNTC, rNTC, 5);
  571. double out_high = ALGO_RT_Table_R2T(rNTC[0] * 2.0, tNTC, rNTC, 5);
  572. ALGO_Temperature_ATY_Test_Out[idx++] = out_low;
  573. ALGO_Temperature_ATY_Test_Out[idx++] = out_high;
  574. if(__aty_close(out_low, -273.15, 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  575. if(__aty_close(out_high, -273.15, 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  576. printf_ATY_D(" OOR Low: R = %f => T = %fC, %s\r\n", rNTC[4] * 0.5, out_low, (__aty_close(out_low, -273.15, 0.01) ? "PASS" : "FAIL"));
  577. printf_ATY_D(" OOR High: R = %f => T = %fC, %s\r\n", rNTC[0] * 2.0, out_high, (__aty_close(out_high, -273.15, 0.01) ? "PASS" : "FAIL"));
  578. // [56..60] Table NTC T->R endpoints: equals rNTC{401.8597, 33.6206, 10.0, 0.6975, 0.19968} at tNTC[-40, 0, 25, 100, 150]
  579. for(int i = 0; i < 5; i++){
  580. double outR = ALGO_RT_Table_T2R(tNTC[i], tNTC, rNTC, 5);
  581. ALGO_Temperature_ATY_Test_Out[idx++] = outR;
  582. if(__aty_close(outR, rNTC[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  583. printf_ATY_D("\r\n[Table NTC T->R] T = %fC => R = %f, %s\r\n", tNTC[i], outR, (__aty_close(outR, rNTC[i], 0.01) ? "PASS" : "FAIL"));
  584. }
  585. // [61..62] Table NTC T->R out-of-range: 0.0 (below/above bounds)
  586. double outTlow = ALGO_RT_Table_T2R(tNTC[0] - 10.0, tNTC, rNTC, 5);
  587. double outThigh = ALGO_RT_Table_T2R(tNTC[4] + 10.0, tNTC, rNTC, 5);
  588. ALGO_Temperature_ATY_Test_Out[idx++] = outTlow;
  589. ALGO_Temperature_ATY_Test_Out[idx++] = outThigh;
  590. if(__aty_close(outTlow, 0.0, 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  591. if(__aty_close(outThigh, 0.0, 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  592. printf_ATY_D(" OOR Low: T = %fC => R = %f, %s\r\n", tNTC[0] - 10.0, outTlow, (__aty_close(outTlow, 0.0, 0.01) ? "PASS" : "FAIL"));
  593. printf_ATY_D(" OOR High: T = %fC => R = %f, %s\r\n", tNTC[4] + 10.0, outThigh, (__aty_close(outThigh, 0.0, 0.01) ? "PASS" : "FAIL"));
  594. // [63..67] Table RTD R->T endpoints: equals tRTD[-40, 0, 25, 100]
  595. // [68..72] Table RTD T->R endpoints: equals rRTD at tRTD[-40, 0, 25, 100]
  596. double tRTD[5] = {-40.0, 0.0, 25.0, 100.0, 850.0};
  597. // double rRTD[5] = {84.272, 100.0, 109.740, 138.506, 390.481};
  598. double rRTD[4];
  599. for(int i = 0; i < 5; i++) rRTD[i] = ALGO_Temp_RTD_T(tRTD[i]);
  600. for(int i = 0; i < 5; i++){
  601. double o1 = ALGO_RT_Table_R2T(rRTD[i], tRTD, rRTD, 5);
  602. ALGO_Temperature_ATY_Test_Out[idx++] = o1;
  603. if(__aty_close(o1, tRTD[i], 0.01)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  604. printf_ATY_D("\r\n[Table RTD R->T] R = %f => T = %fC, %s\r\n", rRTD[i], o1, (__aty_close(o1, tRTD[i], 0.01) ? "PASS" : "FAIL"));
  605. }
  606. for(int i = 0; i < 5; i++){
  607. double o2 = ALGO_RT_Table_T2R(tRTD[i], tRTD, rRTD, 5);
  608. ALGO_Temperature_ATY_Test_Out[idx++] = o2;
  609. if(__aty_close(o2, rRTD[i], 0.02)) ALGO_Temperature_ATY_Test_Pass++; else ALGO_Temperature_ATY_Test_Fail++;
  610. printf_ATY_D(" [Table RTD T->R] T = %fC => R = %f, %s\r\n", tRTD[i], o2, (__aty_close(o2, rRTD[i], 0.02) ? "PASS" : "FAIL"));
  611. }
  612. }
  613. printf_ATY_D("\r\n[ALGO_Temperature_ATY_Test] END: Pass = %d, Fail = %d\r\n", ALGO_Temperature_ATY_Test_Pass, ALGO_Temperature_ATY_Test_Fail);
  614. return ALGO_Temperature_ATY_Test_Fail;
  615. }
  616. #endif /* ALGO_Temperature_ATY_Test_ATY */
  617. /************************************ etc *************************************/
  618. // T ---------------------------------------------------------------------------
  619. // #include "ALGO_Temperature_ATY.h"
  620. // void TempGet(void){
  621. // float MCU_BASE_VOL_D = 1200;//VREFINT_MCU_ATY;
  622. // float BOARD_TEMP = ALGO_VolToKelvinTemp((1000.0 *
  623. // ADC_Get(&hadc1, ADC_CHANNEL_5) / MCU_BASE_VOL_D),
  624. // 3300.0, 10.0, 10.0, 3950, 1);
  625. // printf_ATY_D("\r\nT: %f\r\n", BOARD_TEMP);
  626. // }
  627. #endif /* __ALGO_Temperature_ATY_C */
  628. /******************************** End Of File *********************************/