;+ ; Procedure: thm_cal_hsk ; ; Purpose: Converts housekeeping data into physical units. ; Generates data structure for performing conversion. ; ; Inputs: ; in_names: The list of tplot names that should be converted into physical units, ; tvars not on this list will not be modified ; ; Outputs: ; out_names: Set a named variable to this keyword to return the output variable names ; ; Notes: ; 1. If calibrating use dprint,setdebug=5 to see detailed calibration information ; 2. Some exceptions to the DBX style calibrations are hard-coded into the code, ; If updating calibrations, be sure to check the arrays "naming_corrections" and "group_names" ; to verify that they work correctly with modifications. ; 3. Overall, the calibration is a two part process. A. Tables are pre-generated using DBX records when thm_cal_hsk_make_tables is called. ; These tables completely describe the conversions, with the exception of the exceptions named in #2. The conversion tables ; are loaded and used to transform the data when thm_cal_hsk is called. The end-user should never have to call ; thm_cal_hsk_make_tables ; ; $LastChangedBy: pcruce $ ; $LastChangedDate: 2009-07-13 14:47:13 -0700 (Mon, 13 Jul 2009) $ ; $LastChangedRevision: 6425 $ ; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/thmsoc/tags/tdas_8_00/idl/themis/spacecraft/thm_cal_hsk.pro $ ;- ;helper function, properly converts dbx colors for discrete conversions into themis colors function thm_cal_hsk_conv_colors,in_colors compile_opt idl2,hidden colors = strlowcase(in_colors) out_colors = lonarr(n_elements(in_colors)) col_names = ['black','red','green','yellow','blue','magenta','cyan','white'] col_perm = [0,6,4,5,2,1,3,255] for i = 0,7 do begin idx = where(colors eq col_names[i] or colors eq strtrim(i,2),c) if c gt 0 then begin out_colors[idx] = col_perm[i] endif endfor return,out_colors end ;helper function modularizes repeated record extraction code pro thm_cal_hsk_get_records,file_strings,record_type,record_length,out_records compile_opt idl2,hidden ;split the file into records by type ;and split the records into individual fields record_types = strlowcase(strmid(file_strings,0,3)) idx = where(record_types eq record_type,rec_num) if rec_num gt 0 then begin records = strarr(rec_num,record_length) for i = 0,rec_num-1 do begin rec = strtrim(strsplit(file_strings[idx[i]],'|',/extract,/preserve_null),2) records[i,*] = rec[0:record_length-1] endfor if ~keyword_set(out_records) then begin out_records = records endif else begin out_records = [out_records,records] endelse endif end ;helper function modularizes repeated file read code pro thm_cal_hsk_read_file,path,lines compile_opt idl2,hidden s = '' line_num = file_lines(path) lines = strarr(line_num) ;read the file into an array openr,lun,path,/get_lun for i = 0,line_num-1 do begin readf,lun,s lines[i] = strtrim(s,2) endfor close,lun free_lun,lun ;remove all lines that are non-records first = strmid(lines,0,1) idx = where(first ne '#' and first ne '') lines = lines[idx] end ;helper function swaps names of telemetry conversions, if appropriate function thm_cal_hsk_correct_name,in_name compile_opt idl2,hidden ;some of the names used in the CDF differ from the DBX records, this associative array identifies the transformations naming_corrections = [['imon_p25vd','ivmon_p25vd','imon_efi_board','imon_efi_x','imon_efi_y','imon_efi_z','idcb3v','prmy_htri','scnd_htri'],$ ;Name in CDF ['imon_p2_5vd','ivmon_p2_5vd','imon_efiboard','imon_efix','imon_efiy','imon_efiz','idcb_3v','iprmy_htri','iscnd_htri']] ;Name in DBX record idx = where(in_name eq naming_corrections[*,1],c) if c eq 1 then begin return,naming_corrections[idx,0] endif else begin return,in_name endelse end ;this helper routine constructs a data structure that describes the conversion for each ;quantity that requires calibration. The structure is stored in an IDL sav, and distributed ;It is constructed from the THEMIS MOC dbx records pro thm_cal_hsk_make_tables,dbxpaths,outpath compile_opt idl2,hidden ;Read raw records from file for i = 0,n_elements(dbxpaths)-1 do begin thm_cal_hsk_read_file,dbxpaths[i],file_strings ;get tlm records thm_cal_hsk_get_records,file_strings,'tlm',15,tlm_records ;get alg records thm_cal_hsk_get_records,file_strings,'alg',12,alg_records ;get dsc records thm_cal_hsk_get_records,file_strings,'dsc',9,dsc_records ;get xpr records thm_cal_hsk_get_records,file_strings,'xpr',7,xpr_records endfor ;turn records into conversions for i = 0,(dimen(tlm_records))[0]-1 do begin tlm_record = reform(tlm_records[i,*]) tlm_name = thm_cal_hsk_correct_name(strlowcase(tlm_record[1])) tlm_conv = tlm_record[11] ;these 'if' statements look a little weird because it takes a bit of finangling to do assignments inside conditional in idl if n_elements((idx = where(tlm_conv eq alg_records[*,1],c))) ne 1 || c gt 0 then begin alg_record = reform(alg_records[idx,*]) coefs = alg_record[3:10] cf_idx = where(~is_numeric(coefs),cf_num) if cf_num ne 0 then begin coefs[cf_idx] = '0' endif conversions = csvector({type:'alg',name:tlm_name,conversion:coefs},conversions) endif else if n_elements((idx = where(tlm_conv eq dsc_records[*,1],c))) ne 1 || c gt 0 then begin dsc_labels = dsc_records[idx,2] dsc_mins = float(dsc_records[idx,4]) dsc_maxs = float(dsc_records[idx,5]) dsc_colors = thm_cal_hsk_conv_colors(dsc_records[idx,6]) conversions = csvector({type:'dsc',name:tlm_name,labels:dsc_labels,mins:dsc_mins,maxs:dsc_maxs,colors:dsc_colors},conversions) if c gt 64 then begin dprint,'Warning! Cannot do discrete conversion with more than 64 bits' endif endif else if n_elements((idx = where(tlm_conv eq xpr_records[*,1],c))) ne 1 || c gt 0 then begin xpr_record = reform(xpr_records[idx,*]) conversions = csvector({type:'xpr',name:tlm_name,conversion:xpr_record[3]},conversions) endif ; else begin ;no conversion ; ; conversions = csvector({type:'none',name:tlm_name},conversions) ; ; endelse endfor save,conversions,filename=outpath end ;platform independent mechanism to find file where conversions are stored pro thm_cal_hsk_path,cpath compile_opt idl2,hidden rt_info = routine_info('thm_cal_hsk_path',/source) cpath = file_dirname(rt_info.path) + '/thm_hsk_conversions.sav' end ;this routine substitutes '_conv' in place of '_raw' in a name function thm_cal_hsk_sub_name,name compile_opt idl2,hidden if strmatch(name,'*_raw') then begin return,strmid(name,0,strlen(name)-strlen('_raw')) + '_cal' endif else begin return,name+'_cal' endelse end ;this routine works like strput, but it ;can insert into multiple strings, with multiple ;substrings, and multiple positions. function thm_cal_hsk_strput_vec,str,sub,pos compile_opt idl2,hidden front = strmid(str,0,pos) back = strmid(str,pos+strlen(sub),strlen(str)) if ndimen(front) ne 1 then begin fdim = min(dimen(front)) front = front[lindgen(fdim),lindgen(fdim)] endif if ndimen(back) ne 1 then begin bdim = min(dimen(back)) back = back[lindgen(bdim),lindgen(bdim)] endif return,front+sub+back end ;converts the string representation of ;a coeficient into a double precision representation ;It does this by either replacing the 'e' with a 'd' ;in exponential notation 1e2 -> 1d2 ;or appending a 'd', 1.0 -> 1.0d function thm_cal_hsk_alg_double,coefs compile_opt idl2,hidden out = coefs pos = stregex(coefs,'e',/fold_case) idx = where(pos ne -1,c,complement=cidx,ncomplement=nc) if c ne 0 then begin out[idx] = thm_cal_hsk_strput_vec(coefs[idx],'d',pos[idx]) endif if nc ne 0 then begin out[cidx] += 'd' endif return,out end ;code handles a special case where names were grouped during raw preprocessing, and thus, ;don't match conversion names. Unfortunately, we can't use split_vec because it doesn't ;produce the correct output names ;WARNING: mutates t_names pro thm_cal_hsk_split_groups,t_names,groups,splits=splits compile_opt idl2,hidden for i = 0,n_elements(groups)-1 do begin split_name = strfilter(t_names,'*'+groups[i]+'_raw') if ~keyword_set(split_name) then continue for j = 0,n_elements(split_name)-1 do begin get_data,split_name[j],data=d,dlimit=dl,limit=l dim = dimen(d.y) if ndimen(d.y) ne 2 then continue dprint,dlevel=5,'Splitting variable "' + split_name[j] + '" into components' stem = strmid(split_name[j],0,strlen(split_name[j])-(strlen('_raw')+strlen(groups[i]))) comp_names = stem+groups[i]+strtrim(lindgen(dim[1])+1,2)+'_raw' if n_elements(t_names) eq 1 then begin t_names = [comp_names] endif else begin t_names = [ssl_set_complement([split_name[j]],t_names),comp_names] endelse splits = csvector({in_name:split_name[j],out_name:comp_names},splits) for k = 0,dim[1]-1 do begin store_data,comp_names[k],data={x:d.x,y:d.y[*,k]},dlimit=dl,limit=l endfor endfor endfor end ;reforms the variables split by thm_cal_hsk_split_groups, into ;their calibrated output pro thm_cal_hsk_unsplit_groups,splits compile_opt idl2 if ~keyword_set(splits) then return len = csvector(splits,/length) for i =0,len-1 do begin split = csvector(i,splits,/read) out_name = thm_cal_hsk_sub_name(split.in_name) in_name = strarr(n_elements(split.out_name)) for j = 0,n_elements(in_name)-1 do begin in_name[j] = thm_cal_hsk_sub_name(split.out_name[j]) endfor if ~keyword_set(tnames(in_name[0])) then begin dprint,dlevel=5,'Problem unsplitting "' + split.in_name + "' endif else begin dprint,dlevel=5,'Unsplitting "' + split.in_name + '" into "' + out_name + '"' endelse get_data,in_name[0],data=d,dlimit=dl,limit=l outd = {x:d.x,y:make_array(n_elements(d.y),n_elements(in_name),type=size(d.y,/type))} for j = 0,n_elements(in_name)-1 do begin get_data,in_name[j],data=d outd.y[*,j] = d.y endfor store_data,out_name,data=outd,dlimit=dl,limit=l endfor end ;this routine actually does the conversion on each specific variable pro thm_cal_hsk_do_cal,in_name,conv compile_opt idl2,hidden out_name = thm_cal_hsk_sub_name(in_name) if conv.type eq 'alg' then begin str_name = '"' + in_name + '"' coefs = thm_cal_hsk_alg_double(conv.conversion) ;JWL recommends using polynomial of different form (a + x*(b+x*(c))) ;to prevent computational error during subtractions ; conv_str = '"'+out_name+'"=' ; ; conv_str += conv.conversion[0] ; ; for i = 1,7 do begin ; conv_str += '+' + conv.conversion[i] + '*"' + in_name + '"^' + strtrim(i,2) ; endfor ;This polynomial string is easier to construct working right to left conv_str = '(' + coefs[7] + ')' for i = 6,0,-1 do begin conv_str = '(' + coefs[i] + '+' + str_name + '*' + conv_str + ')' endfor conv_str = '"'+out_name+'"=' + conv_str ;print,conv_str dprint,dlevel=5,'ALG Conversion: ' + conv_str calc,conv_str,err=err if is_struct(err) then begin dprint,"Error in polynomial conversion for: " + in_name endif endif else if conv.type eq 'dsc' then begin get_data,in_name,data=d,limit=l,dlimit=dl dim = dimen(d.y) outd = {x:d.x,y:ulon64arr(dim)} ;discrete data is often not a bit packed encoding, but a range-based encoding ;this converts between the two, as bitplot is the most effective way of ;view hsk discrete data from within tplot for i = 0,n_elements(conv.mins)-1 do begin idx = where(d.y ge conv.mins[i] and d.y le conv.maxs[i],c) if c gt 0 then begin outd.y[idx] = ishft(1ULL,i) endif endfor dprint,dlevel=5,'DSC Conversion: "' + out_name + '" <-- "' + in_name + '"(No closed form for discrete conversion)' store_data,out_name,data=outd,limit=l,dlimit=dl options,out_name,/def,labels=conv.labels,colors=conv.colors,tplot_routine='bitplot',numbits=n_elements(conv.mins),psyms=6,symsize=.3 endif else if conv.type eq 'xpr' then begin conv_str = '"' + out_name + '"=' conv_str += strjoin(strsplit(conv.conversion,'x',/extract),'"'+in_name+'"') ; print,conv_str dprint,dlevel=5,'XPR Conversion: ' + conv_str calc,conv_str,err=err if is_struct(err) then begin dprint,"Error in expression conversion for: " + in_name ; stop endif endif else begin dprint,"Error, Could not apply conversion for: " + in_name ; stop endelse end pro thm_cal_hsk,in_names,out_names=out_names compile_opt idl2 t_names = in_names dprint,'Beginning housekeeping conversion for ' + strtrim(n_elements(in_names),2) + ' values' ;names of variables that need to be split into components to perform uniform conversions group_names = ['iefi_ibias','iefi_usher','iefi_guard'] thm_cal_hsk_split_groups,t_names,group_names,splits=splits ;itm_fifostate 2x? ;iatt_state,idhsk_state ;prmy ;load conversion data from IDL save file thm_cal_hsk_path,convpath restore,convpath conv_num = csvector(conversions,/length) ;runs though the full list of conversions for i = 0,conv_num-1 do begin conversion = csvector(i,conversions,/read) ; print,conversion.name ;get the names that match this conversion idx = where(strmatch(t_names,'*'+conversion.name+'_raw',/fold_case),c,complement=cidx,ncomplement=nc) if c eq 0 then begin continue endif c_names = t_names[idx] for j = 0,n_elements(c_names)-1 do begin thm_cal_hsk_do_cal,c_names[j],conversion endfor ;if no variables are left, then we're done if nc eq 0 then begin t_names ='' break endif ;otherwise remove converted variables from the list t_names = t_names[cidx] endfor if keyword_set(t_names) then begin for i = 0,n_elements(t_names)-1 do begin out_name = thm_cal_hsk_sub_name(t_names[i]) dprint,dlevel=5,'Identity Conversion: "' + out_name + '" = "' + t_names[i] + '"' copy_data,t_names[i],out_name endfor endif thm_cal_hsk_unsplit_groups,splits out_names = in_names for i = 0,n_elements(in_names)-1 do begin out_names[i] = thm_cal_hsk_sub_name(in_names[i]) endfor dprint,'Housekeeping conversion completed' end