//#############################################################################
// ASL IPS Compute Ice Draft Routines
//
// (c) CopyRight ASL Environmental Sciences Inc. 1997-2001
//
//	File:			decodeIPS.c
//
//	Purpose:		Routine to decode IPS string into engineering units
//
//	Development:		National Instruments Labwindows/CVI 5.0 and higher
//					
//	Date:			March 20, 2001
//
// 	Programmer:		Dave Billenness
//
//  	Modified 		April 11, 2001 - Changed definitions of date to short ints
//				Changed to only one include file "IceDraft.h" "IceDraft_def.h
//				removed.
//				April 27, 2001 - Function to decode separated from main
//				function IceDraft.c
//
//******************************************************************************
//#include <ansi_c.h>
#include <stdio.h>
#include <math.h>
#include "IceDraft.h"
//******************************************************************************
//*																			
//*	DEFINE GLOBALS - THESE ARE IPS COEFFICIENTS SPECIFIC TO INSTRUMENT S/N IPS4025
//*  AND PAROS SENSOR #77158
//******************************************************************************

double		ECLOCK = 5.42479e-07;		// Measured IPS Eclock
double 		U0 = 5.833723;			// Temperature coefficient U0 in us
double		Y1 = -4011.829;			// Temperature coefficient Y1 in degC/us
double 		Y2 = -10737.57;			// Temperature coefficient Y2 in degC/us^2 
double 		Y3 = 0.;    			// Temperature coefficient Y3 in degC/us^3
double		C1 = 690.9645786999999; 	// Pressure coefficient C1 in db
double 		C2 = 9.005742459; 		// Pressure coefficient C2 in db/us
double 		C3 = -1179.43833;		// Pressure coefficient C3 in db/us^2
double 		D1 = 0.032802;   		// Pressure coefficient D1
double 		D2 = 0.;   			// Pressure coefficient D2
double		T1 = 27.72351;   		// Pressure coefficient T1 in us
double		T2 = 0.352424;   		// Pressure coefficient T2 in us/us
double		T3 = 17.39557;   		// Pressure coefficient T3 in us/us^2
double		T4 = 17.32600; 			// Pressure coefficient T4 in us/us^3
double		T5 = 0.;   			// Pressure coefficient T5 in us/us^4
double		X_A = 24.71783; 		// Tilt coefficient X_a
double		X_B = -0.20404; 		// Tilt coefficient X_b
double		X_C = 0.;   			// Tilt coefficient X_c
double		X_D = 0.;   			// Tilt coefficient X_d
double		Y_A = 25.16278;   		// Tilt coefficient Y_a
double		Y_B = -0.20465;   		// Tilt coefficient Y_b
double		Y_C = 0.;   			// Tilt coefficient Y_c
double		Y_D = 0.;   			// Tilt coefficient Y_d		  


//#############################################################################
// Section:  Ice Draft Programs
//
// Function: int decodeIPS(icedraft_t *Ice, char IPSString)
//
// Purpose:  decode IPS string into engineering units:
//			Ice - structure containing the decoded IPS values, ice draft etc. (see icedraft.h)
//			IPSString - string of ASCII characters containing raw IPS output string array
//
// returns: structure Ice containing decoded IPS data and int ErrorCode as defined in 
//			IceDraft_Def.h (>= 0 means successful, -3 = IPS string length is invalid)
//
//#############################################################################
int decodeIPS(icedraft_t *Ice, char IPSString[])
{
		int 			i = 0, j = 0;
		char 			DateStr[8],PressureStr[8], TemperatureStr[8], TiltXStr[4], TiltYStr[4], TravelTimeStr[6];
		char			AmplitudeStr[4], PersistenceStr[4], PressureAgeStr[4], FlagStr[4];
		long int		IntDate, IntTravelTime, IntIPSPressure, IntIPSTemperature, IntTiltX, IntTiltY;
		long int		IntAmplitude, IntPersistence, IntPressureAge, IntFlag;
		double			TravelTime, IPSPressure, IPSTemperature, TiltX, TiltY;
		double			IPSPressurePeriod, IPSTemperaturePeriod;

		// Make sure IPSString is the mininum length
		j = strlen(IPSString);
		if(j < MIN_IPS_STRINGSIZE)
		{
			Ice->Status = ERROR_SHORT_IPS_DATA_STRING;
			return ERROR_SHORT_IPS_DATA_STRING;
		} //if(j < MIN_IPS_STRINGSIZE)

		// First step is to pull out the necessary data from the IPSString character array
		//DATE
		//
		// Year
		//
		for(i=DATE_LOCATION;i<DATE_LOCATION+2;i++)
		{
			DateStr[i-DATE_LOCATION] = IPSString[i];
		} //for(i=DATE_LOCATION;i<DATE_LOCATION+2;i++) 
		DateStr[i-DATE_LOCATION] = '\0';
		Ice->Year = atoi(DateStr);		
		//
		// Month
		//
		for(i=DATE_LOCATION+2;i<DATE_LOCATION+4;i++)
		{
			DateStr[i-DATE_LOCATION-2] = IPSString[i];
		} //for(i=DATE_LOCATION;i<DATE_LOCATION+2;i++) 
		DateStr[i-DATE_LOCATION-2] = '\0';
		Ice->Month = atoi(DateStr);		
		//
		// Day
		//
		for(i=DATE_LOCATION+4;i<DATE_LOCATION+6;i++)
		{
			DateStr[i-DATE_LOCATION-4] = IPSString[i];
		} //for(i=DATE_LOCATION;i<DATE_LOCATION+2;i++) 
		DateStr[i-DATE_LOCATION-4] = '\0';
		Ice->Day = atoi(DateStr);		
		// TIME
		//
		// Hour
		//
		for(i=TIME_LOCATION;i<TIME_LOCATION+2;i++)
		{
			DateStr[i-TIME_LOCATION] = IPSString[i];
		} //for(i=TIME_LOCATION;i<TIME_LOCATION+2;i++) 
		DateStr[i-TIME_LOCATION] = '\0';
		Ice->Hour = atoi(DateStr);		
		//
		// Minute
		//
		for(i=TIME_LOCATION+2;i<TIME_LOCATION+4;i++)
		{
			DateStr[i-TIME_LOCATION-2] = IPSString[i];
		} //for(i=TIME_LOCATION;i<TIME_LOCATION+2;i++) 
		DateStr[i-TIME_LOCATION-2] = '\0';
		Ice->Minute = atoi(DateStr);		
		//
		// Second
		//
		for(i=TIME_LOCATION+4;i<TIME_LOCATION+6;i++)
		{
			DateStr[i-TIME_LOCATION-4] = IPSString[i];
		} //for(i=TIME_LOCATION;i<TIME_LOCATION+2;i++) 
		DateStr[i-TIME_LOCATION-4] = '\0';
		Ice->Second = atoi(DateStr);		
		
		//PRESSURE
		for(i=PRESSURE_LOCATION;i<PRESSURE_LOCATION+6;i++)
		{
			PressureStr[i-PRESSURE_LOCATION] = IPSString[i];
		} //for(i=PRESSURE_LOCATION;i<6;i++) 
		PressureStr[i-PRESSURE_LOCATION] = '\0';
		sscanf(PressureStr,"%x",&IntIPSPressure);
		
		//TEMPERATURE
		for(i=TEMPERATURE_LOCATION;i<TEMPERATURE_LOCATION+6;i++)
		{
			TemperatureStr[i-TEMPERATURE_LOCATION] = IPSString[i];
		} //for(i=TEMPERATURE_LOCATION;i<6;i++) 
		TemperatureStr[i-TEMPERATURE_LOCATION] = '\0';
		sscanf(TemperatureStr,"%x",&IntIPSTemperature);
		
		//TILT
		for(i=TX_LOCATION;i<TX_LOCATION+2;i++)
		{
			TiltXStr[i-TX_LOCATION] = IPSString[i];
		} //for(i=TX_LOCATION;i<2;i++) 
		TiltXStr[i-TX_LOCATION] = '\0';
		sscanf(TiltXStr,"%x",&IntTiltX);
		
		for(i=TY_LOCATION;i<TY_LOCATION+2;i++)
		{
			TiltYStr[i-TY_LOCATION] = IPSString[i];
		} //for(i=TY_LOCATION;i<2;i++) 
		TiltYStr[i-TY_LOCATION] = '\0';
		sscanf(TiltYStr,"%x",&IntTiltY);
		
		//TRAVEL TIME
		for(i=TRAVELTIME_LOCATION;i<TRAVELTIME_LOCATION+4;i++)
		{
			TravelTimeStr[i-TRAVELTIME_LOCATION] = IPSString[i];
		} //for(i=TRAVELTIME_LOCATION;i<4;i++) 
		TravelTimeStr[i-TRAVELTIME_LOCATION] = '\0';
		sscanf(TravelTimeStr,"%x",&IntTravelTime);
		
		//AMPLITUDE
		for(i=AMPLITUDE_LOCATION;i<AMPLITUDE_LOCATION+2;i++)
		{
			AmplitudeStr[i-AMPLITUDE_LOCATION] = IPSString[i];
		} //for(i=AMPLITUDE_LOCATION;i<AMPLITUDE_LOCATION+2;i++) 
		AmplitudeStr[i-AMPLITUDE_LOCATION] = '\0';
		sscanf(AmplitudeStr,"%x",&IntAmplitude);
		Ice->Amplitude = IntAmplitude;
		
		//PERSISTENCE
		for(i=PERSISTENCE_LOCATION;i<PERSISTENCE_LOCATION+2;i++)
		{
			PersistenceStr[i-PERSISTENCE_LOCATION] = IPSString[i];
		} //for(i=PERSISTENCE_LOCATION;i<PERSISTENCE_LOCATION+2;i++) 
		PersistenceStr[i-PERSISTENCE_LOCATION] = '\0';
		sscanf(PersistenceStr,"%x",&IntPersistence);
		
		//PRESSUREAGE
		for(i=PRESSUREAGE_LOCATION;i<PRESSUREAGE_LOCATION+2;i++)
		{
			PressureAgeStr[i-PRESSUREAGE_LOCATION] = IPSString[i];
		} //for(i=PRESSUREAGE_LOCATION;i<PRESSUREAGE_LOCATION+2;i++) 
		PressureAgeStr[i-PRESSUREAGE_LOCATION] = '\0';
		sscanf(PressureAgeStr,"%x", &IntPressureAge);
		Ice->PressureAge = IntPressureAge;
		
		//FLAG
		for(i=FLAG_LOCATION;i<FLAG_LOCATION+2;i++)
		{
			FlagStr[i-FLAG_LOCATION] = IPSString[i];
		} //for(i=FLAG_LOCATION;i<FLAG_LOCATION+2;i++) 
		FlagStr[i-FLAG_LOCATION] = '\0';
		sscanf(FlagStr,"%x", &IntFlag);
		Ice->Flag = IntFlag;
		
		// Compute the travel time using the average sound speed
		TravelTime = IntTravelTime * ECLOCK * 16.;
		
		// Compute the tilt using the Paros Coefficients
		Paros_Tilt(IntTiltX, IntTiltY, &TiltX, &TiltY);
		
		// Convert IntIPSTemperature to temperature period in usecs
		IPSTemperaturePeriod = IntIPSTemperature*(ECLOCK/(361.*128.))*1000000.;
		
		// Calculate an IPS Temperature from the temperature period
		Paros_Temperature(IPSTemperaturePeriod, &IPSTemperature);
		
		// Convert IntIPSPressure to pressure period in usecs
		IPSPressurePeriod = IntIPSPressure*(ECLOCK/(340.*32.))*1000000.;
		
		// Calculate an IPS Pressure from the temperature and pressure periods
		Paros_Pressure(IPSTemperaturePeriod, IPSPressurePeriod, &IPSPressure);
		
		// Compute Persistence in ms
		Ice->Persistence = IntPersistence*ECLOCK*16*1000;
		
		// Pass out values to the structure Ice
		Ice->TravelTime = TravelTime;
		Ice->Pressure = IPSPressure;
		Ice->Temperature = IPSTemperature;
		Ice->TiltX = TiltX;
		Ice->TiltY = TiltY;
		
		// Change Ice->Status to 1 to indicate that the IPS data has
		// been decoded but ice drafts have not been calculated
		Ice->Status = DATA_DECODED;

		return DATA_DECODED;
}		


//#############################################################################
// Section:  IceDraft  Program
//
// Function: void Paros_Tilt(long int IntTiltX, long int IntTiltY, double *TiltX, double *TiltY)
//
// Purpose:  compute tilt-x and tilt-y using tilt coeff
//#############################################################################

void Paros_Tilt(long int IntTiltX, long int IntTiltY, double *TiltX, double *TiltY)
{

	*TiltX = X_B * IntTiltX + X_A;
	*TiltY = Y_B * IntTiltY + Y_A;


	return;
}

//#############################################################################
// Section:  IceDraft  Program
//
// Function: void Paros_Temperature(double TemperaturePeriod, double *Temperature)
//
// Purpose:  compute temperature using PAROS coeff
//#############################################################################

void Paros_Temperature(double TemperaturePeriod, double *Temperature)
{

	double U;
	
	U = TemperaturePeriod - U0;
	*Temperature = Y1 * U + Y2 * U * U + Y3 * U * U * U;


	return;
}


//#############################################################################
// Section:  IceDraft  Program
//
// Function: void Paros_Pressure(double TemperaturePeriod, double PressurePeriod, double *Pressure)
//
// Purpose:  compute pressure using PAROS coeff
//#############################################################################

void Paros_Pressure(double TemperaturePeriod, double PressurePeriod, double *Pressure)
{

	double Temperature, U, C, D, T0;
	
	U = TemperaturePeriod - U0;
	C = C1 + C2 * U + C3 * U * U;
	D = D1 + D2 * U;
	T0 = T1 + T2 * U + T3 * U * U + T4 * U * U * U + T5 * U * U * U * U;
	*Pressure = C * (1. - (T0*T0)/(PressurePeriod*PressurePeriod)) * (1. - D * (1. - (T0*T0)/(PressurePeriod*PressurePeriod)));


	return;
}

