123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- /******************************************************************************
- * Additional info
- * ****************************************************************************
- * Changelog:
- * - v. 2.0 Optimize memory usage. Option to use binary search.
- * 2016-01-09 by Joakim Soderberg joakim.soderberg@gmail.com
- * - v. 1.0 Initial release)
- * 2014-04-24 by Albertas Mickėnas mic@wemakethings.net
- *
- * ****************************************************************************
- * Bugs, feedback, questions and modifications can be posted on the github page
- * on https://github.com/Miceuz/k-thermocouple-lib/
- * ****************************************************************************
- * - LICENSE -
- * GNU GPL v2 (http://www.gnu.org/licenses/gpl.txt)
- * This program is free software. You can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- * ****************************************************************************
- */
- #include <stdio.h>
- #include "thermocouple.h"
- #ifdef __AVR__
- #include <avr/pgmspace.h>
- #else
- #undef KTHERM_WITH_PROGMEM
- #endif
- #ifdef KTHERM_TEST
- #include <string.h>
- #endif
- /*
- * Values for this table should be multiplied with 1000 when used.
- * If we store the table as that instead, we need to use unsigned long
- * For example it would need (on an ATmega328):
- * 66 * 4 = 264 bytes
- * instead of:
- * 66 * 2 = 132 bytes
- */
- #define TEMP_TABLE_SCALE 1000
- static const signed int temp_tablek[]
- #ifdef KTHERM_WITH_PROGMEM
- PROGMEM
- #endif
- = {
- -250,
- -240,
- -230,
- -220,
- -210,
- -200,
- -190,
- -180,
- -170,
- -160,
- -150,
- -140,
- -130,
- -120,
- -110,
- -100,
- -90,
- -80,
- -70,
- -60,
- -50,
- -40,
- -30,
- -20,
- -10,
- 0,
- 10,
- 20,
- 30,
- 40,
- 50,
- 60,
- 79,
- 98,
- 116,
- 134,
- 139,
- 155,
- 172,
- 193,
- 212,
- 231,
- 250,
- 269,
- 288,
- 307,
- 326,
- 345,
- 364,
- 383,
- 402,
- 421,
- 440,
- 459,
- 478,
- 497,
- 516,
- 535,
- 554,
- 573,
- 592,
- 611,
- 630,
- 649,
- 668,
- 687,
- 706,
- 725,
- 744,
- 763,
- 782,
- 801,
- 820,
- 839,
- 858,
- 877,
- 896,
- 915,
- 934,
- 953,
- 972,
- 991,
- 1010,
- 1029,
- 1048,
- 1067,
- 1086,
- 1105,
- 1124,
- 1143,
- 1200
- };
- #define TEMP_TABLE_SIZEK (sizeof(temp_table) / sizeof(temp_table[0]))
- static const signed int volt_tablek[]
- #ifdef KTHERM_WITH_PROGMEM
- PROGMEM
- #endif
- = {
- -6404,
- -6344,
- -6262,
- -6158,
- -6035,
- -5891,
- -5730,
- -5550,
- -5354,
- -5141,
- -4913,
- -4669,
- -4411,
- -4138,
- -3852,
- -3554,
- -3243,
- -2920,
- -2587,
- -2243,
- -1889,
- -1527,
- -1156,
- -778,
- -392,
- 0,
- 397,
- 798,
- 1203,
- 1612,
- 2023,
- 2436,
- 3225,
- 4013,
- 4756,
- 5491,
- 5694,
- 6339,
- 7021,
- 7859,
- 8619,
- 9383,
- 10153,
- 10930,
- 11712,
- 12499,
- 13290,
- 14084,
- 14881,
- 15680,
- 16482,
- 17285,
- 18091,
- 18898,
- 19707,
- 20516,
- 21326,
- 22137,
- 22947,
- 23757,
- 24565,
- 25373,
- 26179,
- 26983,
- 27784,
- 28584,
- 29380,
- 30174,
- 30964,
- 31752,
- 32536,
- 33316,
- 34093,
- 34867,
- 35637,
- 36403,
- 37166,
- 37925,
- 38680,
- 39432,
- 40180,
- 40924,
- 41665,
- 42402,
- 43134,
- 43863,
- 44588,
- 45308,
- 46024,
- 46735,
- 48838
- };
- //T
- static const signed int temp_tablet[]
- #ifdef KTHERM_WITH_PROGMEM
- PROGMEM
- #endif
- = {
- -250,
- -240,
- -230,
- -220,
- -210,
- -200,
- -190,
- -180,
- -170,
- -160,
- -150,
- -140,
- -130,
- -120,
- -110,
- -100,
- -90,
- -80,
- -70,
- -60,
- -50,
- -40,
- -30,
- -20,
- -10,
- 0,
- 10,
- 20,
- 30,
- 40,
- 50,
- 60,
- 79,
- 98,
- 116,
- 134,
- 139,
- 155,
- 172,
- 193,
- 212,
- 231,
- 250,
- 269,
- 288,
- 307,
- 326,
- 345,
- 364,
- 383,
- 400
- };
- #define TEMP_TABLE_SIZET (sizeof(temp_tablet) / sizeof(temp_tablet[0]))
- static const signed int volt_tablet[]
- #ifdef KTHERM_WITH_PROGMEM
- PROGMEM
- #endif
- = {
- -6180,
- -6105,
- -6007,
- -5888,
- -5753,
- -5603,
- -5439,
- -5261,
- -5070,
- -4865,
- -4648,
- -4419,
- -4177,
- -3923,
- -3657,
- -3379,
- -3089,
- -2788,
- -2476,
- -2153,
- -1819,
- -1475,
- -1121,
- -757,
- -383,
- 0,
- 391,
- 790,
- 1196,
- 1612,
- 2036,
- 2468,
- 3312,
- 4185,
- 5036,
- 5491,
- 5910,
- 6956,
- 7823,
- 8917,
- 9930,
- 10962,
- 12013,
- 13082,
- 14168,
- 15270,
- 16387,
- 17518,
- 18665,
- 19825,
- 20872
- };
- #define VOLTAGE_TABLE_SIZEK (sizeof(volt_tablek) / sizeof(volt_tablek[0]))
- #define VOLTAGE_TABLE_SIZET (sizeof(volt_tablet) / sizeof(volt_tablet[0]))
- #define POINTS_COUNTK (VOLTAGE_TABLE_SIZEK - 1)
- #define POINTS_COUNTT (VOLTAGE_TABLE_SIZET - 1)
- static inline signed long getTableVal(const signed int *t,
- unsigned char i)
- {
- #ifdef KTHERM_WITH_PROGMEM
- return (unsigned long)pgm_read_word_near(t + i);
- #else
- return (signed long)t[i];
- #endif
- }
- static inline signed long interpolate(signed long val,
- signed long rangeStart,
- signed long rangeEnd,
- signed long valStart,
- signed long valEnd)
- {
- signed long valDiff = valEnd - valStart;
- if (valDiff == 0)
- return 0;
- return rangeStart + (rangeEnd - rangeStart) * (val - valStart) / valDiff;
- }
- static inline signed long interpolateVoltagek(signed long temp,
- signed char i)
- {
- return interpolate(temp,
- getTableVal(volt_tablek, i - 1),
- getTableVal(volt_tablek, i),
- getTableVal(temp_tablek, i - 1) * TEMP_TABLE_SCALE,
- getTableVal(temp_tablek, i) * TEMP_TABLE_SCALE);
- }
- static inline signed long interpolateVoltaget(signed long temp,
- signed char i)
- {
- return interpolate(temp,
- getTableVal(volt_tablet, i - 1),
- getTableVal(volt_tablet, i),
- getTableVal(temp_tablet, i - 1) * TEMP_TABLE_SCALE,
- getTableVal(temp_tablet, i) * TEMP_TABLE_SCALE);
- }
- static inline signed long interpolateTemperaturek(signed long microvolts,
- signed char i)
- {
- return interpolate(microvolts,
- getTableVal(temp_tablek, i - 1) * TEMP_TABLE_SCALE,
- getTableVal(temp_tablek, i) * TEMP_TABLE_SCALE,
- getTableVal(volt_tablek, i - 1),
- getTableVal(volt_tablek, i));
- }
- static inline signed long interpolateTemperaturet(signed long microvolts,
- signed char i)
- {
- return interpolate(microvolts,
- getTableVal(temp_tablet, i - 1) * TEMP_TABLE_SCALE,
- getTableVal(temp_tablet, i) * TEMP_TABLE_SCALE,
- getTableVal(volt_tablet, i - 1),
- getTableVal(volt_tablet, i));
- }
- static inline unsigned char binarySearchK(const signed int *t,
- signed long val,
- signed long scale)
- {
- unsigned char first;
- unsigned char middle;
- unsigned char last;
- unsigned long cur;
- // Note that we skip the first item in the list.
- first = 1;
- last = POINTS_COUNTK - 2;
- middle = (first + last) / 2;
- while (first <= last)
- {
- cur = getTableVal(t, middle) * scale;
- if (val > cur)
- {
- first = middle + 1;
- }
- else if (val == cur)
- {
- return middle + 1;
- }
- else
- {
- last = middle - 1;
- }
- middle = (first + last) / 2;
- }
- return last + 1;
- }
- static inline unsigned char binarySearchT(const signed int *t,
- signed long val,
- signed long scale)
- {
- unsigned char first;
- unsigned char middle;
- unsigned char last;
- unsigned long cur;
- // Note that we skip the first item in the list.
- first = 1;
- last = POINTS_COUNTT - 2;
- middle = (first + last) / 2;
- while (first <= last)
- {
- cur = getTableVal(t, middle) * scale;
- if (val > cur)
- {
- first = middle + 1;
- }
- else if (val == cur)
- {
- return middle + 1;
- }
- else
- {
- last = middle - 1;
- }
- middle = (first + last) / 2;
- }
- return last + 1;
- }
- static inline unsigned char linearSearchK(const signed int *t,
- signed long val,
- signed long scale)
- {
- unsigned char i;
- for (i = 0; i < POINTS_COUNTK; i++)
- {
- if ((getTableVal(t, i) * scale) > val)
- {
- return i;
- }
- }
- return POINTS_COUNTK - 1;
- }
- static inline unsigned char linearSearchT(const signed int *t,
- signed long val,
- signed long scale)
- {
- unsigned char i;
- for (i = 0; i < POINTS_COUNTT; i++)
- {
- if ((getTableVal(t, i) * scale) > val)
- {
- return i;
- }
- }
- return POINTS_COUNTT - 1;
- }
- /**
- * Returns the index of the first point whose temperature
- * value is greater than argument
- **/
- static inline unsigned char searchTempk(signed long temp)
- {
- #ifdef KTHERM_WITH_BINARY_SEARCH
- return binarySearch(temp_table, temp, TEMP_TABLE_SCALE);
- #else
- return linearSearchK(temp_tablek, temp, TEMP_TABLE_SCALE);
- #endif
- }
- static inline unsigned char searchTempt(signed long temp)
- {
- #ifdef KTHERM_WITH_BINARY_SEARCH
- return binarySearch(temp_table, temp, TEMP_TABLE_SCALE);
- #else
- return linearSearchT(temp_tablet, temp, TEMP_TABLE_SCALE);
- #endif
- }
- /**
- * Returns the index of the first point whose microvolts
- * value is greater than argument
- **/
- static inline unsigned char searchMicrovoltsk(signed long microvolts)
- {
- #ifdef KTHERM_WITH_BINARY_SEARCH
- return binarySearch(volt_table, microvolts, 1);
- #else
- return linearSearchK(volt_tablek, microvolts, 1);
- #endif
- }
- static inline unsigned char searchMicrovoltst(signed long microvolts)
- {
- #ifdef KTHERM_WITH_BINARY_SEARCH
- return binarySearch(volt_table, microvolts, 1);
- #else
- return linearSearchT(volt_tablet, microvolts, 1);
- #endif
- }
- /**
- * Returns temperature as a function of the ambient temperature
- * and measured thermocouple voltage.
- * Currently only positive ambient temperature is supported
- **/
- long thermocoupleConvertWithCJCompensationk(signed long microvoltsMeasured,
- signed long ambient)
- {
- // Convert ambient temp to microvolts
- // and add them to the thermocouple measured microvolts
- signed long microvolts =
- microvoltsMeasured + interpolateVoltagek(ambient, searchTempk(ambient));
- // look up microvolts in The Table and interpolate
- return interpolateTemperaturek(microvolts, searchMicrovoltsk(microvolts));
- }
- long thermocoupleConvertWithCJCompensationt(signed long microvoltsMeasured,
- signed long ambient)
- {
- // Convert ambient temp to microvolts
- // and add them to the thermocouple measured microvolts
- signed long microvolts =
- microvoltsMeasured + interpolateVoltaget(ambient, searchTempt(ambient));
- // look up microvolts in The Table and interpolate
- return interpolateTemperaturet(microvolts, searchMicrovoltst(microvolts));
- }
- /**
- * Returns temperature, equivalent to the voltage provided in microvolts
- */
- long thermocoupleMvToCk(signed long microvolts)
- {
- return interpolateTemperaturek(microvolts, searchMicrovoltsk(microvolts));
- }
- long thermocoupleMvToCt(signed long microvolts)
- {
- return interpolateTemperaturet(microvolts, searchMicrovoltst(microvolts));
- }
- #ifdef KTHERM_TEST
- int main(int argc, char **argv)
- {
- unsigned long i = 0;
- if (argc < 2)
- {
- goto usage;
- }
- for (i = 1; i < argc; i++)
- {
- if (!strcmp(argv[i], "--temps"))
- {
- for (i = 0; i < 16383; i++)
- {
- unsigned long voltage = 5000000 / 16384 * i / 101;
- printf("%ld\n", thermocoupleMvToC(voltage));
- }
- }
- else if (!strcmp(argv[i], "--microvolts"))
- {
- for (i = 0; i < 1280000; i+= 1000)
- {
- printf("%ld\n", interpolateVoltage(i, searchTemp(i)));
- }
- }
- else
- {
- fprintf(stderr, "Unknown option %s\n", argv[i]);
- goto usage;
- }
- }
- return 0;
- usage:
- printf("K-Type Thermocouple Library Tests\n");
- printf(" Usage: %s [--microvolts] [--temps]\n", argv[0]);
- return -1;
- }
- #endif
|