Esempio n. 1
0
File: servo.c Progetto: DomChey/ptpd
void
updateDelay(Filter * owd_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal * correctionField)
{

	/* updates paused, leap second pending - do nothing */
	if(ptpClock->leapSecondInProgress)
		return;

	DBGV("updateDelay\n");



	/* todo: do all intermediate calculations on temp vars */
	TimeInternal prev_meanPathDelay = ptpClock->meanPathDelay;

	ptpClock->char_last_msg = 'D';

	{
		//perform basic checks, using local variables only
		TimeInternal slave_to_master_delay;
	
		/* calc 'slave_to_master_delay' */
		subTime(&slave_to_master_delay, &ptpClock->delay_req_receive_time,
			&ptpClock->delay_req_send_time);

		if (rtOpts->maxDelay && /* If maxDelay is 0 then it's OFF */
		    rtOpts->offset_first_updated) {

			if ((slave_to_master_delay.nanoseconds < 0) &&
			    (abs(slave_to_master_delay.nanoseconds) > rtOpts->maxDelay)) {
				INFO("updateDelay aborted, "
				     "delay (sec: %d ns: %d) is negative\n",
				     slave_to_master_delay.seconds,
				     slave_to_master_delay.nanoseconds);
				INFO("send (sec: %d ns: %d)\n",
				     ptpClock->delay_req_send_time.seconds,
				     ptpClock->delay_req_send_time.nanoseconds);
				INFO("recv (sec: %d n	s: %d)\n",
				     ptpClock->delay_req_receive_time.seconds,
				     ptpClock->delay_req_receive_time.nanoseconds);
				goto display;
			}

			if (slave_to_master_delay.seconds && rtOpts->maxDelay) {
				INFO("updateDelay aborted, delay %d.%d greater than 1 second\n",
				     slave_to_master_delay.seconds,
				     slave_to_master_delay.nanoseconds);
				if (rtOpts->displayPackets)
					msgDump(ptpClock);
				goto display;
			}

			if (slave_to_master_delay.nanoseconds > rtOpts->maxDelay) {
				INFO("updateDelay aborted, delay %d greater than "
				     "administratively set maximum %d\n",
				     slave_to_master_delay.nanoseconds, 
				     rtOpts->maxDelay);
				if (rtOpts->displayPackets)
					msgDump(ptpClock);
				goto display;
			}
		}
	}

	/*
	 * The packet has passed basic checks, so we'll:
	 *   - update the global delaySM variable
	 *   - calculate a new filtered MPD
	 */
	if (rtOpts->offset_first_updated) {
		/*
		 * calc 'slave_to_master_delay' (Master to Slave delay is
		 * already computed in updateOffset )
		 */

		DBG("==> UpdateDelay():   %s\n",
			dump_TimeInternal2("Req_RECV:", &ptpClock->delay_req_receive_time,
			"Req_SENT:", &ptpClock->delay_req_send_time));
		
#ifdef PTPD_STATISTICS
	if (rtOpts->delaySMOutlierFilterEnabled) {
		subTime(&ptpClock->rawDelaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
		if(!isDoublePeircesOutlier(ptpClock->delaySMRawStats, timeInternalToDouble(&ptpClock->rawDelaySM), rtOpts->delaySMOutlierFilterThreshold)) {
			ptpClock->delaySM = ptpClock->rawDelaySM;
			ptpClock->delaySMoutlier = FALSE;
		} else {
			ptpClock->delaySMoutlier = TRUE;
			ptpClock->counters.delaySMOutliersFound++;
			if (!rtOpts->delaySMOutlierFilterDiscard)  {
				ptpClock->delaySM = doubleToTimeInternal(ptpClock->delaySMFiltered->mean);
			} else {
				    goto statistics;
			}
		}
	} else {
		subTime(&ptpClock->delaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
	}
#else
		subTime(&ptpClock->delaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
#endif
		/* update 'one_way_delay' */
		addTime(&ptpClock->meanPathDelay, &ptpClock->delaySM, 
			&ptpClock->delayMS);

		/* Substract correctionField */
		subTime(&ptpClock->meanPathDelay, &ptpClock->meanPathDelay, 
			correctionField);

		/* Compute one-way delay */
		div2Time(&ptpClock->meanPathDelay);
		
		if (ptpClock->meanPathDelay.seconds) {
			DBG("update delay: cannot filter with large OFM, "
				"clearing filter\n");
			INFO("Servo: Ignoring delayResp because of large OFM\n");
			
			FilterClear(owd_filt);
			/* revert back to previous value */
			ptpClock->meanPathDelay = prev_meanPathDelay;

			goto display;
		}


		if(ptpClock->meanPathDelay.nanoseconds < 0){
			DBG("update delay: found negative value for OWD, "
			    "so ignoring this value: %d\n",
				ptpClock->meanPathDelay.nanoseconds);
			/* revert back to previous value */
			ptpClock->meanPathDelay = prev_meanPathDelay;
#ifdef PTPD_STATISTICS
			goto statistics;
#else
			goto display;
#endif /* PTPD_STATISTICS */
		}

		{
			// TODO: remove hack
			char s_text[32];
			sprintf(s_text, "%d", rtOpts->s);
			FilterConfigure(owd_filt, "stiffness", s_text);
		}
		FilterFeed(owd_filt, &ptpClock->meanPathDelay.nanoseconds);

/* Update relevant statistics containers, feed outlier filter thresholds etc. */
#ifdef PTPD_STATISTICS
statistics:
                        if (rtOpts->delaySMOutlierFilterEnabled) {
                            double dDelaySM = timeInternalToDouble(&ptpClock->rawDelaySM);
                            /* If this is an outlier, bring it by a factor closer to mean before allowing to influence stdDev */
                            if(ptpClock->delaySMoutlier) {
				/* Allow [weight] * [deviation from mean] to influence std dev in the next outlier checks */
                            DBG("DelaySM outlier: %.09f\n", dDelaySM);
			    if((rtOpts->calibrationDelay<1) || ptpClock->isCalibrated)
                            dDelaySM = ptpClock->delaySMRawStats->meanContainer->mean + rtOpts->delaySMOutlierWeight * ( dDelaySM - ptpClock->delaySMRawStats->meanContainer->mean);
                            } 
                                        feedDoubleMovingStdDev(ptpClock->delaySMRawStats, dDelaySM);
                                        feedDoubleMovingMean(ptpClock->delaySMFiltered, timeInternalToDouble(&ptpClock->delaySM));
                                }
                        feedDoublePermanentStdDev(&ptpClock->slaveStats.owdStats, timeInternalToDouble(&ptpClock->meanPathDelay));
#endif


		DBGV("delay filter %d\n", ptpClock->meanPathDelay.nanoseconds);
	} else {
		INFO("Ignoring delayResp because we didn't receive any sync yet\n");
	}


display:
	logStatistics(rtOpts, ptpClock);

}
Esempio n. 2
0
File: servo.c Progetto: DomChey/ptpd
void
updateOffset(TimeInternal * send_time, TimeInternal * recv_time,
    Filter * ofm_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal * correctionField)
{

	DBGV("UTCOffset: %d | leap 59: %d |  leap61: %d\n", 
	     ptpClock->timePropertiesDS.currentUtcOffset,ptpClock->timePropertiesDS.leap59,ptpClock->timePropertiesDS.leap61);
        /* updates paused, leap second pending - do nothing */
        if(ptpClock->leapSecondInProgress)
		return;

	DBGV("==> updateOffset\n");

	{
	//perform basic checks, using only local variables
	TimeInternal master_to_slave_delay;

	/* calc 'master_to_slave_delay' */
	subTime(&master_to_slave_delay, recv_time, send_time);

	if (rtOpts->maxDelay) { /* If maxDelay is 0 then it's OFF */
		if (master_to_slave_delay.seconds && rtOpts->maxDelay) {
			INFO("updateOffset aborted, delay greater than 1"
			     " second.\n");
			/* msgDump(ptpClock); */
			return;
		}

		if (master_to_slave_delay.nanoseconds > rtOpts->maxDelay) {
			INFO("updateOffset aborted, delay %d greater than "
			     "administratively set maximum %d\n",
			     master_to_slave_delay.nanoseconds, 
			     rtOpts->maxDelay);
			/* msgDump(ptpClock); */
			return;
		}
	}
	}

	// used for stats feedback 
	ptpClock->char_last_msg='S';

	/*
	 * The packet has passed basic checks, so we'll:
	 *   - update the global delayMS variable
	 *   - calculate a new filtered OFM
	 */
#ifdef PTPD_STATISTICS
	if (rtOpts->delayMSOutlierFilterEnabled) {
		subTime(&ptpClock->rawDelayMS, recv_time, send_time);
		if(!isDoublePeircesOutlier(ptpClock->delayMSRawStats, timeInternalToDouble(&ptpClock->rawDelayMS), rtOpts->delayMSOutlierFilterThreshold)) {
			ptpClock->delayMSoutlier = FALSE;
			ptpClock->delayMS = ptpClock->rawDelayMS;
		} else {
			ptpClock->delayMSoutlier = TRUE;
			ptpClock->counters.delayMSOutliersFound++;
			if(!rtOpts->delayMSOutlierFilterDiscard)
			ptpClock->delayMS = doubleToTimeInternal(ptpClock->delayMSFiltered->mean);
		}
	} else {
		subTime(&ptpClock->delayMS, recv_time, send_time);
	}
#else
	/* Used just for End to End mode. */
	subTime(&ptpClock->delayMS, recv_time, send_time);
#endif

	/* Take care about correctionField */
	subTime(&ptpClock->delayMS,
		&ptpClock->delayMS, correctionField);

#ifdef PTPD_STATISTICS
#endif

	/* update 'offsetFromMaster' */
	if (ptpClock->delayMechanism == P2P) {
		subTime(&ptpClock->offsetFromMaster, 
			&ptpClock->delayMS, 
			&ptpClock->peerMeanPathDelay);
	/* (End to End mode or disabled - if disabled, meanpath delay is zero) */
	} else if (ptpClock->delayMechanism == E2E ||
	    ptpClock->delayMechanism == DELAY_DISABLED ) {

		subTime(&ptpClock->offsetFromMaster, 
			&ptpClock->delayMS, 
			&ptpClock->meanPathDelay);
	}

	if (ptpClock->offsetFromMaster.seconds) {
		/* cannot filter with secs, clear filter */
		FilterClear(ofm_filt);
		rtOpts->offset_first_updated = TRUE;
		return;
	}

	FilterFeed(ofm_filt, &ptpClock->offsetFromMaster.nanoseconds);

	DBGV("offset filter %d\n", ptpClock->offsetFromMaster.nanoseconds);

	/* Apply the offset shift */
	subTime(&ptpClock->offsetFromMaster, &ptpClock->offsetFromMaster,
	&rtOpts->ofmShift);

	/*
	 * Offset must have been computed at least one time before 
	 * computing end to end delay
	 */
	rtOpts->offset_first_updated = TRUE;
}
Esempio n. 3
0
/* 2 x fairy dust, 3 x unicorn droppings, 1 x magic beanstalk juice. blend, spray on the affected area twice per day */
static Boolean
outlierFilterFilter(OutlierFilter *filter, double sample)
{

	/* true = accepted - this is to tell the user if we advised to throw away the sample */
	Boolean ret = TRUE;

	/* step change: outlier mean - accepted mean from last sampling period */
	double step = 0.0;

	if(!filter->config.enabled) {
		filter->output = sample;
		return TRUE;
	}

	step = fabs(filter->outlierStats.mean - filter->acceptedStats.bufferedMean);

	if(filter->config.autoTune) {
		filter->autoTuneSamples++;
	}

	/* no outlier first - more convenient this way */
	if(!isDoublePeircesOutlier(filter->rawStats, sample, filter->threshold) && (filter->delay == 0)) {

		filter->lastOutlier = FALSE;
		filter->output = sample;

		/* filter is about to accept after a blocking period */
		if(filter->consecutiveOutliers) {
			DBG_LOCAL_ID(filter,"consecutive: %d, mean: %.09fm accepted bmean: %.09f\n", filter->consecutiveOutliers,
				filter->outlierStats.mean,filter->acceptedStats.bufferedMean);

				/* we are about to open up but the offset has risen above step level, we will block again, but not forever */
				if(filter->config.stepDelay &&
				    (fabs(filter->acceptedStats.bufferedMean) < ((filter->config.stepThreshold + 0.0) / 1E9)) &&
				    (step > ((filter->config.stepLevel + 0.0) / 1E9))) {
				    /* if we're to enter blocking, we need 2 * consecutiveOutliers credit */
				    /* if we're already blocking, we just need enough credit */
				    /* if we're already blocking, make sure we block no more than maxDelay */
				    if((filter->blocking && ((filter->config.maxDelay > filter->totalDelay) && (filter->delayCredit >= filter->consecutiveOutliers))) ||
					    (!filter->blocking && (filter->delayCredit >= filter->consecutiveOutliers * 2 ))) {
					    if(!filter->blocking) {
						INFO_LOCAL_ID(filter,"%.03f us step detected, filter will now block\n", step * 1E6);
					    }
					    DBG_LOCAL_ID(filter,"step: %.09f, credit left %d, requesting %d\n",step,
						    filter->delayCredit, filter->consecutiveOutliers);
					    filter->delay = filter->consecutiveOutliers;
					    filter->totalDelay += filter->consecutiveOutliers;
					    filter->delayCredit -= filter->consecutiveOutliers;
					    filter->blocking = TRUE;
					    resetDoublePermanentMean(&filter->outlierStats);
					    filter->lastOutlier = TRUE;
					    DBG_LOCAL_ID(filter,"maxdelay: %d, totaldelay: %d\n",filter->config.maxDelay, filter->totalDelay);
					    return FALSE;


				    /* much love for the ultra magnetic, cause everybody knows you never got enough credit */
				    /* we either ran out of credit while blocking, or we did not have enough to start with */
				    } else {
					if(filter->blocking) {
					    INFO_LOCAL_ID(filter,"blocking time exhausted, filter will stop blocking\n");
					} else {
					    INFO_LOCAL_ID(filter,"%.03f us step detected but filter cannot block\n", step * 1E6);
					}
					DBG_LOCAL_ID(filter,"credit out (has %d, needed %d)\n", filter->delayCredit, filter->consecutiveOutliers);
				    }
				/* NO STEP */
				} else {

					if (filter->blocking) {
					    INFO_LOCAL_ID(filter,"step event over, filter will stop blocking\n");
					}
					filter->blocking = FALSE;
				}

				if(filter->totalDelay != 0) {
					DBG_LOCAL_ID(filter,"Total waited %d\n", filter->totalDelay);
					filter->totalDelay = 0;
				}
		}

		filter->consecutiveOutliers = 0;
		resetDoublePermanentMean(&filter->outlierStats);
		feedDoublePermanentMean(&filter->acceptedStats, sample);

	/* it's an outlier, Sir! */
	} else {

		filter->lastOutlier = TRUE;
		feedDoublePermanentMean(&filter->outlierStats, sample);

		if(filter->delay) {
			DBG_LOCAL_ID(filter,"delay left: %d\n", filter->delay);
			filter->delay--;
			return FALSE;
		}

		filter->autoTuneOutliers++;
		filter->consecutiveOutliers++;

		if(filter->config.discard) {
			ret = FALSE;
		} else {
			filter->output = filter->filteredStats->mean;
		}


		DBG_LOCAL_ID(filter,"Outlier: %.09f\n", sample);
		/* Allow [weight] * [deviation from mean] to influence std dev in the next outlier checks */
		sample = filter->rawStats->meanContainer->mean + filter->config.weight * ( sample - filter->rawStats->meanContainer->mean);

	}

	/* keep stats containers updated */
	feedDoubleMovingStdDev(filter->rawStats, sample);
	feedDoubleMovingMean(filter->filteredStats, filter->output);

	/* re-tune filter twice per window */
	if( (filter->rawStats->meanContainer->counter % ( filter->rawStats->meanContainer->capacity / 2)) == 0) {
		outlierFilterTune(filter);
	}

	/* replenish filter credit once per window */
	if( filter->config.stepDelay && ((filter->rawStats->meanContainer->counter % filter->rawStats->meanContainer->capacity) == 0)) {
		filter->delayCredit += filter->config.creditIncrement;
		if(filter->delayCredit >= filter->config.delayCredit) {
		    filter->delayCredit = filter->config.delayCredit;
		}
		DBG_LOCAL_ID(filter,"credit added, now %d\n", filter->delayCredit);
	}

	return ret;

}