Melexis MLX90620 and MLX90621, non-contact, 16x4 infrared array temperature sensor device driver.

Dependents:   KL25Z_MLX90620

MLX90620.cpp

Committer:
loopsva
Date:
2016-07-26
Revision:
2:82782c73251e
Parent:
1:fd536ebc7eaf

File content as of revision 2:82782c73251e:

//NOTE:  "Step Measurement Mode" was removed from new MLX90620 data sheet, page 22 dated Sept 19 2012
//       which is used in this implementation

#include "mbed.h"
#include "MLX90620.h"

//for debugging purposes (uncomment)
//#define MLXTEST_621b         1

//--------------------------------------------------------------------------------------------------------------------------------------//
// Original Constructor

MLX9062x::MLX9062x(PinName sda, PinName scl, const char* name) : _i2c(sda, scl){
    _i2c.frequency(400000);                             //set up i2c speed
    _i2c.stop();                                        //initialize with a stop
    mlxDev = mlx90620;                                  //default device is MLX90620
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Additional Constructor for selecting the MLX device

MLX9062x::MLX9062x(PinName sda, PinName scl, MLXdevice MLXtype, const char* name) : _i2c(sda, scl){
    _i2c.frequency(400000);                             //set up i2c speed
    _i2c.stop();                                        //initialize with a stop
    mlxDev = MLXtype;                                   //user select device 620 or 621
}
   
//--------------------------------------------------------------------------------------------------------------------------------------//
//copy contents of EEPROM inside the MLX9062x into a local buffer.  Data is used for lookup tables and parameters

#define MLX_EEP_EASY_LOAD        1

int MLX9062x::LoadEEPROM(mlx_struct& Pntr) {
    Pntr.mlx621IDhi = 0;
    Pntr.mlx621IDlo = 0;
    Pntr.mlxDevice = mlxDev;                                    //make strurcture device same as local device
    
    //clear out buffer first
    for(int i = 0; i < 256; i++) Pntr.MLXEEbuf[i] = 0;  //clear out entire EEMPROM buffer

//the following code addition of a 1 byte I2C fetch is due to a bug in the F746NG which can only transfer 255 bytes at a time.  grrr!!!....
#if defined(TARGET_DISCO_F746NG)
#warning "TARGET_DISCO_F746NG i2c bug, 255 byte limit!!!"
    Pntr.MLXEEbuf[0] = 255;
    if(!_i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true)) {
        _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 1, false);
        Pntr.MLXEEbuf[255] = Pntr.MLXEEbuf[0];
        Pntr.MLXEEbuf[0] = 0;
        _i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true);
        _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 255, false); //s/b 256 if F746NG bug wasn't there
#else
    if(!_i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true)) {      //send command, 0 returned is ok
        _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 256, false);
#endif

    } else {
        _i2c.stop();                                    //don't read EEP if write is broken
        return(1);                                      //return with error
    }
    if(Pntr.mlxDevice == mlx90621) {
        Pntr.mlx621IDhi = (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 7] << 24) | (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 6] << 16) | 
                          (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 5] <<  8) |  Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 4];
        Pntr.mlx621IDlo = (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 3] << 24) | (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 2] << 16) | 
                          (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 1] <<  8) |  Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 0];
    }
    return(0);                                          //return with ok
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//copy oscillator offset from MLXEEbuf to MLX9062x (MS byte on 620 always = 0)

int MLX9062x::SetOscTrimReg(mlx_struct& Pntr) {
    Pntr.MLXRamCmmd[0] = 4;                                     //command
    Pntr.MLXRamCmmd[1] = Pntr.MLXEEbuf[MLX620_EETRIM] - 0xaa;   //LS byte check
    Pntr.MLXRamCmmd[2] = Pntr.MLXEEbuf[MLX620_EETRIM];          //oscillator trim value
    Pntr.MLXRamCmmd[3] = 0x100 - 0xaa;                          //MS byte check
    Pntr.MLXRamCmmd[4] = 0;                                     //MS byte = 0
    int r = _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 5, false); //send command
    //printf("OscTrim-W: %02x %02x %02x %02x %02x\r\n", Pntr.MLXRamCmmd[0], Pntr.MLXRamCmmd[1], Pntr.MLXRamCmmd[2], Pntr.MLXRamCmmd[3], Pntr.MLXRamCmmd[4]);
    return(r);                                                  //return ok or error
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get oscillator offset register from MLX9062x

uint16_t MLX9062x::GetOscTrimReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX_TRIM;                              //address of register
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true);          //send command  
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2, false);          //get 16 bit register
    Pntr.OscTrim = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0]; //store register
    //printf("OscTrim-R: %02x %02x\r\n", Pntr.MLXRamCmmd[0], Pntr.MLXRamCmmd[1]);
    return(Pntr.OscTrim);                                       //return value
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//initialize the configuration register
//******* NOTE: Step measurement mode was removed from new data sheet dated   Sept 19 2012

int MLX9062x::SetConfigReg(mlx_struct& Pntr) {  
    Pntr.MLXRamCmmd[0] = 3;                                     //command 
    if(Pntr.mlxDevice == mlx90621) {
        Pntr.MLXRamCmmd[2] = Pntr.MLXEEbuf[MLX621_CONFIG_LO];   //LS byte
        Pntr.MLXRamCmmd[4] = Pntr.MLXEEbuf[MLX621_CONFIG_HI];   //MS byte
        //here you can manipulate the Config Register contents from the default EEPROM values of 0x463e
        Pntr.MLXRamCmmd[2] = (Pntr.MLXRamCmmd[2] & ~MLX621_CONF_ADC_MASK) | MLX621_CONF_ADC18;
        Pntr.MLXRamCmmd[4] = Pntr.MLXRamCmmd[4] | (MLX621_CONF_MD_1 >> 8);
        Pntr.MLXRamCmmd[1] = Pntr.MLXRamCmmd[2] - 0x55;         //LS byte check
        Pntr.MLXRamCmmd[3] = Pntr.MLXRamCmmd[4] - 0x55;         //MS byte check
    } else {
        Pntr.MLXRamCmmd[1] = 0x10c - 0x55;                      //LS byte check
        Pntr.MLXRamCmmd[2] = 0x0c;                              //LS config value, normal mode, 4Hz array  *******
        Pntr.MLXRamCmmd[3] = 0x5c - 0x55;                       //MS byte check
        Pntr.MLXRamCmmd[4] = 0x5c;                              //MS config value, 8Hz Ta, 400k i2c
    }
    int r = _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 5, false);
    //printf("Command-W: %02x %02x %02x %02x %02x\r\n", Pntr.MLXRamCmmd[0], Pntr.MLXRamCmmd[1], Pntr.MLXRamCmmd[2], Pntr.MLXRamCmmd[3], Pntr.MLXRamCmmd[4]);
    return(r);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get configuration register from MLX9062x

uint16_t MLX9062x::GetConfigReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX_CONFIG;                            //address of register
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true); 
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2);
    Pntr.Config = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
    return(Pntr.Config);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get PTAT register from MLX9062x

uint16_t MLX9062x::GetPTATReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX620_PTATSENS;                       //address of register
    if(Pntr.mlxDevice == mlx90621) Pntr.MLXRamCmmd[1] = MLX621_PTATSENS;
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true); 
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2);
    Pntr.PtatD = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
#ifdef MLXTEST_621b
    if(Pntr.mlxDevice == mlx90620) {
        Pntr.PtatD = 0x1ac0;
    } else {
        if(ConfigReg54 == 0) {
            Pntr.PtatD = 0x0cfb;
        } else
        if(ConfigReg54 == 1) {
            Pntr.PtatD = 0x19f7;
        } else
        if(ConfigReg54 == 2) {
            Pntr.PtatD = 0x33ef;
        } else
        if(ConfigReg54 == 3) {
            Pntr.PtatD = 0x67de;
        } else {
            Pntr.PtatD = 0;
        }
    }
#endif
    return(Pntr.PtatD);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get VCP / TGC register from MLX9062x

int16_t MLX9062x::GetTGCReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX620_TGCSENS;                        //address of register
    if(Pntr.mlxDevice == mlx90621) Pntr.MLXRamCmmd[1] = MLX621_TGCSENS;
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true);
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2); 
    int16_t VCP = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
#ifdef MLXTEST_621b
    VCP = 0xffdc;
#endif
    Pntr.VCP = VCP;
    return(VCP);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get RAM dump from MLX9062x

void MLX9062x::LoadMLXRam(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = 0;                                     //start address
    Pntr.MLXRamCmmd[2] = 1;                                     //address step
    Pntr.MLXRamCmmd[3] = 0x40;                                  //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true);
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamBuf, 0x80); 
    Pntr.PtatD = MLX9062x::GetPTATReg(Pntr);
    Pntr.VCP = MLX9062x::GetTGCReg(Pntr);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//start measurement MLX9062x

int MLX9062x::StartMeasurement(mlx_struct& Pntr) {  
    if(Pntr.mlxDevice == mlx90621)  return(0);                          //there is no start_meas in the 90621  
    Pntr.MLXRamCmmd[0] = 1;                                     //command
    Pntr.MLXRamCmmd[1] = 8;                                     //address of config register
    int r = _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 2, false);
    return(r);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Only a test to set up values in EEPROM and RAM buffers to debug math.
//Note: must be performed after reading the EEPROM and RAM data

void MLX9062x::DSSetup(mlx_struct& Pntr, int Pixel) {
#ifdef MLXTEST_621b
#warning "MLX90620 test mode B"
    if(Pntr.mlxDevice == mlx90620) {
        Pntr.MLXEEbuf[0xda] = 0x78;
        Pntr.MLXEEbuf[0xdb] = 0x1a;
        Pntr.MLXEEbuf[0xdc] = 0x33;
        Pntr.MLXEEbuf[0xdd] = 0x5b;
        Pntr.MLXEEbuf[0xde] = 0xcc;
        Pntr.MLXEEbuf[0xdf] = 0xed;
    } else {
        //7.3.2 for Ta Calculations
        Pntr.MLXEEbuf[0xda] = 0x20;
        Pntr.MLXEEbuf[0xdb] = 0x64;
        Pntr.MLXEEbuf[0xdc] = 0x89;
        Pntr.MLXEEbuf[0xdd] = 0x55;
        Pntr.MLXEEbuf[0xde] = 0x7e;
        Pntr.MLXEEbuf[0xdf] = 0x5e;
        Pntr.MLXEEbuf[0xd2] = 0x8b;
        
        //7.3.4 for To Calculations (pixel 11)
        Pntr.MLXEEbuf[0x00 + Pixel] = 0x21;
        Pntr.MLXEEbuf[0x40 + Pixel] = 0xbc;
        Pntr.MLXEEbuf[0x80 + Pixel] = 0xcd;
        
        Pntr.MLXEEbuf[0xc0] = 0x99;
        Pntr.MLXEEbuf[0xc4] = 0x9e;
        
        Pntr.MLXEEbuf[0xd0] = 0x8a;
        Pntr.MLXEEbuf[0xd1] = 0xff;
    
        Pntr.MLXEEbuf[0xd3] = 0x9d;
        Pntr.MLXEEbuf[0xd4] = 0xff;
        Pntr.MLXEEbuf[0xd5] = 0xa2;
        Pntr.MLXEEbuf[0xd6] = 0xa8;
        Pntr.MLXEEbuf[0xd7] = 0x0f;
        Pntr.MLXEEbuf[0xd8] = 0x18;
        Pntr.MLXEEbuf[0xd9] = 0x07;
        
        Pntr.MLXEEbuf[0xe0] = 0xae;
        Pntr.MLXEEbuf[0xe1] = 0x4e;
        Pntr.MLXEEbuf[0xe2] = 0x26;
        Pntr.MLXEEbuf[0xe3] = 0x1f;
        Pntr.MLXEEbuf[0xe4] = 0x00;
        Pntr.MLXEEbuf[0xe5] = 0x80;
        Pntr.MLXEEbuf[0xe6] = 0x0c;
        Pntr.MLXEEbuf[0xe7] = 0x02;
        
        VirPix = 0x01b7;
    }
#endif
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Initial Calculations for Ta and To

//#define MLXTEST_621         1

double MLX9062x::GetDieTemp(mlx_struct& Pntr) {
    Pntr.PtatD = MLX9062x::GetPTATReg(Pntr);

    //Note: There seems to be a scaling error in the following routine
    //MLX621_CONF_ADC18 = +26.891C
    //MLX621_CONF_ADC17 = +25.934C
    //MLX621_CONF_ADC16 = +25.467C
    //MLX621_CONF_ADC15 = +25.187C

    double TaX = (-Kt1_f + sqrt(pow(Kt1_f, 2.0) - 4.0 * Kt2_f * (((Vth25 - (double)Pntr.PtatD)/ScaleCR54))))/(2.0 * Kt2_f) + 25.0;
    Pntr.DieTemp = TaX;
    return(TaX);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Display internal PIXEL registers for debugging math

void MLX9062x::DumpPixRegs(mlx_struct& Pntr, int Pixel) {
#ifdef MLXTEST_621b
    if(Pntr.mlxDevice == mlx90620) {
    /*
        printf("\r\n\r\npixel = %d\r\n", Pixel);
        printf("Acp   = %d\r\nBcp   = %d\r\nBiS   = %d\r\n", AcpX, BcpX, BiScaleX);
        printf("Vcp   = %d\r\neps   = %d\r\nTGC   = %d\r\n", VCP, elipsonX, TGCX);
        printf("Vcp_off_comp             = %f\r\n", Vcp_off_comp);
        printf("VirPix_off_comp        = %f\r\n", VirPix_off_comp);
        printf("VirPix                 = %d\r\n", VirPix);
        printf("AiPix                  = %d\r\n", AiPix);
        printf("BiPix                  = %d\r\n", BiPix);
        printf("BiScale                  = %d\r\n", BiScaleX);
        printf("2^BiScale                = %f\r\n", (powf(2.0,BiScaleX)));
        printf("1 << BiScale             = %d\r\n", (1 << BiScaleX));
        printf("Ta-25.0                  = %f\r\n", (Ta - 25.0f));
        printf("BiPix/2^BiScale          = %f\r\n", (BiPix / powf(2.0,BiScaleX)));
        printf("AiP+BiP/2^BiScale)*(Ta-25= %f\r\n", (AiPix + BiPix / powf(2.0,BiScaleX) * (Ta - 25.0f)));
        printf("VirPix_off_comp again  = %f\r\n", (VirPix - (AiPix + BiPix / powf(2.0,BiScaleX) * (Ta - 25.0f))));
        printf("VirPix_off_comp2 step  = %f\r\n", VirPix_off_comp2);
        printf("VirPix_tgc_comp        = %f\r\n", VirPix_tgc_comp);
        printf("elipsonf                 = %f\r\n", elipsonf);
        printf("VirPix_comp            = %f\r\n", VirPix_comp);
        printf("theta28                  = %f  << double print problem\r\n", (theta28 * 100000000.0));  //<<< can't print a double
        printf("TempPxl                  = %f\r\n",  TempPxl);
*/
    
    } else {
        printf("Pixel,%2d\r\n", Pixel);
    
        //DSSetup(Pntr, Pixel);
        printf("VirPix,%d,%x\r\n", VirPix, VirPix);
        printf("VCP,%d\r\n", Pntr.VCP);
        printf("Ta,%.3f\r\n\r\n", Ta);
        
        printf("Acommon_mod,%d\r\n", Acommon);
        printf("AiPix,%d\r\n", AiPix);
        printf("Ai_ij_f,%.16f\r\n", Ai_ij); 
        printf("BiPix_mod,%d\r\n", BiPix);
        printf("Bi_ij_f,%.16f\r\n", Bi_ij);
        printf("VirOffComp,%.16f\r\n", VirOffComp);
        printf("ACP_ee_mod,%d\r\n", ACP_ee); 
        int8_t bCPx = Pntr.MLXEEbuf[MLX621_BCP];
        if(bCPx > 127) bCPx -= 256;
        printf("bCP_ee_mod,%d\r\n", bCPx);
        printf("bCP,%.16f\r\n", bCP);
        printf("VcpCPOffComp,%.16f\r\n", VcpCPOffComp);
        printf("TempTCG_mod,%d\r\n\r\n", TempTCG);
        
        printf("Tgc621 mod,%.16f\r\n", Tgc621);
        printf("Emiss mod,%d\r\n", Emiss); 
        printf("VirTGCComp,%.16f\r\n", VirTGCComp);
        printf("VirComp,%.16f\r\n", VirComp);
    
        printf("KsTa,%d\r\n", KsTa);
        printf("KsTaF,%.16f\r\n", KsTaF);
        printf("ThPix,%.16f\r\n", ThPix);
        printf("ThetaCP,%.16f\r\n", ThetaCP);
        printf("ThetaCompPix,%.16f\r\n", ThetaCompPix);
        
        printf("Ks4_ee,%d\r\n", Ks4_ee);
        printf("Ks4_scale,%d,%x\r\n", Pntr.MLXEEbuf[MLX621_KS_SCALE], Pntr.MLXEEbuf[MLX621_KS_SCALE]);
        printf("Ks4,%.16f\r\n", Ks4);
        printf("TaK4,%.2f\r\n", TaK4);
        printf("Sx,%.16f\r\n", Sx);
    /*
        
        printf("BiPix,%d,%x\r\n", Pntr.MLXEEbuf[Pixel + 0x40], Pntr.MLXEEbuf[Pixel + 0x40]);
        printf("d_Th_Pix,%d,%x\r\n", d_Th_Pix, d_Th_Pix);
        
        //printf("VirOff_(Ta - 25.0f),%.16f\r\n", (Ta - 25.0f));
        //printf("VirOff_Bi_ij * (Ta - 25.0f),%.16f\r\n", Bi_ij * (Ta - 25.0f));
        //printf("VirOff_(Ai_ij + Bi_ij * (Ta - 25.0f)),%.16f\r\n", (Ai_ij + Bi_ij * (Ta - 25.0f)));
        
        printf("VircpTgcComp,%.16f\r\n", VircpTgcComp);
        printf("VirTGCComp,%.16f\r\n", VirTGCComp);
        printf("DELTA_TH_SCALE,%d,%.0f\r\n", Pntr.MLXEEbuf[MLX621_DELTA_TH_SCALE], (double) powf(2.0,Pntr.MLXEEbuf[MLX621_DELTA_TH_SCALE]));
        printf("THETA0_SCALE,%d,%.0f\r\n", Pntr.MLXEEbuf[MLX621_THETA0_SCALE], (double) powf(2.0,Pntr.MLXEEbuf[MLX621_THETA0_SCALE]));
        //printf("Alpha_ij_raw,%d,%04x\r\n", (Pntr.MLXEEbuf[MLX621_THETA0_HI] << 8) + Pntr.MLXEEbuf[MLX621_THETA0_LO], (Pntr.MLXEEbuf[MLX621_THETA0_HI] << 8) + Pntr.MLXEEbuf[MLX621_THETA0_LO]);
        //printf("Alpha_ij_f,%.16f\r\n", Alpha_ij);
        //printf("VirNorm,%.16f\r\n", VirNorm);
        printf("VirComp,%.16f\r\n", VirComp);
        printf("TempPxl,%.16f\r\n", TempPxl);
            
        //printf("TempPxl_a,%.16f\r\n", powf((Ta + 273.15), 4.0));
        //printf("TempPxl_b,%.16f\r\n", log10((VirComp + powf((Ta + 273.15), 4.0)) / 4.0));
        //printf("TempPxl_c,%.16f\r\n", exp((log10((VirComp + powf((Ta + 273.15), 4.0)) / 4.0))));
        //printf("TempPxl_d,%.16f\r\n", powf((Ta + 273.15), 1.0));
        //printf("TempPxl_e,%.16f\r\n", Ta + 273.15);
        //printf("TempPxl_f,%.16f\r\n", Ta + 273.15);
        printf("Th_0  ,%.16f\r\n", (double)Th_0 / pow(2.0,(double)Th_0_sc));
        //printf("d_Th_Pix,%d,%x\r\n", d_Th_Pix, d_Th_Pix);
        //printf("d_Th_Pix_raw,%d,%3.20f\r\n", Pntr.MLXEEbuf[Pixel + 0x80], (double)Pntr.MLXEEbuf[Pixel + 0x80]);
        //printf("ThDeltaZ,%3.20f\r\n", (double)d_Th_Pix); // !!!!! coverting 205 to 34!!
        //d_Th_Pix = Pntr.MLXEEbuf[Pixel + 0x80];
        //printf("ThDelta1,%.16f\r\n", (double)d_Th_Pix); 
        //printf("ThDelta2,%.16f\r\n", (double)Th_0 / pow(2.0,(double)Th_0_sc));
        //printf("ThDelta3,%.16f\r\n", (double)d_Th_Pix / pow(2.0,(double)d_Th_sc));
        //printf("ThDelta4,%.16f\r\n", (double)Th_0 / pow(2.0,(double)Th_0_sc) + (double)d_Th_Pix / pow(2.0,(double)d_Th_sc));
        //printf("ThDelta5,%.16f\r\n", (double)d_Th_Pix / pow(2.0,(double)d_Th_sc));
            
        //ThPix = (((double)Th_0 / pow(2.0,(double)Th_0_sc) + ((double)d_Th_Pix / pow(2.0,(double)d_Th_sc)))) / ScaleCR54;
            
        printf("ThPix,%.16f\r\n", ThPix);
        printf("ThetaCP,%.16f\r\n", ThetaCP);
        printf("ThetaCompPix,%.16f\r\n", ThetaCompPix);
        //printf("SxGuts1,%.32f\r\n", pow(ThetaCompPix, 3.0));
        //printf("SxGuts2,%.32f\r\n", pow(ThetaCompPix, 3.0) * VirComp);
        //printf("SxGuts3,%.32f\r\n", pow(ThetaCompPix, 4.0));
        //printf("SxGuts4,%.32f\r\n", pow(ThetaCompPix, 4.0) * TaK4);
        //printf("SxGuts5,%.32f\r\n", pow(ThetaCompPix, 3.0) * VirComp + (pow(ThetaCompPix, 4.0) * TaK4));
        printf("SxGuts,%.32f\r\n", SxGuts);
        printf("Sx,%.16f\r\n", Sx);
*/
        printf("TempPxl,%.16f\r\n", TempPxl);
        printf("\r\n");
    }
#endif
}


//--------------------------------------------------------------------------------------------------------------------------------------//
// Display internal registers for debugging math
 
void MLX9062x::DumpRawRegs(mlx_struct& Pntr) {
#ifdef MLXTEST_621b
    if(Pntr.mlxDevice == mlx90620) {
        printf("\r\n\r\nMLX90620 Ta_T0 regs:\r\n");
        //printf("ConfigReg54     = %d\r\n", ConfigReg54);
        //printf("ScaleCR54        = %d\r\n", ScaleCR54);
        //printf("Ktbits          = %02x\r\n",Pntr.MLXEEbuf[MLX621_KT12_SCALE]);
        printf("Kt1,%d,%x\r\n", Kt1, Kt1);
        //printf("Kt1_0xd2        = %d\r\n", 1 << ((Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT1SCALE_BITS) >> 4));
        printf("Kt2,%d,%x\r\n", Kt2, Kt2);
        //printf("Kt2_0xd2        = %d  %x\r\n", 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
        //printf("Kt2_0xd2 2      = %d  %x\r\n", 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
        printf("Vth25,%d,%x\r\n", Vth25, Vth25);
        printf("Kt1_f,%f\r\n", Kt1_f);
        printf("Kt2_f,%f\r\n", Kt2_f);
        printf("Pntr.PtatD,%d,%x\r\n", Pntr.PtatD, Pntr.PtatD);
        printf("Ta,%f\r\n", Ta);
        //printf("Tak4            = %f\r\n", Tak4);
            
        //printf("MLX621_KS4_EE   = %d\r\n", Pntr.MLXEEbuf[MLX621_KS4_EE]);
        //printf("MLX621_KS_SCALE = %d\r\n", Pntr.MLXEEbuf[MLX621_KS_SCALE]);
        //printf("ks4             = %d\r\n", ks4);
        //printf("Acommon      = %d\r\n", Acommon);
        //printf("deltaAi621      = %d\r\n", deltaAi621);
        //printf("deltaAiScale621 = %d\r\n", deltaAiScale621);
        //printf("Ai_ij           = %d\r\n", Ai_ij);
            
        //printf("BiScale621      = %d\r\n", BiScale621);
        //printf("Bi_ijEEP        = %d **\r\n", Bi_ijEEP);
        //printf("Bi_ij           = %d\r\n", Bi_ij);
            
        //printf("ACP_ee       = %d **\r\n", ACP_ee);
        //printf("aCP         = %d\r\n", aCP);  //was 8 bit, now 16 
         
        //printf("Vth(25) = %6d 0x%x\nTa1     = %6d 0x%x\nTa2     = %6d 0x%x\n", Vth25, Vth25, Kt1, Kt1, Kt2, Kt2);
        //printf("Kt1_f   = %f\nKt2_f   = %f\nTa    = %f\n\n", Kt1_f, Kt2_f, Ta);
        //printf("Acp     = %6d 0x%x\nBcp     = %6d 0x%x\nThCP    = %6d 0x%x\n", AcpX, AcpX, BcpX, BcpX, thetaCPX, thetaCPX); 
        //printf("TGC     = %6d 0x%x\nBiS     = %6d 0x%x\nTh0     = %6d 0x%x\n", TGCX, TGCX, BiScaleX, BiScaleX, theta0X, theta0X);   
        //printf("T0s     = %6d 0x%x\nDts     = %6d 0x%x\nelip    = %6d 0x%x\n\n", theta0ScaleX, theta0ScaleX, deltaThetaScaleX, deltaThetaScaleX, elipsonX, elipsonX); 
    } else {
        printf("\r\n\r\nMLX90621 Ta_T0 regs:\r\n");
        printf("ConfigReg54,%d,%02x\r\n", (Pntr.Config & MLX621_RESOLUTION) >> 4, (Pntr.Config & MLX621_RESOLUTION) >> 4);
        printf("Pntr.PtatD,%d,%x\r\n", Pntr.PtatD, Pntr.PtatD);
        printf("Vth25 mod,%d,%x\r\n", Vth25, Vth25);
        printf("Kt1_f,%.16f\r\n", Kt1_f);
        printf("Kt2_f,%.16f\r\n", Kt2_f);
        printf("Ta,%.16f\r\n\r\n", Ta);
    
        printf("ScaleCR54,%d,%x\r\n", 1 << (3 - ((Pntr.Config & MLX621_RESOLUTION) >> 4)), 1 << (3 - ((Pntr.Config & MLX621_RESOLUTION) >> 4))); 
        printf("Ktbits,%02x\r\n",Pntr.MLXEEbuf[MLX621_KT12_SCALE]);
        printf("Kt1,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_KT1_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT1_LO], (Pntr.MLXEEbuf[MLX621_KT1_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT1_LO]); 
        printf("Kt1_0xd2,%d\r\n", 1 << ((Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT1SCALE_BITS) >> 4));      
        printf("Kt1 mod,%d,%x\r\n", Kt1, Kt1); 
        printf("Kt2,%d,%x\r\n", (int16_t)((Pntr.MLXEEbuf[MLX621_KT2_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT2_LO]), ((Pntr.MLXEEbuf[MLX621_KT2_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT2_LO])); 
        printf("Kt2_0xd2,%d,%x\r\n", 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
        printf("Kt2_0xd2_2,%d,%x\r\n", 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
        printf("Kt2 mod,%d,%x\r\n", Kt2, Kt2);
        printf("Vth25,%d,%x\r\n", (int16_t)(((Pntr.MLXEEbuf[MLX621_VTH25_HI] << 8) | Pntr.MLXEEbuf[MLX621_VTH25_LO])), (((Pntr.MLXEEbuf[MLX621_VTH25_HI] << 8) | Pntr.MLXEEbuf[MLX621_VTH25_LO]))); 
        printf("Kt1_f^2,%12f\r\n", pow(Kt1_f, 2.0));
        printf("Vth25-PtatD,%12f\r\n", (Vth25 - (double)Pntr.PtatD));
        printf("4*Kt2_f,%12f\r\n", 4.0 * Kt2_f);
        printf("4*Kt2_f*(Vth25 - Pntr.PtatD),%12f\r\n", 4.0 * Kt2_f * (Vth25 - (double)Pntr.PtatD));
        printf("TopBeforesqrt,%12f\r\n", -pow(Kt1_f, 2.0) - 4.0 * Kt2_f * (Vth25 - (double)Pntr.PtatD));
        printf("\r\n");
        
        printf("Acommon,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_A_COMMON_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_COMMON_LO], (Pntr.MLXEEbuf[MLX621_A_COMMON_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_COMMON_LO]); 
        printf("Acommon mod,%d,%x\r\n", Acommon, Acommon); 
        printf("Emiss,%d,%x\r\n", (uint16_t)((Pntr.MLXEEbuf[MLX621_A_EMMIS_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_EMMIS_LO]), ((Pntr.MLXEEbuf[MLX621_A_EMMIS_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_EMMIS_LO])); 
        printf("Emiss mod,%d,%x\r\n", Emiss, Emiss); 
        printf("ACP_ee,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_ACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ACP_LO], (Pntr.MLXEEbuf[MLX621_ACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ACP_LO]); 
        printf("ACP_ee mod,%d,%x\r\n", ACP_ee, ACP_ee); 
        printf("AlphaCP,%d,%x\r\n", (int16_t)((Pntr.MLXEEbuf[MLX621_ALPHACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ALPHACP_LO]), ((Pntr.MLXEEbuf[MLX621_ALPHACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ALPHACP_LO])); 
        printf("AlphaCP mod,%d,%x\r\n", AlphaCP, AlphaCP); 
        printf("aCP,%.16f\r\n", aCP);
        printf("AiScale621,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DAISCALE_BITS) >> 4, (Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DAISCALE_BITS) >> 4);
        printf("BiScale621,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DBISCALE_BITS), (Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DBISCALE_BITS));
        printf("bCP,%d,%x\r\n", (int8_t)Pntr.MLXEEbuf[MLX621_BCP], Pntr.MLXEEbuf[MLX621_BCP]);
        printf("bCP mod,%.16f\r\n", bCP);
            
        printf("TempTCG,%d,%x\r\n", (int8_t)Pntr.MLXEEbuf[MLX621_TGC], Pntr.MLXEEbuf[MLX621_TGC]);
        printf("TempTCG mod,%d,%x\r\n", TempTCG, TempTCG);
        printf("Tgc621 mod,%.16f\r\n", Tgc621);
        //printf("TGCReg,%d,%x\r\n", (int16_t)TGCReg, TGCReg);
        printf("VCP,%d,%x\r\n", (int16_t)Pntr.VCP, Pntr.VCP);
        printf("VcpCPOffComp,%.16f\r\n", VcpCPOffComp);
        printf("KsTa,%d,%x\r\n", (int16_t)KsTa, KsTa);
        printf("KsTaF,%.16f\r\n", KsTaF);
        printf("Ks4_ee,%d,%x\r\n", (int16_t)Ks4_ee, Ks4_ee);
        printf("Ks4_scale,%d,%x\r\n", Pntr.MLXEEbuf[MLX621_KS_SCALE], Pntr.MLXEEbuf[MLX621_KS_SCALE]);
        printf("Ks4,%.16f\r\n", Ks4);
        printf("TaK4,%.16f\r\n", TaK4);
        printf("Th_0,%d,%x\r\n", (int16_t)Th_0, Th_0);
        printf("Th_0_sc,%d,%x\r\n", (int16_t)Th_0_sc, Th_0_sc);
        printf("d_Th_sc,%d,%x\r\n", (int16_t)d_Th_sc, d_Th_sc);
        printf("\r\n");
    }
#endif
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Initial Calculations for Ta and To

void MLX9062x::CalcTa_To(mlx_struct& Pntr) {
#ifdef MLXTEST_621b
    DSSetup(Pntr, 11);
#endif
    if(Pntr.mlxDevice == mlx90620) {
        //Calculate Ta first
        Vth25 = (Pntr.MLXEEbuf[MLX_TAINDEX +  1] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX +  0];
        Kt1 = (Pntr.MLXEEbuf[MLX_TAINDEX +  3] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX +  2];
        Kt2 = (Pntr.MLXEEbuf[MLX_TAINDEX +  5] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX +  4];
        if(Vth25  > 32767) Vth25  -= 65536;  
        if(Kt1 > 32767) Kt1 -= 65536; 
        if(Kt2 > 32767) Kt2 -= 65536;
        
        Kt1_f = (double)Kt1 / 1024.0f;
        Kt2_f = (double)Kt2 / 1048576.0f;
        ScaleCR54 = 1;
        Ta = MLX9062x::GetDieTemp(Pntr);
        
        //Calculate To
        AcpX =              Pntr.MLXEEbuf[MLX621_A_COMMON_LO]; //[MLX_TOINDEX +  0];
        BcpX =              Pntr.MLXEEbuf[MLX621_A_COMMON_HI]; //[MLX_TOINDEX +  1];
        //uint16_t thetaCPX = (EEbuf[MLX_TOINDEX + 3] << 8) + MLXEEbuf[MLX_TOINDEX + 2];
        TGCX =              Pntr.MLXEEbuf[MLX_TGCX_REG]; //[MLX_TOINDEX +  4];
        BiScaleX =          Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE]; //[MLX_TOINDEX +  5];
        theta0X =          (Pntr.MLXEEbuf[MLX_THETA0_REG_HI] << 8) + Pntr.MLXEEbuf[MLX_THETA0_REG_LO]; //[MLX_TOINDEX + 13] << 8) + Pntr.MLXEEbuf[MLX_TOINDEX + 12];
        theta0ScaleX =      Pntr.MLXEEbuf[MLX_THETA0_SCALE_REG];  //[MLX_TOINDEX + 14];
        deltaThetaScaleX =  Pntr.MLXEEbuf[MLX_DELTA_TH_SCALE_REG];  //[MLX_TOINDEX + 15];
        elipsonX =         (Pntr.MLXEEbuf[MLX_EPSILON_REG_HI] << 8) + Pntr.MLXEEbuf[MLX_EPSILON_REG_LO];  //[MLX_TOINDEX + 17] << 8) + Pntr.MLXEEbuf[MLX_TOINDEX + 16];  
    } else {
        ConfigReg54 = (Pntr.Config & MLX621_RESOLUTION) >> 4;
        ScaleCR54 = 1 << (3 - ((Pntr.Config & MLX621_RESOLUTION) >> 4));  //1 << (3 - ConfigReg54);
        Kt1 = (int16_t)((Pntr.MLXEEbuf[MLX621_KT1_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT1_LO]);
        Kt2 = (int16_t)((Pntr.MLXEEbuf[MLX621_KT2_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT2_LO]);
        Vth25 = (int16_t)(((Pntr.MLXEEbuf[MLX621_VTH25_HI] << 8) | Pntr.MLXEEbuf[MLX621_VTH25_LO]));
           
#ifdef MLXTEST_621
#warning "MLX90620 test mode"
        //for testing only
        ConfigReg54 = 0;
        ScaleCR54 =  1 << (3 - ConfigReg54);
        Vth25  = 0x6420;
        Kt1    = 0x5589;
        Kt2    = 0x5e7e;
#endif

        if(Kt1 > 32767) Kt1 -= 65536; 
        if(Kt2 > 32767) Kt2 -= 65536;
        if(Vth25  > 32767) Vth25  -= 65536;  
        Vth25 /= ScaleCR54;
        Kt1_f = (double)Kt1 / ((1 << ((Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT1SCALE_BITS) >> 4)) * ScaleCR54);
        Kt2_f = (double)Kt2 / ((1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS)) * ScaleCR54);        
        Ta = MLX9062x::GetDieTemp(Pntr);
        //double Tak4 = pow(Ta + 273.15, 4.0);
        
        Acommon = (int16_t)(Pntr.MLXEEbuf[MLX621_A_COMMON_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_COMMON_LO];
        Emiss = (uint16_t)((Pntr.MLXEEbuf[MLX621_A_EMMIS_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_EMMIS_LO]) / 32768;
        ACP_ee = (int16_t)(Pntr.MLXEEbuf[MLX621_ACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ACP_LO];
        AlphaCP = (int16_t)((Pntr.MLXEEbuf[MLX621_ALPHACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ALPHACP_LO]) / ScaleCR54;
        
        if(Acommon > 32767) Acommon -= 65536; 
        //if(Emiss > 32767) Emiss -= 65536; 
        if(ACP_ee > 32767) ACP_ee -= 65536;
        aCP = (float)(ACP_ee / ScaleCR54);  
        AiScale621 = (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DAISCALE_BITS) >> 4;
        BiScale621 = (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DBISCALE_BITS);
        bCP = (float)Pntr.MLXEEbuf[MLX621_BCP];
        if(bCP > 127.0f) bCP -= 256.0f;
        bCP /= (pow(2.0f, (float)BiScale621) * (float)ScaleCR54);
        TempTCG = Pntr.MLXEEbuf[MLX621_TGC];
        if(TempTCG > 127) TempTCG -= 256;
        Tgc621 = (float)TempTCG / 32.0f;
        TGCReg = GetTGCReg(Pntr);
        if(Pntr.VCP > 32767) Pntr.VCP -= 65536;
        VcpCPOffComp = (double)Pntr.VCP - ((double)aCP + bCP * (Ta - 25.0));
        KsTa = (Pntr.MLXEEbuf[MLX621_KSTA_HI] << 8) + Pntr.MLXEEbuf[MLX621_KSTA_LO];
        if(KsTa > 32767) KsTa -= 65536;
        KsTaF = (double)KsTa / pow(2.0, 20);
        Ks4_ee =  Pntr.MLXEEbuf[MLX621_KS4_EE];
        if(Ks4_ee > 127) Ks4_ee -= 256;
        Ks4 = (double)Ks4_ee / pow(2.0, (double)((Pntr.MLXEEbuf[MLX621_KS_SCALE] & 15) + 8.0));
        TaK4 = pow((Ta + 273.15), 4.0);
        Th_0 = (Pntr.MLXEEbuf[MLX621_THETA0_HI] << 8) + Pntr.MLXEEbuf[MLX621_THETA0_LO];
        Th_0_sc = Pntr.MLXEEbuf[MLX621_THETA0_SCALE];
        d_Th_sc = Pntr.MLXEEbuf[MLX621_DELTA_TH_SCALE];
    }
    DumpRawRegs(Pntr);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Pixel Temperature Calculation

double MLX9062x::CalcPixel(mlx_struct& Pntr, int Pixel) {
    if(Pntr.mlxDevice == mlx90620) {
        AiPix = Pntr.MLXEEbuf[Pixel];                                        //eeprom address range 0x00 - 0x3f
        BiPix = Pntr.MLXEEbuf[Pixel + 0x40];                                 //eeprom address range 0x40 - 0x7f
        d_Th_Pix = Pntr.MLXEEbuf[Pixel + 0x80];                             //eeprom address range 0x08 - 0xbf
        VirPix = (Pntr.MLXRamBuf[Pixel * 2 + 1] << 8) + Pntr.MLXRamBuf[Pixel * 2];   //ram address range 0x000 - 0x08f, 16b
        float Vcp_off_comp = Pntr.VCP - (AcpX + BcpX / powf(2.0f,BiScaleX) * (Ta - 25.0f));
        float VirPix_off_comp = VirPix - (AiPix + BiPix / powf(2.0f,BiScaleX) * (Ta - 25.0f));
        float VirPix_off_comp2 = (float(AiPix) + float(BiPix) / float(1 << BiScaleX) * (Ta - 25.0f));
        VirPix_off_comp2 = VirPix - VirPix_off_comp2;
        float VirPix_tgc_comp = VirPix_off_comp - TGCX / 32.0 * Vcp_off_comp;
        float elipsonf = elipsonX / 32768.0;
        float VirPix_comp = VirPix_tgc_comp / elipsonf;
        double theta28 = theta0X / powf(2.0, theta0ScaleX) + d_Th_Pix / powf(2.0, deltaThetaScaleX);
        TempPxl = powf((VirPix_comp / theta28 + powf((Ta + 273.15f), 4.0f)), (1.0f / 4.0f)) - 273.15f;
    } else {
        AiPix = Pntr.MLXEEbuf[Pixel];                                       //eeprom address range 0x00 - 0x3f
        BiPix = Pntr.MLXEEbuf[Pixel + 0x40];                                //eeprom address range 0x40 - 0x7f
        d_Th_Pix = Pntr.MLXEEbuf[Pixel + 0x80];                             //eeprom address range 0x08 - 0xbf
        VirPix = (Pntr.MLXRamBuf[Pixel * 2 + 1] << 8) + Pntr.MLXRamBuf[Pixel * 2];   //ram address range 0x000 - 0x08f, 16b
#ifdef MLXTEST_621b
        VirPix = 0x01b7;
#endif 
        if(VirPix > 32767) VirPix -= 65536;       
        if(BiPix > 127) BiPix -= 256; 
        Ai_ij = (float)(Acommon + AiPix * pow(2.0, AiScale621)) / (float)ScaleCR54;
        Bi_ij = (float)BiPix / (float)((1 << BiScale621) * ScaleCR54);
        
        VirOffComp = (float)VirPix - (Ai_ij + Bi_ij * (Ta - 25.0f));
        VirTGCComp = VirOffComp - Tgc621 * VcpCPOffComp;
        VirComp = VirTGCComp / Emiss;
        
        ThPix = (((double)Th_0 / pow(2.0,(double)Th_0_sc) + ((double)d_Th_Pix / pow(2.0,(double)d_Th_sc)))) / ScaleCR54;
        ThetaCP = (double)AlphaCP / (pow(2.0, (double)Th_0_sc) * ScaleCR54);
        ThetaCompPix = (1.0 + KsTaF * (Ta - 25.0)) * (ThPix - Tgc621 * ThetaCP);
        SxGuts = pow(ThetaCompPix, 3.0) * VirComp + (pow(ThetaCompPix, 4.0) * TaK4);
        Sx = sqrt(SxGuts); 
        Sx = Ks4 * sqrt(Sx); 

        TempPxl = ThetaCompPix * (1.0 - (Ks4 * 273.15)) + Sx;
        TempPxl = (VirComp / TempPxl) + TaK4;
        TempPxl = sqrt(TempPxl);
        TempPxl = sqrt(TempPxl) - 273.15;
    }
    DumpPixRegs(Pntr, Pixel);
    return(TempPxl);
}