#!/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