;+
; NAME:
; SPINMODEL_INTERP_T.PRO
;
; PURPOSE:
; Given a spin model and time (or array of times), calculate
; the spin count, spin phase, spin period, and time of last sun pulse
; for each input time.
;
; CATEGORY:
; TDAS
;
; CALLING SEQUENCE:
; spinmodel->interp_t,time=input_times,$
; spincount=output_spincount, spinper=output_spinper,$
; t_last=output_sun_pulse_times, segflag=output_segflag, eclipse_delta_phi=delta_phi
;
; INPUTS:
; Time: A double precision scalar or array specifying the input times.
; If the input is a scalar, all outputs will be scalars; otherwise,
; all outputs are arrays having the same size as the input times.
;
; OUTPUTS:
; spinper: Optional keyword parameter to receive spin period values.
; tlast: Optional keyword parameter to receive sun pulse time
; immediately preceding each input time.
; spincount: Optional keyword parameter to receive count of spins
; since the start of the model.
; spinphase: Optional keyword parameter to receive the spin phase
; (ranging from 0.0 to 360.0 degrees) at each input time.
; eclipse_delta_phi: Optional keyword parameter to receive
; deviation (degrees) between the IDPU's spin model and
; the sunpulse+fgm spin model. Zero in sunlight, non-zero
; if in eclipse AND FGM "synthetic" sunpulses were used
; when the spinmodel was created during L0->L1 processing.
;
; KEYWORDS:
;
; /TIME: Required input keyword argument specifying a time or array of times.
; /SPINPER: Optional keyword argument to receive spin period values.
; /T_LAST: Optional keyword argument to receive sun pulse times
; /SPINCOUNT: Optional keyword argument to receive spin counts
; /SPINPHASE: Optional keyword argument to receive spin phase
;
; PROCEDURE:
; Find the spinmodel segment containing the input time.
; Use b and c segment parameters to determine the spin period,
; spin phase, and spin count at each input time
; Invert phi(t) function to find sun pulse time immediately preceding
; each input time.
;
; EXAMPLE:
;
; ; Assume 'input_times' and 'input_spinphase' already exist as a
; ; IDL variables -- perhaps obtained from thm_load_state.
; ;
; ; Get a pointer to the spin model for probe A
; modelptr=spinmodel_get_ptr('a')
;
; ; Calculate spin phase at each time from spin model
;
; model->interp_t,time=input_times,spinphase=output_spinphase
;
; ; Calculate spinphase differences between spin model and state
; phi_diff=output_spinphase-input_spinphase
;
; ; Fix wraparounds
;
; i=where(phi_diff GT 180.0D)
; i2=where(phi_diff LT -180.0D)
; phi_diff[i] = phi_diff[i] - 360.0D
; phi_diff[i2] = phi_diff[i2] + 360.0D
;
; Plot results
;
; plot,input_times,phi_diff
;
;-
; Helper routine to apply spin phase corrections
pro thm_spinmodel::adjust_spinphase,time=time,spinphase=spinphase
self->get_info,start_time=start_time,end_time=end_time
min_time = min(time,/nan,max=max_time)
if start_time-min_time gt 60*60 || max_time - end_time gt 60*60 then begin
dprint,'NON-FATAL-ERROR: spinmodel(from state file) failed to overlap for time greater than 1 hour. Data may have significant interpolation errors.'
endif
corr_times=*( self.spincorr_times )
corr_vals=*( self.spincorr_vals )
corr_count=n_elements(corr_times)
first_corr_time=corr_times[0]
first_corr_val= corr_vals[0]
last_corr_time=corr_times[corr_count-1]
last_corr_val= corr_vals[corr_count-1]
; Interpolate corrections using input_times
; Special case: if only one correction is available, e.g. when only
; a single day is loaded in thm_load_state, then that value applies for
; all time. (interpol needs at least two points or it will bomb).
if (corr_count LT 2) then begin
interp_correction=replicate(first_corr_val,n_elements(time))
endif else begin
interp_correction=interpol(corr_vals,corr_times,time)
endelse
; For times before & after spinmodel time range, use nearest
; neighbor instead of extrapolation
idx=where(time LT first_corr_time,count)
if (count GT 0) then interp_correction[idx] = first_corr_val
idx=where(time GE last_corr_time,count)
if (count GT 0) then interp_correction[idx] = last_corr_val
; Apply corrections
corr_spinphase = spinphase - interp_correction
; Map to range [0.0,360.0) deg
idx=where(corr_spinphase LT 0.0D,count)
if (count GT 0) then corr_spinphase[idx] = corr_spinphase[idx] + 360.0D
idx=where(corr_spinphase GE 360.0D,count)
if (count GT 0) then corr_spinphase[idx] = corr_spinphase[idx] - 360.0D
; Pass corrected spin phase back to caller
spinphase = corr_spinphase
end
pro thm_spinmodel::interp_t,time=time,spincount=spincount,t_last=t_last,$
spinphase=spinphase,spinper=spinper,segflag=segflag,eclipse_delta_phi=eclipse_delta_phi,$
use_spinphase_correction=use_spinphase_correction
sp = self.segs_ptr
if (ptr_valid(sp) NE 1) then begin
message,'Spinmodel segment pointer is invalid.'
end
if (keyword_set(time) NE 1) then begin
message,'Required TIME keyword argument not present.'
end
if (n_elements(use_spinphase_correction) EQ 0) then begin
use_spinphase_correction=1
dprint,dlevel=4,'Defaulting to use V03 spin phase correction.'
end
segs = (*sp)[self->findseg_t(time)]
segment_interp_t,segs,time,my_spincount,my_t_last,my_spinphase,my_spinper,my_segflag,my_eclipse_delta_phi,mask=3
if keyword_set(use_spinphase_correction) then begin
dprint,dlevel=4,'Using spinphase correction'
self->adjust_spinphase,time=time,spinphase=my_spinphase
endif else begin
dprint,dlevel=4,'Not using spinphase correction'
endelse
if (arg_present(spincount) EQ 1) then spincount=my_spincount
if (arg_present(t_last) EQ 1) then t_last=my_t_last
if (arg_present(spinphase) EQ 1) then spinphase=my_spinphase
if (arg_present(spinper) EQ 1) then spinper=my_spinper
if (arg_present(segflag) EQ 1) then segflag=my_segflag
if (arg_present(eclipse_delta_phi) EQ 1) then eclipse_delta_phi=my_eclipse_delta_phi
; endelse
end