FreeBSD/contrib/ntp/ntpd/refclock_wwv.c
/*
 * wwv_endpoc - identify and acquire second sync pulse
 *
 * This routine is called at the end of the second sync interval. It
 * determines the second sync epoch position within the second and
 * disciplines the sample clock using a frequency-lock loop (FLL).
 *
 * Second sync is determined in the RF input routine as the maximum
 * over all 8000 samples in the second comb filter. To assure accurate
 * and reliable time and frequency discipline, this routine performs a
 * great deal of heavy-handed heuristic data filtering and grooming.
 */
identify and acquire second sync pulse
This routine is called at the end of the second sync interval. It
determines the second sync epoch position within the second and
disciplines the sample clock using a frequency-lock loop (FLL).

Second sync is determined in the RF input routine as the maximum
over all 8000 samples in the second comb filter. To assure accurate
and reliable time and frequency discipline, this routine performs a
great deal of heavy-handed heuristic data filtering and grooming.
identify and acquire second sync pulse This routine is called at the end of the second sync interval . It determines the second sync epoch position within the second and disciplines the sample clock using a frequency - lock loop ( FLL ) . Second sync is determined in the RF input routine as the maximum over all 8000 samples in the second comb filter . To assure accurate and reliable time and frequency discipline this routine performs a great deal of heavy - handed heuristic data filtering and grooming .
static void
wwv_endpoc(
	struct peer *peer,	
	int epopos		
	)
{
	struct refclockproc *pp;
	struct wwvunit *up;
	static int epoch_mf[3]; 
	static int tepoch;	
 	static int xepoch;	
 	static int zepoch;	
	static int zcount;	
	static int scount;	
	static int syncnt;	
	static int maxrun;	
	static int mepoch;	
	static int mcount;	
	static int avgcnt;	
	static int avginc;	
	static int iniflg;	
	char tbuf[TBUF];		
	double dtemp;
	int tmp2;
	pp = peer->procptr;
	up = pp->unitptr;
	if (!iniflg) {
		iniflg = 1;
		ZERO(epoch_mf);
	}
	scount++;
	if (up->epomax < STHR || up->eposnr < SSNR) {
		up->status &= ~(SSYNC | FGATE);
		avgcnt = syncnt = maxrun = 0;
		return;
	}
	if (!(up->status & (SELV | SELH)))
		return;
	epoch_mf[2] = epoch_mf[1];
	epoch_mf[1] = epoch_mf[0];
	epoch_mf[0] = epopos;
	if (epoch_mf[0] > epoch_mf[1]) {
		if (epoch_mf[1] > epoch_mf[2])
			tepoch = epoch_mf[1];	
		else if (epoch_mf[2] > epoch_mf[0])
			tepoch = epoch_mf[0];	
		else
			tepoch = epoch_mf[2];	
	} else {
		if (epoch_mf[1] < epoch_mf[2])
			tepoch = epoch_mf[1];	
		else if (epoch_mf[2] < epoch_mf[0])
			tepoch = epoch_mf[0];	
		else
			tepoch = epoch_mf[2];	
	}
	tmp2 = (tepoch - xepoch) % WWV_SEC;
	if (tmp2 == 0) {
		syncnt++;
		if (syncnt > SCMP && up->status & MSYNC && (up->status &
		    FGATE || scount - zcount <= up->avgint)) {
			up->status |= SSYNC;
			up->yepoch = tepoch;
		}
	} else if (syncnt >= maxrun) {
		maxrun = syncnt;
		mcount = scount;
		mepoch = xepoch;
		syncnt = 0;
	}
	if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
	    MSYNC)) {
		snprintf(tbuf, sizeof(tbuf),
		    "wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d",
		    up->status, up->gain, tepoch, up->epomax,
		    up->eposnr, tmp2, avgcnt, syncnt,
		    maxrun);
		record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
		if (debug)
			printf("%s\n", tbuf);
#endif 
	}
	avgcnt++;
	if (avgcnt < up->avgint) {
		xepoch = tepoch;
		return;
	}
	if (syncnt >= maxrun) {
		maxrun = syncnt;
		mcount = scount;
		mepoch = xepoch;
	}
	xepoch = tepoch;
	if (maxrun == 0) {
		mepoch = tepoch;
		mcount = scount;
	}
	dtemp = (mepoch - zepoch) % WWV_SEC;
	if (up->status & FGATE) {
		if (fabs(dtemp) < MAXFREQ * MINAVG) {
			up->freq += (dtemp / 2.) / ((mcount - zcount) *
			    FCONST);
			if (up->freq > MAXFREQ)
				up->freq = MAXFREQ;
			else if (up->freq < -MAXFREQ)
				up->freq = -MAXFREQ;
			if (fabs(dtemp) < MAXFREQ * MINAVG / 2.) {
				if (avginc < 3) {
					avginc++;
				} else {
					if (up->avgint < MAXAVG) {
						up->avgint <<= 1;
						avginc = 0;
					}
				}
			}
		} else {
			if (avginc > -3) {
				avginc--;
			} else {
				if (up->avgint > MINAVG) {
					up->avgint >>= 1;
					avginc = 0;
				}
			}
		}
	}
	if (pp->sloppyclockflag & CLK_FLAG4) {
		snprintf(tbuf, sizeof(tbuf),
		    "wwv2 %04x %5.0f %5.1f %5d %4d %4d %4d %4.0f %7.2f",
		    up->status, up->epomax, up->eposnr, mepoch,
		    up->avgint, maxrun, mcount - zcount, dtemp,
		    up->freq * 1e6 / WWV_SEC);
		record_clock_stats(&peer->srcadr, tbuf);
#ifdef DEBUG
		if (debug)
			printf("%s\n", tbuf);
#endif 
	}
	up->status |= FGATE;
	zepoch = mepoch;
	zcount = mcount;
	avgcnt = syncnt = maxrun = 0;
}
static void wwv_endpoc ( struct peer * peer , int epopos ) { struct refclockproc * pp ; struct wwvunit * up ; static int epoch_mf [ 3 ] ; static int tepoch ; static int xepoch ; static int zepoch ; static int zcount ; static int scount ; static int syncnt ; static int maxrun ; static int mepoch ; static int mcount ; static int avgcnt ; static int avginc ; static int iniflg ; char tbuf [ TBUF ] ; double dtemp ; int tmp2 ; pp = peer -> procptr ; up = pp -> unitptr ; if ( ! iniflg ) { iniflg = 1 ; ZERO ( epoch_mf ) ; } scount ++ ; if ( up -> epomax < STHR || up -> eposnr < SSNR ) { up -> status &= ~ ( SSYNC | FGATE ) ; avgcnt = syncnt = maxrun = 0 ; return ; } if ( ! ( up -> status & ( SELV | SELH ) ) ) return ; epoch_mf [ 2 ] = epoch_mf [ 1 ] ; epoch_mf [ 1 ] = epoch_mf [ 0 ] ; epoch_mf [ 0 ] = epopos ; if ( epoch_mf [ 0 ] > epoch_mf [ 1 ] ) { if ( epoch_mf [ 1 ] > epoch_mf [ 2 ] ) tepoch = epoch_mf [ 1 ] ; else if ( epoch_mf [ 2 ] > epoch_mf [ 0 ] ) tepoch = epoch_mf [ 0 ] ; else tepoch = epoch_mf [ 2 ] ; } else { if ( epoch_mf [ 1 ] < epoch_mf [ 2 ] ) tepoch = epoch_mf [ 1 ] ; else if ( epoch_mf [ 2 ] < epoch_mf [ 0 ] ) tepoch = epoch_mf [ 0 ] ; else tepoch = epoch_mf [ 2 ] ; } tmp2 = ( tepoch - xepoch ) % WWV_SEC ; if ( tmp2 == 0 ) { syncnt ++ ; if ( syncnt > SCMP && up -> status & MSYNC && ( up -> status & FGATE || scount - zcount <= up -> avgint ) ) { up -> status |= SSYNC ; up -> yepoch = tepoch ; } } else if ( syncnt >= maxrun ) { maxrun = syncnt ; mcount = scount ; mepoch = xepoch ; syncnt = 0 ; } if ( ( pp -> sloppyclockflag & CLK_FLAG4 ) && ! ( up -> status & MSYNC ) ) { snprintf ( tbuf , sizeof ( tbuf ) , " " , up -> status , up -> gain , tepoch , up -> epomax , up -> eposnr , tmp2 , avgcnt , syncnt , maxrun ) ; record_clock_stats ( & peer -> srcadr , tbuf ) ; #ifdef DEBUG if ( debug ) printf ( " \n " , tbuf ) ; #endif } avgcnt ++ ; if ( avgcnt < up -> avgint ) { xepoch = tepoch ; return ; } if ( syncnt >= maxrun ) { maxrun = syncnt ; mcount = scount ; mepoch = xepoch ; } xepoch = tepoch ; if ( maxrun == 0 ) { mepoch = tepoch ; mcount = scount ; } dtemp = ( mepoch - zepoch ) % WWV_SEC ; if ( up -> status & FGATE ) { if ( fabs ( dtemp ) < MAXFREQ * MINAVG ) { up -> freq += ( dtemp / 2. ) / ( ( mcount - zcount ) * FCONST ) ; if ( up -> freq > MAXFREQ ) up -> freq = MAXFREQ ; else if ( up -> freq < - MAXFREQ ) up -> freq = - MAXFREQ ; if ( fabs ( dtemp ) < MAXFREQ * MINAVG / 2. ) { if ( avginc < 3 ) { avginc ++ ; } else { if ( up -> avgint < MAXAVG ) { up -> avgint <<= 1 ; avginc = 0 ; } } } } else { if ( avginc > -3 ) { avginc -- ; } else { if ( up -> avgint > MINAVG ) { up -> avgint >>= 1 ; avginc = 0 ; } } } } if ( pp -> sloppyclockflag & CLK_FLAG4 ) { snprintf ( tbuf , sizeof ( tbuf ) , " " , up -> status , up -> epomax , up -> eposnr , mepoch , up -> avgint , maxrun , mcount - zcount , dtemp , up -> freq * 1e6 / WWV_SEC ) ; record_clock_stats ( & peer -> srcadr , tbuf ) ; #ifdef DEBUG if ( debug ) printf ( " \n " , tbuf ) ; #endif } up -> status |= FGATE ; zepoch = mepoch ; zcount = mcount ; avgcnt = syncnt = maxrun = 0 ; }
wwv_endpoc - identify and acquire second sync pulse
 This routine is called at the end of the second sync interval.
wwv_endpoc - identify and acquire second sync pulse This routine is called at the end of the second sync interval .
/* peer structure pointer */ /* epoch max position */ /* epoch median filter */ /* current second epoch */ /* last second epoch */ /* last run epoch */ /* last run end time */ /* seconds counter */ /* run length counter */ /* longest run length */ /* longest run end epoch */ /* longest run end time */ /* averaging interval counter */ /* averaging ratchet */ /* initialization flag */ /* monitor buffer */ /*
	 * If the signal amplitude or SNR fall below thresholds, dim the
	 * second sync lamp and wait for hotter ions. If no stations are
	 * heard, we are either in a probe cycle or the ions are really
	 * cold. 
	 */ /*
	 * A three-stage median filter is used to help denoise the
	 * second sync pulse. The median sample becomes the candidate
	 * epoch.
	 */ /* 0 1 2 */ /* 2 0 1 */ /* 0 2 1 */ /* 2 1 0 */ /* 1 0 2 */ /* 1 2 0 */ /*
	 * If the epoch candidate is the same as the last one, increment
	 * the run counter. If not, save the length, epoch and end
	 * time of the current run for use later and reset the counter.
	 * The epoch is considered valid if the run is at least SCMP
	 * (10) s, the minute is synchronized and the interval since the
	 * last epoch  is not greater than the averaging interval. Thus,
	 * after a long absence, the program will wait a full averaging
	 * interval while the comb filter charges up and noise
	 * dissapates..
	 */ /* DEBUG */ /*
	 * The sample clock frequency is disciplined using a first-order
	 * feedback loop with time constant consistent with the Allan
	 * intercept of typical computer clocks. During each averaging
	 * interval the candidate epoch at the end of the longest run is
	 * determined. If the longest run is zero, all epoches in the
	 * interval are different, so the candidate epoch is the current
	 * epoch. The frequency update is computed from the candidate
	 * epoch difference (125-us units) and time difference (seconds)
	 * between updates.
	 */ /*
	 * The master clock runs at the codec sample frequency of 8000
	 * Hz, so the intrinsic time resolution is 125 us. The frequency
	 * resolution ranges from 18 PPM at the minimum averaging
	 * interval of 8 s to 0.12 PPM at the maximum interval of 1024
	 * s. An offset update is determined at the end of the longest
	 * run in each averaging interval. The frequency adjustment is
	 * computed from the difference between offset updates and the
	 * interval between them.
	 *
	 * The maximum frequency adjustment ranges from 187 PPM at the
	 * minimum interval to 1.5 PPM at the maximum. If the adjustment
	 * exceeds the maximum, the update is discarded and the
	 * hysteresis counter is decremented. Otherwise, the frequency
	 * is incremented by the adjustment, but clamped to the maximum
	 * 187.5 PPM. If the update is less than half the maximum, the
	 * hysteresis counter is incremented. If the counter increments
	 * to +3, the averaging interval is doubled and the counter set
	 * to zero; if it decrements to -3, the interval is halved and
	 * the counter set to zero.
	 */ /* DEBUG */ /*
	 * This is a valid update; set up for the next interval.
	 */