head 3.1; access oasisa; symbols ; locks oasisa:3.1; strict; comment @ * @; 3.1 date 2001.06.19.13.12.52; author oasisa; state Exp; branches ; next 3.0; 3.0 date 99.05.12.10.11.26; author bobh; state Exp; branches ; next 2.9; 2.9 date 98.08.24.13.45.54; author bobh; state Exp; branches ; next 2.8; 2.8 date 98.03.17.11.11.40; author bobh; state Exp; branches ; next 2.5; 2.5 date 94.12.15.10.59.40; author hebo; state Exp; branches ; next 2.2; 2.2 date 92.09.24.18.34.44; author hebo; state Exp; branches ; next 2.1; 2.1 date 92.09.04.13.35.12; author hebo; state Exp; branches ; next 2.0; 2.0 date 92.08.31.15.34.16; author hebo; state Exp; branches ; next 1.0; 1.0 date 92.02.25.10.46.57; author hebo; state Rel; branches ; next ; desc @Routines to decode CTD output for decode.c and extract.c @ 3.1 log @ Periodic Update 6/19/2001 (klh) @ text @/****************************************************************************/ /* Copyright 1992 MBARI */ /****************************************************************************/ /* $Header: ctd.c,v 3.0 99/05/12 10:11:26 bobh Exp $ */ /* Summary : CTD decode routines for decode.c, extract.c */ /* Filename : ctd.c */ /* Author : Robert Herlien (rah) */ /* Project : OASIS Mooring */ /* $Revision: 3.0 $ */ /* Created : 01/24/92 */ /* */ /* MBARI provides this documentation and code "as is", with no warranty, */ /* express or implied, of its quality or consistency. It is provided without*/ /* support and without obligation on the part of the Monterey Bay Aquarium */ /* Research Institute to assist in its use, correction, modification, or */ /* enhancement. This information should not be published or distributed to */ /* third parties without specific written permission from MBARI. */ /* */ /****************************************************************************/ /* Modification History: */ /* 24jan91 rah - created */ /* $Log: ctd.c,v $ * Revision 3.0 99/05/12 10:11:26 10:11:26 bobh (Bob Herlien) * Added tstring, misc changes * * Revision 2.9 98/08/24 13:45:54 13:45:54 bobh (Bob Herlien) * Archiving sources after M2/M3 & Eqpac deployments of 1998 * * Revision 2.8 98/03/17 11:11:40 11:11:40 bobh (Bob Herlien) * Archiving sources prior to porting to DOS/Windows * * Revision 2.5 94/12/15 10:59:40 10:59:40 hebo (Bob Herlien) * Accumulated minor changes, mainly due to move to tsunami * * Revision 2.2 92/09/24 18:34:44 18:34:44 hebo (Bob Herlien) * Changed trfl to trans and fluor, use upper 12 bits if offset even, lower * if odd. This due to trans, fluor backward on some CTDs * * Revision 2.1 92/09/04 13:35:12 13:35:12 hebo (Bob Herlien) * Read pressure from calibration file if CTD has no pressure sensor. * * Revision 2.0 92/08/31 15:34:16 15:34:16 hebo (Bob Herlien) * August 1992 Deployment. Changed to allow multiple sensors of same type. * * Revision 1.0 92/02/25 10:46:57 10:46:57 hebo (Bob Herlien) * Initial revision * * Revision 1.1 92/02/25 10:45:31 10:45:31 hebo (Bob Herlien) * Initial revision * */ /****************************************************************************/ #include /* Standard I/O */ #include /* MBARI type definitions */ #include /* MBARI constants */ #include /* OASIS controller definitions */ #include /* Time */ #include /* for toupper() */ #include /* for strcmp */ #include /********************************/ /* External Function */ /********************************/ Extern Nat16 getMotword( Byte *p ); /********************************/ /* Module Local Data */ /********************************/ MLocal char buff[256]; /* Scratch buffer */ /************************************************************************/ /* Function : init_one_cal */ /* Purpose : Initialize one CTD calibration value */ /* Inputs : Ptr to Cal to init */ /* Outputs : None */ /************************************************************************/ Void init_one_cal( CCal *p ) { p->offset = 0; p->a = (double)0.0; p->b = (double)0.0; p->c = (double)0.0; p->d = (double)0.0; p->mf = (double)0.0; } /* init_one_cal() */ /************************************************************************/ /* Function : read_ctd_cal */ /* Purpose : Read CTD calibration file */ /* Inputs : Name of file, place to put calibrations */ /* Outputs : OK or ERROR */ /************************************************************************/ Status read_ctd_cal( char *name, CTDCal *ccp ) { FILE *fp; Int ncals; ccp->cc_size = CTD_BYTES; init_one_cal(&ccp->cc_cond); init_one_cal(&ccp->cc_temp); init_one_cal(&ccp->cc_press); init_one_cal(&ccp->cc_trans); init_one_cal(&ccp->cc_fluor); init_one_cal(&ccp->cc_sample); if ( (fp = fopen(name, "rb")) == (FILE *)NULL ) return( ERROR ); ncals = 0; while ( fscanf(fp, " %s", buff) != EOF ) { if ( strcmp(buff, "length") == 0 ) { if ( fscanf(fp, " %d", &ccp->cc_size) == 1 ) ncals++; } if ( strcmp(buff, "cond") == 0 ) { if ( fscanf(fp, " %d %lg %lg %lg %lg %lg", &ccp->cc_cond.offset, &ccp->cc_cond.a, &ccp->cc_cond.b, &ccp->cc_cond.c, &ccp->cc_cond.d, &ccp->cc_cond.mf) >= 5 ) ncals++; } else if ( strcmp(buff, "temp") == 0 ) { if ( fscanf(fp, " %d %lg %lg %lg %lg %lg", &ccp->cc_temp.offset, &ccp->cc_temp.a, &ccp->cc_temp.b, &ccp->cc_temp.c, &ccp->cc_temp.d, &ccp->cc_temp.mf) == 6 ) ncals++; } else if ( strcmp(buff, "press") == 0 ) { if ( fscanf(fp, " %d %lg %lg %lg", &ccp->cc_press.offset, &ccp->cc_press.a, &ccp->cc_press.b, &ccp->cc_press.c) >= 2 ) ncals++; } else if ( strcmp(buff, "trans") == 0 ) { if ( fscanf(fp, " %d", &ccp->cc_trans.offset) == 1 ) ncals++; } else if ( strcmp(buff, "fluor") == 0 ) { if ( fscanf(fp, " %d", &ccp->cc_fluor.offset) == 1 ) ncals++; } else if ( strcmp(buff, "sample") == 0 ) { if ( fscanf(fp, " %d", &ccp->cc_sample.offset) == 1 ) ncals++; } } fclose( fp ); return( ncals >= 5 ? OK : ERROR ); } /* read_ctd_cal() */ /************************************************************************/ /* Function : ctd_temperature */ /* Purpose : Calculate CTD temperature */ /* Inputs : Temp count, Calibration struct */ /* Outputs : Temperature in degrees Celsius */ /************************************************************************/ double ctd_temperature( Nat16 t, CTDCal *ccp ) { double freq; /* val converted to freq */ double x; /* Intermediate value */ freq = (double)t / 19.0 + 2100.0; /* Convert to frequency */ x = log( ccp->cc_temp.mf / freq ); /* Calc ln(f0/f) */ return( 1.0 / (ccp->cc_temp.a + (ccp->cc_temp.b * x) + (ccp->cc_temp.c * x * x) + (ccp->cc_temp.d * x * x * x)) - 273.15 ); } /* ctd_temperature() */ /************************************************************************/ /* Function : ctd_pressure */ /* Purpose : Calculate CTD pressure */ /* Inputs : Pressure count, Calibration struct */ /* Outputs : Pressure in decibars */ /************************************************************************/ #define DECIBAR 0.6894759 /* PSI to decibar conversion const */ double ctd_pressure( Nat16 p, CTDCal *ccp ) { Nat32 p1; p1 = (p > 4095) ? p - 65536 : p; return( DECIBAR * (ccp->cc_press.a + (ccp->cc_press.b * (double)p1) + (ccp->cc_press.c * (double)p1 * (double)p1) - 14.7) ); } /* ctd_pressure() */ /************************************************************************/ /* Function : ctd_conduct */ /* Purpose : Calculate CTD conductivity */ /* Inputs : Conductivity count, Temp, Pressure (decibars), calibr */ /* Outputs : Conductivity in Siemans/meter */ /************************************************************************/ #define CONP 9.57e-08 /* "Magic" conductivity constant */ double ctd_conduct( Nat16 c, double t, double p, CTDCal *ccp ) { double freq; /* conductivity frequency */ double x; /* Intermediate value */ freq = sqrt(2100.0 * (double)c + 6.25e06) / 1000.0; x = 0.1 * ((ccp->cc_cond.a * pow(freq,ccp->cc_cond.mf)) + (ccp->cc_cond.b * freq * freq) + ccp->cc_cond.c + (ccp->cc_cond.d * t)); return( x / (1.0 - CONP * p) ); } /* ctd_conduct() */ /************************************************************************/ /* Function : ctd_salinity */ /* Purpose : Calculate CTD salinity */ /* Inputs : Conductivity, temperature, pressure */ /* Outputs : Salinity as a double precision real number */ /* Comments : Lifted (almost) directly from Seabird's cnv.c file */ /************************************************************************/ #define A1 2.070e-5 /* salinity constants */ #define A2 -6.370e-10 #define A3 3.989e-15 #define B1 3.426e-2 #define B2 4.464e-4 #define B3 4.215e-1 #define B4 -3.107e-3 #define C0 6.766097e-1 #define C1 2.00564e-2 #define C2 1.104259e-4 #define C3 -6.9698e-7 #define C4 1.0031e-9 double a[6] = { /* constants for salinity calculation */ 0.0080, -0.1692, 25.3851, 14.0941, -7.0261, 2.7081 }; double b[6]={ /* constants for salinity calculation */ 0.0005, -0.0056, -0.0066, -0.0375, 0.0636, -0.0144 }; double ctd_salinity( double c, double t, double p ) { double rt,rp,temp,sum1,sum2,result; Int i; if ( c <= 0.0 ) result = 0.0; else { c *= 10.0; /* convert Siemens/meter to mmhos/cm */ c /= 42.914; rp = 1+(p*(A1+p*(A2+p*A3)))/(1+B1*t+B2*t*t+B3*c+B4*c*t); rt = c /(rp*(C0+(t*(C1+t*(C2+t*(C3+t*C4)))))); sum1 = sum2 = 0.0; for(i=0;i<6;i++) { temp = pow(rt,(double)i/2.0); sum1 = sum1 + a[i] * temp; sum2 = sum2 + b[i] * temp; } result = sum1+sum2*(t-15.0)/(1+0.0162*(t-15.0)); } return( result ); } /* ctd_salinity() */ /************************************************************************/ /* Function : ctd_transfluor */ /* Purpose : Calculate transmissometer or fluorometer voltage */ /* Inputs : Ptr to data buffer, ptr to calibration struct */ /* Outputs : Voltage of transmissometer or fluorometer */ /* Comments : Transmissometer and fluorometer get packed together */ /* into a 3 byte value (12 bits per voltage). It looks */ /* OK coming out in hex from the CTD, because it's 3 ASCII*/ /* digits per value. But OASIS decodes the ASCII into hex,*/ /* with the result that 3 bytes stores 2 values. */ /* The offset parameter of the calibration file doesn't */ /* really tell you whether to use the first 12 bits of the*/ /* word (i >> 4) or the last 12 bits (i & 0xfff). But we */ /* fake it because we know that an even offset means the */ /* first 12 bits, and an odd offset means the last 12 bits*/ /************************************************************************/ double ctd_transfluor( Byte *dp, CCal *ccp ) { Reg Nat16 i; i = getMotword(dp + ccp->offset); if ( ccp->offset & 1 ) i &= 0xfff; else i >>= 4; return( (double)i / 819.0 ); } /* ctd_transfluor() */ /************************************************************************/ /* Function : decode_ctd */ /* Purpose : Decode CTD information */ /* Inputs : Pointer to CTD data, length, ptr to return struct */ /* Outputs : OK or SIZE_ERR */ /************************************************************************/ Status decode_ctd( Byte *dp, Int len, CTDDecode *cdp, CTDCal *ccp ) { if ( len != ccp->cc_size ) /* Check # words, rtn if bad*/ return( SIZE_ERR ); if ( ccp->cc_sample.offset >= 0 ) cdp->ctd_sample = getMotword(dp + ccp->cc_sample.offset); else cdp->ctd_sample = 0; cdp->ctd_temp = ctd_temperature(getMotword(dp + ccp->cc_temp.offset), ccp); /* Get temperature */ if ( ccp->cc_press.offset >= 0 ) cdp->ctd_press = ctd_pressure( getMotword(dp + ccp->cc_press.offset), ccp ); else cdp->ctd_press = ccp->cc_press.a; cdp->ctd_cond = ctd_conduct( getMotword(dp + ccp->cc_cond.offset), cdp->ctd_temp, cdp->ctd_press, ccp ); /* Get conductivity */ cdp->ctd_sal = ctd_salinity(cdp->ctd_cond, cdp->ctd_temp, cdp->ctd_press); /* Get salinity */ if ( ccp->cc_fluor.offset > 0 ) cdp->ctd_fluor = ctd_transfluor( dp, &ccp->cc_fluor ); if ( ccp->cc_trans.offset > 0 ) cdp->ctd_trans = ctd_transfluor( dp, &ccp->cc_trans ); return( OK ); } /* decode_ctd() */ @ 3.0 log @Added tstring, misc changes @ text @d4 1 a4 1 /* $Header: ctd.c,v 2.9 98/08/24 13:45:54 bobh Exp $ */ d9 1 a9 1 /* $Revision: 2.9 $ */ d11 8 d23 3 d367 1 d369 1 @ 2.9 log @Archiving sources after M2/M3 & Eqpac deployments of 1998 @ text @d4 1 a4 1 /* $Header: ctd.c,v 2.8 98/03/17 11:11:40 bobh Exp $ */ d9 1 a9 1 /* $Revision: 2.8 $ */ d15 3 @ 2.8 log @Archiving sources prior to porting to DOS/Windows @ text @d4 1 a4 1 /* $Header: ctd.c,v 2.5 94/12/15 10:59:40 hebo Exp $ */ d9 1 a9 1 /* $Revision: 2.5 $ */ d15 3 d41 2 a42 2 #include /* MBARI type definitions */ #include /* MBARI constants */ d46 1 d49 1 a92 1 CCal fc; @ 2.5 log @Accumulated minor changes, mainly due to move to tsunami @ text @d4 1 a4 1 /* $Header: ctd.c,v 2.2 92/09/24 18:34:44 hebo Exp $ */ d9 1 a9 1 /* $Revision: 2.2 $ */ d15 3 @ 2.2 log @Changed trfl to trans and fluor, use upper 12 bits if offset even, lower if odd. This due to trans, fluor backward on some CTDs @ text @d4 1 a4 1 /* $Header: ctd.c,v 2.1 92/09/04 13:35:12 hebo Exp $ */ d9 1 a9 1 /* $Revision: 2.1 $ */ d15 4 d327 4 a330 1 cdp->ctd_sample = getMotword(dp + ccp->cc_sample.offset); d334 1 a334 1 if ( ccp->cc_press.offset > 0 ) @ 2.1 log @Read pressure from calibration file if CTD has no pressure sensor. @ text @d4 1 a4 1 /* $Header: ctd.c,v 2.0 92/08/31 15:34:16 hebo Exp $ */ d9 1 a9 1 /* $Revision: 2.0 $ */ d15 3 d88 2 a89 1 init_one_cal(&ccp->cc_trfl); d125 1 a125 1 else if ( strcmp(buff, "transfluor") == 0 ) d127 1 a127 1 if ( fscanf(fp, " %d", &ccp->cc_trfl.offset) == 1 ) d130 5 d279 33 d339 3 a341 4 cdp->ctd_fluor = (double)(getMotword(dp + ccp->cc_trfl.offset) >> 4) / 819.0; cdp->ctd_trans = (double)(getMotword(dp + ccp->cc_trfl.offset + 1) & 0xfff) / 819.0; @ 2.0 log @August 1992 Deployment. Changed to allow multiple sensors of same type. @ text @d4 1 a4 1 /* $Header: ctd.c,v 1.0 92/02/25 10:46:57 hebo Rel $ */ d9 1 a9 1 /* $Revision: 1.0 $ */ d15 3 d118 1 a118 1 &ccp->cc_press.c) == 4 ) d285 1 a285 1 if ( len >= CTD_BYTES ) /* Get pressure */ d289 1 a289 1 cdp->ctd_press = 0.0; @ 1.0 log @Initial revision @ text @d4 1 a4 1 /* $Header: ctd.c,v 1.1 92/02/25 10:45:31 hebo Exp $ */ d9 1 a9 1 /* $Revision: 1.1 $ */ d15 3 a31 24 #define CAL_FILE "ctd.cal" /* CTD calibration file */ #define COND_OFS 2 /* Offset in data for conductivity */ #define TRANS_OFS 4 /* Offset in data for transmissometer*/ #define FLUOR_OFS 5 /* Offset in data for fluorometer */ #define PRESS_OFS 7 /* Offset in data for pressure */ #define SAMPLE_OFS 9 /* Offset in data for sample number */ typedef struct /************************************/ { /* Calibration structure type */ double a; /* A or A0 calibration coefficient */ double b; /* B or A1 calibration coefficient */ double c; /* C or A2 calibration coefficient */ double d; /* D calibration coefficient */ double mf; /* M or F0 calibration coefficient */ } Cal; /************************************/ typedef struct /************************************/ { /* Struct for CTD calibration */ Cal cc_cond; /* Conductivity calibration */ Cal cc_temp; /* Temperature calibration */ Cal cc_press; /* Pressure calibration */ } CTDCal; /************************************/ d43 1 a43 1 MLocal CTDCal ccal; /* CTD calibration */ d53 1 a53 1 init_one_cal( Cal *p ) d55 1 d68 1 a68 1 /* Inputs : Name of file */ d72 1 a72 1 read_ctd_cal( char *name ) d75 1 a75 2 Cal fc; char buff[256]; d78 6 a83 3 init_one_cal(&ccal.cc_cond); init_one_cal(&ccal.cc_temp); init_one_cal(&ccal.cc_press); d85 1 a85 6 if ( name == NULL ) fp = fopen( CAL_FILE, "rb" ); else fp = fopen( name, "rb" ); if ( fp == (FILE *)NULL ) d92 5 d99 3 a101 3 if ( fscanf(fp, " %lg %lg %lg %lg %lg", &ccal.cc_cond.a, &ccal.cc_cond.b, &ccal.cc_cond.c, &ccal.cc_cond.d, &ccal.cc_cond.mf) == 5 ) d106 3 a108 3 if ( fscanf(fp, " %lg %lg %lg %lg %lg", &ccal.cc_temp.a, &ccal.cc_temp.b, &ccal.cc_temp.c, &ccal.cc_temp.d, &ccal.cc_temp.mf) == 5 ) d113 3 a115 2 if ( fscanf(fp, " %lg %lg %lg", &ccal.cc_press.a, &ccal.cc_press.b, &ccal.cc_press.c) == 3 ) d118 10 d131 1 a131 1 return( ncals == 3 ? OK : ERROR ); d139 1 a139 1 /* Inputs : Temp count */ d143 1 a143 1 ctd_temperature( Nat16 t ) d149 3 a151 3 x = log( ccal.cc_temp.mf / freq ); /* Calc ln(f0/f) */ return( 1.0 / (ccal.cc_temp.a + (ccal.cc_temp.b * x) + (ccal.cc_temp.c * x * x) + (ccal.cc_temp.d * x * x * x)) d160 1 a160 1 /* Inputs : Pressure count */ d166 1 a166 1 ctd_pressure( Nat16 p ) d171 2 a172 2 return( DECIBAR * (ccal.cc_press.a + (ccal.cc_press.b * (double)p1) + (ccal.cc_press.c * (double)p1 * (double)p1) - 14.7) ); d180 1 a180 1 /* Inputs : Conductivity count, Temp, Pressure (decibars) */ d186 1 a186 1 ctd_conduct( Nat16 c, double t, double p ) d192 3 a194 3 x = 0.1 * ((ccal.cc_cond.a * pow(freq,ccal.cc_cond.mf)) + (ccal.cc_cond.b * freq * freq) + ccal.cc_cond.c + (ccal.cc_cond.d * t)); d273 1 a273 1 decode_ctd( Byte *dp, Int len, CTDDecode *cdp ) d275 1 a275 1 if ( len < CTD_BYTES ) /* Check # words, rtn if bad*/ d278 3 a280 3 cdp->ctd_sample = getMotword(dp + SAMPLE_OFS); /* Get sample number */ cdp->ctd_temp = ctd_temperature(getMotword(dp)); d282 8 a289 4 cdp->ctd_press = ctd_pressure( getMotword(dp + PRESS_OFS) ); /* Get pressure */ cdp->ctd_cond = ctd_conduct( getMotword(dp + COND_OFS), cdp->ctd_temp, cdp->ctd_press ); d294 4 a297 3 cdp->ctd_trans = (double)(getMotword(dp + TRANS_OFS) >> 4) / 819.0; cdp->ctd_fluor = (double)(getMotword(dp + FLUOR_OFS) & 0xfff) / 819.0; @