pro nis_c_dark, seq_in, noise_mode, voltcor, $ volterr, header_in, filename, seq_out, vid, sourcedir, outdir, $ verbose, exit1 ; SUB-PROGRAM of nis_proc ; ; ABSTRACT ; Removes dark spectra from nis data. Most darks are interleaved with spectra. ; this program separates the dark spectra in to a seperate array that ; gets saved as a separate file, interpolates the dark spectra so that ; each data spectrum has a corresponding dark, and then subtracts the ; dark. ; This procedure is for dark_mode 0 - interleaved darks ; ; INPUTS ; seq_in - sequence of averaged spectra from nis_c_div ; noise_mode - how spectra noise is determined ; 0 = noise determined from average of all dark spectra in ; sequence (Default) ; 1 = initial noise from extant file of 300 averaged darks ; header_in - header from input FITS file. to be modified and saved ; with dark data as its own FITS file. ; vid - Version ID of niscal ; sourcedir - source directory for NISCAL programs and data ; verbose - Toggle description of events std output. ; voltcor - Motor Voltge correction from table ; volterr - Motor Voltge noise from table ; ; OUTPUTS ; dark_arr - array of dark-only spectra, saved to library ; seq_out - array of data spectra with dark subtracted ; output file .dko which is 179 columns long, one row for each dark ; measurement. Standard CNFF format. ; exit1 - error kickout ; ; USES ; sxpar - creads header data for keyword ; sxaddpar - changes header for dark only spectra ; fxaddpar - similar to sxaddpar ; writefits - save dark data in dark library ; eprop_sumdif - to propagate error from dark subtraction ; ; HISTORY ; Created 9/17/97 by N. R. Izenberg ; Modified 11/24/97 (NRI) to include error propagation ; 12/16/97 (NRI) to include sequnce dark current error as default error ; 12/19/97 (NRI) fixed and improved header modification commands ; 12/30/95 (NRI) V1.1 directory structure ; 01/19/98 (NRI) add sourcedir ; 02/05/98 (NRI) Repair: change sign of motor volt correction. ; 07/14/98 (NRI) v2.0 compliant. CNFF ; 08/20/98 (NRI) fixed shutter telltale column error(col 10 = seq_in 9) ; 09/15/98 (NRI) Add set to zero for values that are less than zero ; after dark subtraction. For calmodes greater ; than .dks ; 11/11/98 (NRI) Add fix for shutter-closed sequences ; 02/03/00 (NRI) v3.7 Change in method of dark subtraction from ; sequence-based to MET-based. This should ; alleviate problems when missing data throws ; off the commanded interleave step ; 02/17/00 (NRI) v3.9 Kill setting negative data to zero. This ; interfered with dark analysis by artificially ; removing variability in the data ; 06/15/00 (NRI) v4.2 Convert size commands to NAXIS call ; Change Motor Voltage correction ; from single file to table driven files ; 07/19/01 (NRI) v5.0 Compliant (CNISF changes mostly) ; NOTES ; From NIS sequence data: ; IDL columns 1 and 2 define MET high and low word ; CNISF 5.0 column 9 = shutter in/out (0 = in) ; CNISF 5.0 Data is 131:194 for Calibration ; CNISF 5.0 Data is 195:258 for Noise ;------------------------------------------------------------------------------ ; Main err_in=seq_in(195:258,*) header=header_in if verbose eq 1 then begin print," >>>> Noise Mode = "+ strcompress(string(noise_mode),/remove_all) endif NAX=sxpar(header,'NAXIS2') Fname=sxpar(header,'NEAR-003') FMET=double(strmid(fname,3,9)) ;MET of start spectrum ;Find total number of data and dark spectra based on shutter open/closed ;----------------------------------------------------------------------- total_spectra = total(seq_in(9,*) eq 1) ;Separate Dark spectra from Data spectra in sequence. ;---------------------------------------------------- total_dark = total(seq_in(9,*) eq 0) ;Get METs and make file for dark_METs and data_METS ;-------------------------------------------------- mets=lonarr(NAX) for m=0,NAX-1 do begin met_hi=double(seq_in(1,m)) met_lo=double(seq_in(2,m)) if (met_lo lt 0) then met_lo=65536.d0+met_lo mets(m)=long(met_hi*65536.d0+met_lo) endfor dark_mets=lonarr(total_dark) data_mets=lonarr(total_spectra) case total_dark of 0: begin print,"*********** There are no darks in this sequence. " print,"***ERROR*** Use Alternative Dark Mode (1, 5-8)" print,"***ERROR*** You'll need preceeding and following sequences of " print,"*********** dark-only spectra for proper calibration." print,"Exiting..." exit1=1 goto,kickout end NAX: begin print,"*********** This is a dark-only (shutter closed) sequence" print,"***NOTE!*** Program will subtract mean dark from each spectrum " print,"*********** and treat otherwise as regular data." total_spectra=total_dark dark_arr=seq_in dark_err=seq_in(195:258,*) seq_out = seq_in end else : begin ; initialize dark-only and spectra-only variables dark_arr = fltarr(259,total_dark) dark_err = fltarr(64,total_dark) seq_out = fltarr(259,total_spectra) ;populate dark and spectra variables spect_count = 0 dark_count = 0 for j = 0,NAX-1 do begin case seq_in(9,j) of 0:begin dark_arr(*,dark_count) = seq_in(*,j) dark_err(*,dark_count) = seq_in(195:258,j) dark_mets(dark_count) = mets(j) dark_count = dark_count+1 end 1:begin seq_out(*,spect_count) = seq_in(*,j) data_mets(spect_count) = mets(j) spect_count = spect_count +1 end else: print,"WARNING! INVALID SHUTTER POSITION" endcase endfor endelse endcase ; 2. Apply voltage correction ;---------------------------- for m= 0,total_dark-1 do begin dark_arr(131:194,m)=dark_arr(131:194,m)+voltcor dark_err(*,m)=eprop_sumdif(dark_err(*,m),volterr) endfor ; Initially, dark_err is determined by a lookup table from an ; average of 300 dark spectra. If the noise_mode 0 is selected, the noise ; will be the average of the dark spectra from the sequence curently ; being calibrated. The advantage is that the noise is now closely ; associated with the spectra in time. The disadvantage is that less ; than 300 dark measurements will probably result in higher noise, as the ; standard deviation of a smaller number of spectra will be higher. ;---------------------------------------------------------------------------- if noise_mode eq 0 then begin mean_err=fltarr(64) for n=0,63 do begin dsz=size(dark_arr) if dsz(0) ne 1 then mean_err(n)=stdev(dark_arr(131+n,*)) else $ mean_err(n)=dark_arr(131+n) endfor for o=0,total_dark-1 do begin dark_err(*,o)=mean_err endfor endif ; 3. Save motor voltage corrected darks to Dark directory as FITS file. ;----------------------------------------------------------------------- dark_out=dark_arr dark_out(195:258,*)=dark_err dsz=size(dark_out) ; Change the header ;------------------ sxaddpar, header, 'AUTHOR', 'N. R. Izenberg' sxaddpar, header, 'NAXIS2', dsz(2) date1=sstrr( bin_date(systime(0)) ) date_now=date1(1)+'/'+date1(2)+'/'+strmid(date1(0),2,2) sxaddpar, header, 'NEAR-003', filename+'.dko' ; Name of darkfile sxaddpar, header, 'NEAR-004', date_now ; date of file sxaddpar, header, 'NEAR-006', 'nis_c_dark.pro' ; creator program sxaddpar, header, 'NEAR-007', vid ; Version # fxaddpar, header, 'HISTORY', ' This is a file of dark spectra only' fxaddpar, header, 'HISTORY', ' created by nis_c_dark.pro on '+date_now fxaddpar, header, 'HISTORY', ' sub-process of nis_proc.pro' fxaddpar, header, 'HISTORY', ' Sub-process of niscal.pro' ;mfilename=strmid(filename,0,strlen(filename)-4) mfilename=filename writefits,outdir+mfilename+'.dko', dark_arr, header if verbose eq 1 then begin print," >>>> Dark spectra from this sequence saved as: " print," >>>> ",outdir+filename+'.dko' endif ;3b if the sequence is dark only, sutract the mean and kickout. ;--------------------------------------------------------------- if total_dark eq NAX then begin darkav=fltarr(64) for nn=0,63 do begin darkav(nn) = mean(dark_arr(131+nn,*)) endfor for aa=0,NAX-1 do begin seq_out(131:194,aa) = seq_in(131:194,aa)-darkav seq_out(195:258,aa) = mean_err endfor goto,kick1 endif ;Systematic read/interpolate/subtract ;Use initial dark as preceeding and following dark for subtraction. ;Read through spectrum by spectrum, subtract appropriate interpolated dark. ;--------------------------------------------------------------------------- ;Read spectrum. ; determine preceeding and following dark METs ; If no preceeding dark (start of sequence), use following dark ; If no following dark (end of sequence w. gap), use preceeding dark ; interpolate dark for that spectrum based on time elapsed (some kind of weighted mean ; subtract dark from data for l = 0,total_spectra-1 do begin Seq_time=data_mets(l) noprec=0 nopost=0 prec = abs((dark_mets * (dark_mets lt seq_time)) - seq_time) if min(prec) gt 1.e4 then begin d1=dark_arr(131:194,0) e1=dark_err(*,0) noprec=1 endif else begin prec2 =total(findgen(total_dark) * (prec eq min(prec))) d1=dark_arr(131:194,prec2) e1=dark_err(*,prec2) prec_time=dark_mets(prec2) endelse post = abs((dark_mets * (dark_mets gt seq_time)) - seq_time) if min(post) gt 1.e5 then begin d2=dark_arr(131:194,total_dark-1) e2=dark_err(*,total_dark-1) nopost=1 endif else begin post2=total(findgen(total_dark) * (post eq min(post))) d2=dark_arr(131:194,post2) e2=dark_err(*,post2) post_time=dark_mets(post2) endelse ;Interpolate b/t d1 and d2, and subtract dark from data if nopost eq 1 or noprec eq 1 then begin ; subtract un-interped dark from data seq_out(131:194,l)=seq_out(131:194,l)- d1 seq_out(195:258,l)=eprop_sumdif(err_in(*,l),e1) ;print,dark_mets(0),seq_time, dark_mets(total_dark-1) endif else begin elapse=post_time-prec_time time1=seq_time-prec_time time2=post_time-seq_time int_dark= (d1*(elapse-time1)+ d2*(elapse-time2))/elapse int_err=eprop_sumdif(e1*(elapse-time1),e2*(elapse-time2))/elapse seq_out(131:194,l)=seq_out(131:194,l)-int_dark seq_out(195:258,l)=eprop_sumdif(err_in(*,l),int_err) ;print,l, prec_time, seq_time,post_time,elapse, time1, time2 ;wait,.1 endelse endfor ;Change header_data to reflect the spectra-only data sxaddpar, header_in, 'NAXIS2', total_spectra kick1: if verbose eq 1 then print,' STEP 3: background removed' kickout: return end