#!/usr/bin/env perl # -*- perl -*- # 'di'; # 'ig00'; #----------------------------------------------------------------------- # Module Name: $Source: /Users/goeke/programming/perl/crater/RCS/calcurve,v $ # Purpose: Convert decimal data into hex and engineering units # Language: Perl 5 # Assumptions: Consistent with Data ICD, 32-02001 # Part Number: # Author: Robert F. Goeke (goeke@space.mit.edu # References: # Copyright: Massachusetts Institute of Technology 2006 #----------------------------------------------------------------------- $Version = '$Id: calcurve,v 2.38 2008/10/22 13:50:35 goeke Exp goeke $'; ############################################# # These are CRaTER standard data archive tags ############################################# @House = ( 'V28bus', 'V5digital', 'V5plus', 'V5neg', 'I28bus', 'BiasCurrentD1', 'BiasCurrentD2', 'BiasCurrentD3', 'BiasCurrentD4', 'BiasCurrentD5', 'BiasCurrentD6', 'BiasVoltThin', 'BiasVoltThick', 'CalAmp', 'LLDThin', 'LLDThick', 'Ttelescope', 'Tanalog', 'Tdigital', 'Tpower', 'Tref', 'RadMonitor1', 'RadMonitor2', 'RadMonitor3', 'Tprt', 'Purge' ); $SN = 2; &Recalibrate($SN); # Do a default in case CRaTER isn't running &Setup; &Operate; exit 0; ######################################################################## # Help facility ######################################################################## sub Help { my $ii; print "usage: $0 [-h] [-v]\n"; return if (!$Verbose); print "$Version Receives CRaTER telemetry in archive format on STDIN and converts analog housekeeping to decimal/hex/engineering/units on STDOUT. Interogates instrument serial number to determine coefficients; returns *sn* if no unit-specific coefficients are found. Non-analog telemetry is passed through unchanged. flag -h help message -r flip dosimeter RadMed and RadLo channels -v verbose display "; print "\nOperates on the following Housekeeping Mnemonics\n "; for ($ii=0; $ii<=$#House; ) { print "$House[$ii] "; $ii++; print "\n " if (!($ii % 5)); } print "\nAdds mnemonic \"P28bus\" as calculation of V28bus * I28bus.\n"; exit 0; } ######################################################################## # Take input and apply conversion equations # NB Because some conversions require data from multiple tags, # one needs to see a whole packet to get a valid conversion # Req. input in standard rtlm archive format; i.e.: decimal values # Output is in engineering units or hex ######################################################################## sub Operate { my $not_eng; my ($aa,$bb); my $value; my $units; my $_counts = 'counts'; my $_volts = 'Volts'; my $_amps = 'Amps'; my $_watts = 'Watts'; my $_microamps = 'microamps'; # my $_nanoamps = 'nanoamps'; my $_cent = 'degrees C'; my $_millirad = 'milliRad'; my $_rad = 'Rad'; my $_cfh = "CFH"; my $save_28v; my $save_28p = -1; while (<>) { $not_eng = $_; # safety save for pass through lines ($aa,$bb) = split; if (defined($RadFlip)) { if ($aa =~ /RadMedSens/) { $aa = 'RadLowSens'; } elsif ($aa =~ /RadLowSens/) { $aa = 'RadMedSens'; } } SW: { # a giant case statement $aa =~ /SerialNumber/ && do { $bb = &Recalibrate($bb); # (re)set the calibration, perhaps printf "%s\t%s\n",$aa,$bb; last SW; }; $aa =~ /V28bus/ && do { $value = sprintf "%2.2f", $__V28bus*$bb + $__V28bus_offset; $units = $_volts; $value = "n/a" if ($bb<100); $save_28v = $value; # we use this later for power next SW; }; $aa =~ /V5digital/ && do { $value = sprintf "%1.3f", $__V5digital*$bb ; $units = $_volts; next SW; }; $aa =~ /V5plus/ && do { $V5plus = $__V5plus*$bb; # save this for temperature conversion $value = sprintf "%1.3f", $__V5plus*$bb ; $units = $_volts; next SW; }; $aa =~ /V5neg/ && do { $value = sprintf "%1.3f", $__V5neg*$bb ; $units = $_volts; next SW; }; $aa =~ /I28bus/ && do { $value = sprintf "%1.3f", $__I28bus*$bb ; $units = $_amps; if ($bb<100) { $value = "n/a"; $save_28p = "n/a"; } else { $save_28p = $value * $save_28v; # this is power $save_28p = sprintf "%1.2f", $save_28p; } next SW; }; $aa =~ /BiasCurrentD[135]/ && do { $value = sprintf "%1.3f", $__BiasCurrentD135*$bb ; $units = $_microamps; next SW; }; $aa =~ /BiasCurrentD[246]/ && do { $value = sprintf "%2.2f", $__BiasCurrentD246*$bb ; $units = $_microamps; next SW; }; $aa =~ /BiasVoltThin/ && do { $value = sprintf "%3.1f", $__BiasVoltThin*$bb; $units = $_volts; next SW; }; $aa =~ /BiasVoltThick/ && do { $value = sprintf "%3.1f", $__BiasVoltThick*$bb; $units = $_volts; next SW; }; $aa =~ /CalAmp/ && do { $value = sprintf "%1.3f", $__CalAmp*$bb ; $units = $_volts; next SW; }; $aa =~ /LLDThin/ && do { $value = sprintf "%1.3f", $__LLDThin*$bb - $__LLDThin_offset ; $units = $_volts; next SW; }; $aa =~ /LLDThick/ && do { $value = sprintf "%1.3f", $__LLDThick*$bb - $__LLDThick_offset ; $units = $_volts; next SW; }; $aa =~ /Time/ && do { # just to clear the T* which follow print($not_eng); last SW; }; $aa =~ /Tprt/ && do { $value = sprintf "%2.1f", $__Tprt_a*(4*$bb - 10000)/(5 - $bb*$__Tprt_b) ; $value = "n/a" if ($__Tprt_a > 10); $units = $_cent; next SW; }; $aa =~ /^Ttelescope/ && do { if (defined($V5plus) && $V5plus>2.5) { $value = sprintf "%2.1f", 100*$V5plus - $__Temp_a*$bb - $__Temp_b_telescope ; } else { $value = "n/a"; } $units = $_cent; next SW; }; $aa =~ /^Tanalog/ && do { if (defined($V5plus) && $V5plus>2.5) { $value = sprintf "%2.1f", 100*$V5plus - $__Temp_a*$bb - $__Temp_b_analog ; } else { $value = "n/a"; } $units = $_cent; next SW; }; $aa =~ /^Tdigital/ && do { if (defined($V5plus) && $V5plus>2.5) { $value = sprintf "%2.1f", 100*$V5plus - $__Temp_a*$bb - $__Temp_b_digital ; } else { $value = "n/a"; } $units = $_cent; next SW; }; $aa =~ /^Tpower/ && do { if (defined($V5plus) && $V5plus>2.5) { $value = sprintf "%2.1f", 100*$V5plus - $__Temp_a*$bb - $__Temp_b_power ; } else { $value = "n/a"; } $units = $_cent; next SW; }; $aa =~ /^Tref/ && do { if (defined($V5plus) && $V5plus>2.5) { $Tref = 100*$V5plus - $__Temp_a*$bb - $__Temp_b_ref ; $value = sprintf "%2.1f", $Tref; } else { $value = "n/a"; $Tref = 999; # we use $Tref for purge } $units = $_cent; next SW; }; # The Dosimeter converts counts to voltage using an 8-bit DAC # So we translate the 12-bit count to the nearest 8-bit value $aa =~ /RadHighSens/ && do { $value = sprintf "%1.2f", $__RadHighSens*(($bb+4-$__RadHighOffset)>>3) ; $_radhi = $bb; $units = $_millirad; $value = "n/a" if (!$__RadExist); next SW; }; $aa =~ /RadMedSens/ && do { $value = sprintf "%4.0f", $__RadMedSens*(($bb+4-$__RadMedOffset)>>3) ; $_radmed = $bb; $units = $_millirad; $value = "n/a" if (!$__RadExist); next SW; }; $aa =~ /RadLowSens/ && do { $value = sprintf "%3.1f", $__RadLowSens*(($bb+4-$__RadLowOffset)>>3) ; $_radlo = $bb; $units = $_rad; $value = "n/a" if (!$__RadExist); next SW; }; $aa =~ /Purge/ && do { if (defined($V5plus) && $V5plus>2.5 && defined($Tref) && $Tref>14 && $Tref<36) { $value = sprintf "%d", $__Purge_a*($bb - 1000*$__Purge_b*$V5plus + 1000*$__Purge_c*($Tref-25)) + $__Purge_d; } else { $value = "n/a"; } $units = $_cfh; next SW; }; $aa =~ /BusCmd/ && do { $value = ($bb) ? "On" : "Off"; $units = ''; next SW; }; $aa =~ /BusVoltage/ && do { $BV = sprintf "%1.1f", $__BusVoltage_a + $__BusVoltage_b*$bb ; $value = $BV; $units = $_volts; next SW; }; $aa =~ /BusCurrent/ && do { $BI = sprintf "%1.3f", $__BusCurrent_a + $__BusCurrent_b*$bb ; $value = $BI; $units = $_amps; next SW; }; $aa =~ /BusPower/ && do { $bb = 0; $value = sprintf "%1.2f", $BV*$BI ; $units = $_watts; next SW; }; print($not_eng); last; } continue { $units = "no s/n" if ($SN<1); $value = '' if ($SN<1); $value = '--' if ($bb>4094); # A/D is saturated printf("%s\t%d\t0x%03x\t%s\t%s\n",$aa,$bb,$bb,$value,$units); if ($save_28p >= 0) { printf("%s\t%s\t%s\t%s\t%s\n","P28bus", "--", "--", $save_28p, "watts"); $save_28p = -1; } } } } ######################################################################## # Set up the calibration constants based upon the unit SerialNumber ######################################################################## sub Recalibrate { return $SN if ($Last_SN == $_[0]); # What's done is done $SN = $_[0]; print STDERR "CAL Switching to Serial Number $SN\n" if $Verbose; $Last_SN = $SN; # Remember who we are # First specify the nominal case $__V28bus = 0.0101; $__V28bus_offset = 0; $__V5digital = 0.002; $__V5plus = 0.002; $__V5neg = -0.00201; $__I28bus = 0.000198; $__BiasCurrentD135 = 0.0005; $__BiasCurrentD246 = 0.005; $__BiasVoltThin = 0.1; $__BiasVoltThick = 0.1; $__CalAmp = 0.001; $__LLDThin = 0.000124; $__LLDThick = 0.000124; $__LLDThin_offset = 0.124; $__LLDThick_offset = 0.124; $__Tprt_a = 0.1299; $__Tprt_b = 0.001; $__Temp_a = 0.1; $__Temp_b_telescope = 273; $__Temp_b_analog = 273; $__Temp_b_digital = 273; $__Temp_b_power = 273; $__Temp_b_ref = 273; $__RadExist = 0; # set to 1 if dosimeter present $__RadHighSens = 0.02; $__RadHighOffset = 0; $__RadMedSens = 5.12; $__RadMedOffset = 0; $__RadLowSens = 1.31; $__RadLowOffset = 0; $__Purge_a = 1; # counts to CFH scale factor $__Purge_b = 300/(2*300 + 250); # static 300 ohm thermistor at 25C $__Purge_c = 0.0183; # straight line slope for temp $__Purge_d = 0; # DC offset in CFH $__BusCurrent_a = -10.229; # Goddard said -10.2313 $__BusCurrent_b = 0.0050022; $__BusVoltage_a = -42.1303; $__BusVoltage_b = 0.020590; if ($SN == 31) { # Software simulator } elsif ($SN == 11) { # FlatSat simulator $__RadExist = 1; } elsif ($SN == 1) { # The first first flight unit $__V28bus = 0.01000; $__V5digital = 0.001986; $__V5plus = 0.002000; $__V5neg = -0.001996; $__I28bus = 0.000205; $__CalAmp = 0.000995; $__Temp_b_telescope = 273+1.1; $__Temp_b_analog = 273+1.5; $__Temp_b_digital = 273+1.5; $__Temp_b_power = 273-0.2; } elsif ($SN == 2) { # First cut l $__V28bus = 0.01026; $__V28bus_offset = -1.45; $__V5digital = 0.001997; $__V5plus = 0.002004; $__V5neg = -0.002009; $__BiasVoltThin = 0.1001; $__BiasVoltThick = 0.09972; $__LLDThin = 0.0001232; $__LLDThick = 0.0001234; $__LLDThin_offset = 0.123; $__LLDThick_offset = 0.1239; $__CalAmp = 0.000995; $__Temp_b_telescope = 273; $__Temp_b_analog = 273+1.2; $__Temp_b_digital = 273+0.5; $__Temp_b_power = 273+0.5; $__Temp_b_ref = 273+0.1; $__RadExist = 1; $__RadHighOffset = 23; $__RadMedOffset = 27; $__RadLowOffset = 30; } elsif ($SN == 8) { # The first engineering unit $__BiasVoltThin = 0.1070; $__BiasVoltThick = 0.1108; $__LLDThin = 0.001; $__LLDThick = 0.001; $__LLDThin_offset = 0; $__LLDThick_offset = 0; $__Tprt_a = 100; # no resistor installed $__Purge_a = 0; # no sensors installed } elsif ($SN == 9) { # NB that s/n 9 became s/n 10 $__V28bus = 0.009812; $__I28bus = 0.000200; $__BiasVoltThin = 0.1011; $__BiasVoltThick = 0.1003; $__Tprt_a = 100; # just a fixed 2K resistor for continuity $__Temp_b_telescope = 273+7.4; $__Temp_b_analog = 273+2.8; $__Temp_b_digital = 273+3.3; $__Temp_b_power = 273+0.7; $__Temp_b_ref = 273-1.6; $__Purge_b = 300/(2*300); # no 250 ohm series protection } elsif ($SN == 10) { # NB that s/n 9 became s/n 10 $__V28bus = 0.01049; # originally 0.01032; $__V28bus_offset = -1.7; $__I28bus = 0.000206; $__BiasVoltThin = 0.1011; $__BiasVoltThick = 0.1003; $__Tprt_a = 100; # just a fixed 2K resistor for continuity $__Temp_b_telescope = 273+7.4; $__Temp_b_analog = 273+2.8; $__Temp_b_digital = 273+3.3; $__Temp_b_power = 273+0.7; $__Temp_b_ref = 273+1.6; $__RadExist = 1; $__RadHighOffset = 18; $__RadMedOffset = 21; $__RadLowOffset = 21; $__Purge_d = 63; # CFH offset } else { print STDERR "Missing calibration constants for Serial Number $SN\n"; $SN = "*" . $SN . "*"; } return $SN; } ######################################################################## # Process all the command line arguments # Open input and output files # NB that output must be closed and write protected before progam exit! ######################################################################## sub Setup { $Verbose = 0; # assume quiet mode to start my $foo; while ( $foo = shift(@ARGV) ) { if ( $foo =~ /^-[hH]/ ) { $Verbose++; &Help; } if ( $foo =~ /^-[rR]/ ) { # Handle swap in rad sensor lines $RadFlip++; next; } if ( $foo =~ /^-[vV]/ ) { $Verbose++; next; } print STDERR "Unknown argument: $foo\n"; &Help; } print STDERR "$Version\n" if ($Verbose); $| = 1; # don't buffer stdout } ######################################################################## # Pod follows ######################################################################## =for html CRaTER -- calcurve =head2 NAME calcurve -- Convert CRaTER raw housekeeping to engineering units =head2 USAGE calcurve [-h] [-v] =head2 FLAGS -h help message -r flip dosimeter RadLo and RadMed channels -v verbose display =head2 DESCRIPTION Receives CRaTER telemetry in B format on STDIN and converts analog housekeeping to decimal/hex/engineering/units on STDOUT. See the B man page for a list of applicable mnemonics. Adds mnemonic \"P28bus\" as calculation of V28bus * I28bus. Interogates instrument serial number to determine coefficients; returns *sn* if no unit-specific coefficients are found. There was a period of time when the Engineering Unit (SN10) had its RadLow and RadMed channels of the dosimeter flipped. The B<-r> flag accounts for that situation. Non-analog telemetry is passed through unchanged. =head2 BUGS =head2 SEE ALSO rtlm.tcl, command.tcl, house.tcl =head2 AUTHOR Bob Goeke =head2 RCS Information $Id: calcurve,v 2.38 2008/10/22 13:50:35 goeke Exp goeke $ =cut ######################################################################## # history follows ######################################################################## # $Log: calcurve,v $ # Revision 2.38 2008/10/22 13:50:35 goeke # Minor adjustment on S/C bus current offset; fixed power calculation # to read zero if current display is zero # # Revision 2.37 2008/07/28 15:03:26 goeke # Added -r flag # # Revision 2.36 2008/07/14 13:58:55 goeke # Dosimeter /does/ exist in sn10 # # Revision 2.35 2008/06/30 14:26:26 goeke # Add spacecraft bus data for voltage, current, command, power # # Revision 2.34 2008/04/10 19:15:52 goeke # Entry error in Rad[Med,Low]Offset # # Revision 2.33 2008/02/27 15:54:38 goeke # Update input bus voltage for SN10 # # Revision 2.33 2008/02/20 21:07:37 goeke # Update SN10 28VDC monitor # # Revision 2.32 2007/11/06 16:28:11 goeke # Added SN1 temperature correctins # Added n/a criteria for 28VDC monitors and power # # Revision 2.31 2007/10/05 20:27:54 goeke # Adjusted sn02 temps to agree with RTD resistance measurement. # Trimmed Temp display to be xx.x rather than yy.yy # # Revision 2.30 2007/09/19 19:41:26 goeke # Update sn2 values for biascurrent and v28bus # Added v28offset # Modify units message/supress value for absent sn # # Revision 2.29 2007/08/28 19:37:32 goeke # Change scale to 8mv/bit for radiation dosimeter outputs; add offsets # # Revision 2.28 2007/08/23 18:13:02 goeke # Added offsets constants to radiation monitor; put in numbers for sn2 # # Revision 2.27 2007/08/07 14:11:27 goeke # Simplify purge equation # # Revision 2.26 2007/07/03 18:35:39 goeke # initial calibration of sn02 # # Revision 2.25 2007/06/28 15:57:12 goeke # Redo equation for purge with 250 ohm fixed resistor and temp compensation # # Revision 2.24 2007/06/07 14:57:43 goeke # Initial values for sn01 digital board updated # # Revision 2.23 2007/05/24 12:50:45 goeke # Fix label bug for bias voltages # Change purge equation to handle 250 ohm series resistor # # Revision 2.22 2007/05/14 13:40:04 goeke # Add 28bus power calculation # # Revision 2.21 2007/05/03 17:04:41 goeke # Fixed typo in default telescope temp offset # # Revision 2.20 2007/04/06 18:37:35 goeke # Added POD # # Revision 2.19 2007/03/30 13:38:48 goeke # Revise purge constants for s/n 10 and 300 ohm thermistor # # Revision 2.18 2007/03/27 17:46:29 goeke # Make note if no sn match is found in coefficient switch. # # Revision 2.17 2007/03/14 13:08:19 goeke # Fix logic error in calculation of dosimeter outputs # # Revision 2.16 2007/03/13 17:52:47 goeke # Change from sn 9 to sn 10 # # Revision 2.15 2007/02/23 18:57:07 goeke # Indicate saturated A/D in engineering units display # # Revision 2.14 2007/02/13 20:32:16 goeke # Calibrate room temperature for AD590s on S/N 9 # # Revision 2.13 2007/02/09 16:41:31 goeke # Install equation for purge; s/n 9 still needs calibration # # Revision 2.12 2007/01/29 14:49:23 goeke # Fix biasvoltthick cal factor for s/n 9 # # Revision 2.11 2007/01/29 14:45:17 goeke # Adjust cal factors for Bias Voltages # # Revision 2.10 2007/01/26 21:24:15 goeke # Redid Dosimeter correction factors and logic # # Revision 2.8 2007/01/09 21:39:16 goeke # Update LLD coversions to bipolar housekeeping design # # Revision 2.7 2007/01/04 16:50:39 goeke # Fix units, change scale factor for I28bus # # Revision 2.6 2006/10/05 18:03:23 goeke # Update detector bias current constants per latest ICD # # Revision 2.5 2006/10/02 19:35:51 goeke # Put in some particulars for S/N 8 # # Revision 2.4 2006/09/13 21:09:05 goeke # Redid mnemonics to be compatible with Rev B of DataICD # # Revision 2.3 2006/08/18 17:54:19 goeke # Was clipping SerialNumber out of the data stream. # # Revision 2.2 2006/08/18 15:07:21 goeke # Reformat help message # # Revision 2.1 2006/08/17 20:23:18 goeke # Switch output format to name-decimal-hex-eng-units # (No signals for format shift here.) # # Revision 1.5 2006/08/17 19:03:24 goeke # Fix format for V2p5ref # # Revision 1.4 2006/08/16 19:54:28 goeke # Workable version. # # Revision 1.3 2006/08/15 21:01:46 goeke # Still interim; mostly converted to new form in switch # # Revision 1.2 2006/08/15 20:35:35 goeke # Interim version; only V28bus works properly; # Outputs eng units, hex, and decimal with kill -HUP switch # # Revision 1.1 2006/08/14 20:37:13 goeke # Initial revision # #