;+ ; This procedure retrieves and calibrates a frequency switched ; scan. ; ;
This code could be used as a template for the user who may wish ; to develop more sophisticated calibration schemes. The spectrum is ; calibrated in Ta (K) by default. Other recognized units are Ta* and ; Jy. ; ;
Summary ;
Parameters ;
; The only required parameter is the scan number. Arguments to ; identify the IF number, polarization number, and feed number are ; optional. ;
;
If ifnum, fdnum, or plnum are not supplied then the lowest ; values for each of those where data exists (all combinations may not ; have data) will be used, using any user-supplied values. The value ; of ifnum is determined first, followed by fdnum and finally plnum. If a ; combination with data can not be found then showiftab ; is used to show the user what the set of valid combinations are. ; The summary line includes the ifnum, fdnum, and plnum used. ;
; Tsys and Available Units ;
; The procedure calculates Tsys based on the Tcal values ; and the data. The user can override this calculation by ; entering a zenith system temperature. The procedure will then correct the ; user-supplied Tsys for the observed elevation. If the data are ; calibrated to Ta* or Jy, additional parameters are used. A zenith ; opacity (tau) may be specified, and an aperture efficiency may be ; specified. The user is strongly encouraged to enter values for ; these calibration parameters, but they will be estimated if none are ; provided. The user can also supply a mean tcal using the tcal ; keyword. That will override the tcal found in the data. ;
; Smoothing the Reference Spectra ;
; A parameter called smthoff can be used to smooth the reference ; spectrum in dofreqswitch. In certain cases this can improve the ; signal to noise ratio, but it may degrade baseline shapes and ; artificially emphasize spectrometer glitches. Use with care. A ; value of smthoff=16 is often a good choice. ;
; Weighting of Integrations in Scan Average ;
; By default, the averaging of integrations is weighted using tsys, ; exposure, and frequency_resolution as described in the dcaccum ; documentation. To give all integrations equal weight instead of the ; default weighting based on Tsys, use the /eqweight keyword. ;
; If the data were taken with out-of-band frequency switching then no folding ; will be done and the nofold argument is ignored. ;
; Using or Ignoring Flags ;
; Flags (set via flag) can be selectively ; applied or ignored using the useflag and skipflag keywords. Only one of ; those two keywords can be used at a time (it is an error to use both ; at the same time). Both can be either a boolean (/useflag or /skipflag) ; or an array of strings. The default is /useflag, meaning that all flag ; rules that have been previously set are applied when the data is ; fetched from disk, blanking data as described by each rule. If ; /skipflag is set, then all of the flag rules associated with this data ; are ignored and no data will be blanked when fetched from disk (it ; may still contain blanked values if the actual values in the disk ; file have already been blanked by some other process). If useflag is a ; string or array of strings, then only those flag rules having the ; same idstring value are used to blank the data. If skipflag is a ; string or array of strings, then all flag rules except those ; with the same idstring value are used to blank the data. ;
; Dealing with flagged channels ;
; When individual channels are flagged in the raw data (e.g. VEGAS ; spikes at the expected spike locations) the data values at those ; channels are replaced with Not a Number when the data is read from ; disk. That presents a challenge when processing frequency switched ; data to avoid a spike appearing at the flagged channel locations ; after the fold step done by this procedure (unless nofold is ; selected). When the data are combined at the fold step, each ; channel data average is the weighted average (using Tsys) of two ; data values, each from the same sky frequency but from different ; original channels in the raw data. When indivual channels are ; flagged, that average can consist of just one finite value because ; the frequency shift will seldom lead to overlapping flagged ; channels. If there is any significant baseline structure across the ; bandpass then that single finite channel will be noticeably ; different from the local average of two channels. That will lead to ; a noticable spike (positive or negative) at the location of a ; flagged channel, which is exactly the behavior that flagging the ; channel was trying to avoid. ; ;
; This procedure offers two ways of dealing with flagged channels to ; avoid that problem. The default makes sure that both the original ; flagged channel and the corresponding channel in the other spectrum, ; after one of them has been shifted to align in frequency, is also ; flagged so that the final average has no finite values for that ; channel (i.e. it appears as a flagged channel). Alternatively, the ; blankinterp keyword can be used to tell the fold procedure to ; interpolate across all blanked values before doing any shifting and ; averaging. In the case of individually flagged channels, the ; blanked channel is replaced by the average of the two adjacent ; channels. This obviously adds a new data value at the previously ; unknown (flagged) channel but it can make downstream data processing ; simpler by not having to worry that some of the channels contain ; non-finite values. That may be important if the data are exported ; out of GBTIDL. Finally, the nomask keyword can be used to turn ; off this special handling (masking) of flagged channels before the ; average (where spikes may result). If blankinterp is used then ; nomask has no effect because the data are interpolated before the ; masking step happens. If nofold is used then the data are never ; masked or interpolated. ;
; Dealing With Duplicate Scan Numbers ;
; There are 3 ways to attempt to resolve ambiguities when the
; same scan number appears in the data source. The instance keyword
; refers to the element of the returned array of scan_info structures
; that scan_info returns. So, if scan 23
; appears 3 times then instance=1 refers to the second time that scan 23
; appears as returned by scan_info. The file keyword is useful if a
; scan is unique to a specific file and multiple files have been accessed
; using dirin. If file is specified and instance
; is also specified, then instance refers to the instance of that scan
; just within that file (which may be different from its instance within
; all opened files when dirin is used). The timestamp keyword is another
; way to resolve ambiguous scan numbers. The timestamp here is a string
; used essentially as a label by the monitor and control system and is
; unique to each scan. The format of the timestamp string is
; "YYYY_MM_DD_HH:MM:SS". When timstamp is given, scan and instance
; are ignored. If more than one match is found, an error is
; printed and this procedure will not continue.
;
; @param scan {in}{required}{type=integer} scan number
; @keyword ifnum {in}{optional}{type=integer} IF number
; (starting with 0). Defaults to the lowest value associated with data
; taking into account any user-supplied values for fdnum, and plnum.
; @keyword intnum {in}{optional}{type=integer} integration number,
; default is all integrations.
; @keyword plnum {in}{optional}{type=integer} Polarization number
; (starting with 0). Defaults to the lowest value with data after
; determining the values of ifnum and fdnum if not supplied by the
; user.
; @keyword fdnum {in}{optional}{type=integer} Feed number. Defaults
; to the lowest value with data after determining the value of ifnum
; if not supplied by the user and using any value of plnum supplied by
; the user.
; @keyword sampler {in}{optional}{type=string} sampler name, this is
; an alternative way to specify ifnum,plnum, and fdnum. When sampler
; name is given, ifnum, plnum, and fdnum must not be given.
; @keyword tsys {in}{optional}{type=float} tsys at zenith, this is
; converted to a tsys at the observed elevation. If not suppled, the
; tsys for each integration is calculated as described elsewhere.
; @keyword tau {in}{optional}{type=float} tau at zenith, if not
; supplied, it is estimated using get_tau
; tau is only used when the requested units are other than the default
; of Ta and when a user-supplied tsys value at zenith is to be used.
; @keyword ap_eff {in}{optional}{type=float} aperture efficiency, if
; not suppled, it is estimated using get_ap_eff
; ap_eff is only used when the requested units are Jy.
; @keyword smthoff {in}{optional}{type=integer} smooth factor for reference spectrum
; @keyword units {in}{optional}{type=string} takes the value 'Jy',
; 'Ta', or 'Ta*', default is Ta.
; @keyword nofold {in}{optional}{type=boolean} When set, getfs does not fold
; the calibrated spectrum. Buffer 0 then contains the result of
; (sig-ref)/ref while buffer 1 contains the result of
; (ref-sig)/sig, calibrated independently and averaged over all
; integrations. Only data container 0 will be shown on the plotter.
; Default is unset (folded result).
; @keyword blankinterp {in}{optional}{type=boolean} When set, blanks
; are replaced, before the fold step, by a linear interpolation
; using the finite values found in the two spectra. For isolated blanked
; channels, the replacement value is the average of the two adjacent
; channel values. This argument is ignored if nofold is used.
; @keyword nomask {in}{optional}{type=boolean} When set, turn off the
; masking of blank channels from each spectrum on to the other, after
; the shift, when folding the data. This may result in spikes at the
; location of blanked channels. This was the original behavior of this
; routine. This keyword is ignored if /nofold is used.
; @keyword eqweight {in}{optional}{type=boolean} When set, all
; integrations are averaged with equal weight (1.0). Default is unset.
; @keyword tcal {in}{optional}{type=float} Cal temperature (K) to use
; in the Tsys calculation. If not supplied, the mean_tcal value from
; the header of the cal_off switching phase data in each integration
; is used. This must be a scalar, vector tcal is not yet supported.
; The resulting data container(s) will have it's mean_tcal header value
; set to this keyword when it is set by the user.
; @keyword quiet {in}{optional}{type=boolean} When set, the normal
; status message on successful completion is not printed. This keyword will
; not affect error messages. Default is unset.
; @keyword keepints {in}{optional}{type=boolean} When set, the
; individual integrations are saved to the current output file
; (as set by fileout). This keyword is ignored if an integration is
; specified using the intnum keyword. Default is unset.
; @keyword useflag {in}{optional}{type=boolean or string}
; Apply all or just some of the flag rules? Default is set.
; @keyword skipflag {in}{optional}{type=boolean or string} Do not apply
; any or do not apply a few of the flag rules? Default is unset.
; @keyword instance {in}{optional}{type=integer} Which occurence
; of this scan should be used. Default is 0.
; @keyword file {in}{optional}{type=string} When specified, limit the search
; for this scan (and instance) to this specific file. Default is all files.
; @keyword timestamp {in}{optional}{type=string} The M&C timestamp associated
; with the desired scan. When supplied, scan and instance are ignored.
; @keyword status {out}{optional}{type=integer} An output value to indicate
; whether the procedure finished as expected. A value of 1 means there were
; no problems, a value of -1 means there were problems with the
; arguments before any data was processed, and a value of 0 means that
; some of the individual integrations were processed (and possibly
; saved to the output file if keepints was set) but there was a
; problem with the final average, and the contents of the PDC remain
; unchanged.
;
; @examples
; Typical use of getfs:
;
; getfs,76
; accum
; getfs,77
; accum
; ave
; show
;
;
;
; In the following example, the spectrum is not folded and the two components
; of the calibration are shown overlaid on the plotter. Then the data are
; folded 'by hand'. This example also shows how /skipflag can be used to
; ignore all previously set flags.
;
;
; getfs,76,/nofold,/skipflag
; oshow,1
; fold
;
;
; @uses accumave
; @uses accumclear
; @uses calsummary
; @uses check_calib_args
; @uses data_free
; @uses dcaccum
; @uses dcfold
; @uses dcscale
; @uses dcsetunits
; @uses dofreqswitch
; @uses find_scan_info
; @uses get_calib_data
; @uses set_data_container
; @uses showiftab
;
; @version $Id$
;-
pro getfs,scan,ifnum=ifnum,intnum=intnum,plnum=plnum,fdnum=fdnum,sampler=sampler,tsys=tsys,tau=tau,$
ap_eff=ap_eff,smthoff=smthoff,units=units,nofold=nofold,blankinterp=blankinterp,$
nomask=nomask,eqweight=eqweight,$
tcal=tcal,quiet=quiet,keepints=keepints,useflag=useflag,skipflag=skipflag,$
instance=instance,file=file,timestamp=timestamp,status=status
compile_opt idl2
status=-1
; basic argument checks
argsOK=check_calib_args(scan,ifnum=ifnum,intnum=intnum,plnum=plnum,fdnum=fdnum,sampler=sampler, $
eqweight=eqweight,units=units,quiet=quiet,keepints=keepints,useflag=useflag, $
skipflag=skipflag,instance=instance,file=file,$
timestamp=timestamp,tau=tau,ap_eff=ap_eff,ret=ret,info=info)
if not argsOK then return
if size(info,/type) ne 8 then return
; FS data must have 4 swiching states, 2 CAL states and 2 SIG states.
if info.n_switching_states ne 4 then begin
message,'This does not appear to be standard frequency switched data.',/info
if info.n_cal_states ne 2 then begin
message,'The number of cal states is not 2, as needed for this procedure.',/info
endif
if info.n_sig_states ne 2 then begin
message,'The number of sig states is not 2, as needed for this procedure.',/info
endif
return
end
; Get the requested data
data = get_calib_data(info, ret.ifnum, ret.plnum, ret.fdnum, ret.sampler, count, $
intnum=intnum, useflag=useflag, skipflag=skipflag)
if count le 0 then begin
message,"No data found, can not continue.",/info
return
endif
; from this point on, data contains data containers that must be
; freed whenever this routine returns to avoid memory leaks
; this test isn't available via scan_info, it has to wait until now
if data[0].switch_state ne 'FSWITCH' then begin
message,'This is apparently not frequency switched data. switch_state = ' + data[0].switch_state,/info
return
endif
; find the 4 types of data container
; signal with cal, signal without cal,
; reference with cal, referece without cal
sigwcal = where(data.cal_state eq 1 and data.sig_state eq 1, countSigwcal)
sig = where(data.cal_state eq 0 and data.sig_state eq 1, countSig)
refwcal = where(data.cal_state eq 1 and data.sig_state eq 0, countRefwcal)
ref = where(data.cal_state eq 0 and data.sig_state eq 0, countRef)
; Final sanity checks
; In this calibration, we calibrate each integration separately
; and then average the results. That means that we need the same
; number of data containers of each type, one per integration.
if n_elements(intnum) eq 1 then begin
expectedCount = 1
endif else begin
; find appropriate number for this sampler
sampIndx = (where(info.samplers eq data[0].sampler_name))[0]
expectedCount = info.n_sampints[sampIndx]
endelse
if (countSigwcal ne expectedCount or countSigwcal ne countSig or $
countSigwcal ne countRefwcal or countSigwcal ne countRef) then begin
message,"Unexpected number of spectra retrieved for some or all of the switching phases, can not continue.",/info
data_free, data
return
endif
; watch for out-of-band frequency switching, it's okay, just turn on nofold if true.
thisnofold=keyword_set(nofold)
sig0 = sig[0]
ref0 = ref[0]
sigF0 = chantofreq(data[sig0],0.d)
refF0 = chantofreq(data[ref0],0.d)
chan_shift = (refF0-sigF0)/data[sig0].frequency_interval
npts = data_valid(data[sig0])
if abs(chan_shift) ge npts then thisnofold = 1
status = 0
missing = 0
if keyword_set(eqweight) then weight = 1.0 ; else undefined and use default weight
res1accum = {accum_struct}
if thisnofold then res2accum = {accum_struct}
tauInts = fltarr(expectedCount)
apEffInts = tauInts
for n_int = 0,(expectedCount-1) do begin
dofreqswitch,data[sigwcal[n_int]],data[sig[n_int]],data[refwcal[n_int]],data[ref[n_int]],smthoff,$
tsys=tsys,tau=tau,tcal=tcal,sigResult=sigResult,refResult=refResult
if thisnofold then begin
; convert units on both result
dcsetunits,sigResult,units,tau=tau,ap_eff=ap_eff
dcsetunits,refResult,units,tau=tau,ap_eff=ap_eff,$
ret_tau=ret_tau,ret_ap_eff=ret_ap_eff
endif else begin
; fold the two results
folded = dcfold(sigResult,refResult,blankinterp=blankinterp,nomask=nomask)
data_copy, folded, sigResult
data_free, folded
; and convert theunits
dcsetunits,sigResult,units,tau=tau,ap_eff=ap_eff,$
ret_tau=ret_tau,ret_ap_eff=ret_ap_eff
endelse
; these are only used in the status line at the end
tauInts[n_int] = ret_tau
apEffInts[n_int] = ret_ap_eff
dcaccum,res1accum,sigResult,weight=weight
if thisnofold then dcaccum,res2accum,refResult,weight=weight
if keyword_set(keepints) then begin
; re-use existing DCs so space isn't wasted.
; can't use the array element directly as it would
; not be passed by reference so would not be changed
; won't work : data_copy,sigResult,data[sig[n_int]]
; instead, do this
tmp = data[sig[n_int]] ; gets the right pointer
data_copy, sigResult, tmp ; copies header, re-uses pointer
data[sig[n_int]] = tmp ; puts it back in place
if keyword_set(nofold) then begin
; same here
tmp = data[ref[n_int]] ; gets the right pointer
data_copy, refResult, tmp ; copies header, re-uses pointer
data[ref[n_int]] = tmp ; puts it back in place
endif
endif
endfor
if keyword_set(keepints) then begin
putchunk,data[sig]
if keyword_set(nofold) then putchunk,data[ref]
endif
naccum1 = res1accum.n
if naccum1 le 0 then begin
message,'Result is all blanked - probably all of the data were flagged',/info
; sigResult must therefor be all blanked, use it as the end result
set_data_container, sigResult
data_free, sigResult
if data_valid(refResult) gt 0 then data_free, refResult
if data_valid(res2accum) gt 0 then data_free, res2accum
data_free, data
return
endif
accumave,res1accum,sigResult,/quiet
missing = naccum1 ne expectedCount
if thisnofold then begin
naccum2 = res2accum.n
if naccum2 le 0 then begin
message,'Result in buffer 1 is all blanked - probably at least one phase in each integration was blanked.',/info
message,'Can not continue - units of result in primary data container may not be as expected.',/info
; refResult must be all blanked, use it as the result in buffer 1
set_data_container, refResult, buffer=1
; clean up
data_free,sigResult
data_free,refResult
data_free, data
return
endif
accumave,res2accum,refResult,/quiet
missing = missing or naccum2 ne expectedCount
endif
status = 1
set_data_container, sigResult
if thisnofold then set_data_container, refResult, buffer=1
if not keyword_set(quiet) then begin
if missing then nmiss = expectedCount-naccum1
calsummary, info.scan, sigResult.tsys, sigResult.units, $
tauInts=tauInts, apEffInts=apEffInts, missingInts=nmiss, $
ifnum=ret.ifnum,plnum=ret.plnum,fdnum=ret.fdnum
endif
data_free, data
data_free, sigResult
if data_valid(refResult) gt 0 then data_free, refResult
end