PRO PMTRAS_DBASE_INTERPOLATE, dbsolution, ndeg, gapcounts, return_flag ; ; Interpolates missing or marginal points in dbsolution with a polynomial of degree, ndeg. ; Sets return_flag=1 if any changes to dbsolution were made; 0 otherwise. ; Loads gapcounts array with gap statistics. ; ; 21-Aug-03 gh Initial version. ; 30-Nov-03 gh Revise formula for calculation of est_error. ; Ease fit tolerance from 1 to 1.3 arcminutes (per gh notebook analysis 11-30-03). ; return_flag = 0 npt = N_ELEMENTS(dbsolution) fit_tolerance = 0.0004 ; Fit tolerance = 1.3 arcminutes twopi = 2.*!DPI ; ; Identify good data points in original dbsolution. igood = WHERE(dbsolution.roll_quality GE 192, ngood) IF (ngood LT 2) THEN BEGIN PRINT, 'PMTRAS_DBASE_INTERPOLATE: Fails with only ', ngood, 'data points.' RETURN ENDIF scgoodtime = dbsolution[igood].sctime gapcounts = INTARR(4) ; gapcounts[0] = total number of gaps ; ; gapcounts[1] = number of short gaps (< 800s) ; ; gapcounts[2] = number of short gaps with good coverage ; ; gapcounts[3] = number of successfully filled gaps. ; ; Identify prospective gaps. dt = SHIFT(scgoodtime, -1) - scgoodtime ; good array index corresponding to earlier time, dt >0 dummy = WHERE (dt GT 65, ng) ; only used for getting a gapcount jgap = WHERE (dt GT 65 AND dt LT 800, ngap) ; selects indices in good array of start of 65-800s gaps gapcounts[0] = ng gapcounts[1] = ngap IF (ngap EQ 0) THEN BEGIN PRINT, 'PMTRAS_DBASE_INTERPOLATE: No short gaps to fill.' RETURN ENDIF igapstart = igood[jgap] ; original array indices at start of gaps igapend = igood[jgap+1] ; original array indices at end of gaps missing = dt[jgap]/64-1 ; array of number of missing data points ; ; Define a structure for a single interpolated data point. star = {detections: 0, $ ; detections of this star in this interval id: 0, $ ; Harvard ref# of star intensity: 0, $ ; average blip total av_offset: 0.0, $ ; average offset from overall fit in this interval rms_scatter: 0.0 } ; rms scatter, relative to av_offset (defined for ndet>1) stars = REPLICATE (star,10) ; can support up to 10 stars dbinterpoint = {sctime: 0L, $ ; in s/c clock seconds, should be a multiple of 64 roll_phase: 0L, $ ; in microradians approx_angvel: 0B, $ ; approximate angular velocity, in radians/second * 2^7 roll_quality: 192B, $ ; roll_quality byte blipcount: 0, $ ; number of blips in this interval starcount: 0B, $ ; number of unique stars in this interval roll_period: 0.0, $ ; exact roll period (s) est_error: 0.0, $ ; estimated error in roll_phase (radians) analysis_code: 0B, $ ; TBD code to indicated software configuration/parameters stars: stars } ; ; Begin loop over individual gaps. ; First task is to select the good 'reference' points that will be used to fit solution vs time. ; Points on each side of gap should be the minumum satisfying the 3 criteria that: ; A. There must be at least ndeg+1 points; ; B. There must be at least a number equal to the number of missing points in the gap ; C. The separation of at least 1 of the points from the nearest edge of the gap be at least as large as half the ; width of the gap. FOR n=0, ngap-1 DO BEGIN jgapnstart = jgap[n] ; index in good array of start of this gap jgapnend = jgap[n]+1 ; index in good array of end of this gap missingn = missing[n] ; number of missing data points in this gap dtgapn = dt[jgap[n]] nmin = missingn > (ndeg + 1) ; minimum number of 'before' points reqd ; Identify relevant pregap indices jp0 = jgapnstart - INDGEN(nmin) ; indices in good array of points shortly before this gap. IF (jp0[nmin-1] LT 0 ) THEN CONTINUE ; insufficient points to interpolate - go to next gap dtp0 = scgoodtime[jgapnstart] - scgoodtime[jp0] ; array of (increasing +ve) intervals until start of gap m0 = WHERE(dtp0 GE dtgapn/2.) ; points far from gap mpre = (ndeg+1) > (m0[0]+1) > missingn ; final number of 'before' points jpre = INDGEN(mpre) + jgapnstart - mpre + 1 ; indices of relevant pregap points in good array ; Identify relevant postgap indices jp1 = INDGEN(nmin) + jgapnend ; indices in good array of points shortly after this gap. IF (jp1[nmin-1] GT ngood) THEN CONTINUE ; insufficient points to interpolate - go to next gap dtp1 = scgoodtime[jp1] - scgoodtime[jgapnend] ; array of (increasing +ve) intervals until start of gap m1 = WHERE(dtp1 GE dtgapn/2.) ; points far from gap mpost = (ndeg+1) > (m1[0]+1) > missingn ; final number of 'before' points jpost = INDGEN(mpost) + jgapnend ; indices of relevant postgap points in good array ; Combine to specify reference points for this gap. jref = [jpre, jpost] ; array of indices in good array of reference points mref = mpre + mpost ; number of reference points (>=8). x = scgoodtime[jref] ; = times in seconds IF x[mref-1] - x[0] GT 2400 THEN CONTINUE ; range of reference times is too great - go to next gap gapcounts[2] = gapcounts[2] + 1 ; ; Polynomial fit of points around the gap. soln = hsi_pmtras_dbase_expand (dbsolution[igood[jref]]) ; returns normal roll_solution structure t0f = soln.t0_ref.seconds ; sctime.seconds of first datum x = soln.reltime y = soln.posn_angle ; radians fitparm = POLY_FIT(x, y, ndeg, /DOUBLE, YFIT=yfit) ; polynomial fit ; est_error = SQRT(TOTAL((y-yfit)^2)/(mref-ndeg-1)) ; Obsolete formula replaced 11-30-03 gh. est_error = SQRT( TOTAL((y-yfit)^2) / (mref*(mref-ndeg-1))) IF (est_error GT fit_tolerance) THEN CONTINUE ; scatter is too large - go to next gap gapcounts[3] = gapcounts[3] + 1 ; ; Flag existing gap points in dbsolution for deletion. igapstartn = igapstart[n] igapendn = igapend[n] FOR i = igapstartn+1, igapendn-1 DO dbsolution[i].sctime = -1L ; ; Calculate solutions for all missing points. t0m = dbsolution[igapstartn].sctime +64 - t0f ; time of 1st missing point in same units as 'x' t = t0m + 64L*INDGEN(missingn) ; times of all the missing points. ygap = DBLARR(missingn) FOR k=0, ndeg DO ygap = ygap + fitparm[k]*t^k ; array of interpolated values (increasing radians) roll_phase = LONG((ygap MOD twopi)*1.D6) ; microradians ygap0 = [y[mpre-1], ygap] ; add last pregap point to interpolated value array xgap0 = [x[mpre-1], t] roll_period = twopi * (xgap0[1:missingn] - xgap0[0:missingn-1]) / $ (ygap0[1:missingn] - ygap0[0:missingn-1]) approx_angvel = BYTE(128 * twopi / roll_period) ; ; Load a structure with one point at a time and append it to an array of new points. FOR m=0, missingn-1 DO BEGIN dbinterpoint.sctime = t[m] +t0f dbinterpoint.roll_phase = roll_phase[m] dbinterpoint.approx_angvel = approx_angvel[m] dbinterpoint.roll_period = roll_period[m] dbinterpoint.est_error = est_error IF N_ELEMENTS(dbnew) EQ 0 THEN dbnew = dbinterpoint ELSE dbnew = [dbnew, dbinterpoint] ENDFOR ENDFOR ; ; Eliminate obsolute points in dbsolution, insert new points at their proper location. IF N_ELEMENTS(dbnew) EQ 0 THEN RETURN ; no changes to database iok = WHERE(dbsolution.sctime GE 0) dbtemp = [dbsolution[iok], dbnew] iseq = SORT(dbtemp.sctime) dbsolution = dbtemp[iseq] ; dbsolution is time-ordered again. return_flag = -1 RETURN END