protected ListeningProbe() { _maxDataStoresPerSecond = null; // no data rate limit by default _keepDeviceAwake = DefaultKeepDeviceAwake; _deviceAwake = false; _incomingDataRateCalculator = new DataRateCalculator(100); // store all data to start with. we'll compute a store/drop rate after data have arrived. _samplingModulus = 1; _samplingModulusMatchAction = SamplingModulusMatchAction.Store; }
public sealed override Task <bool> StoreDatumAsync(Datum datum, CancellationToken?cancellationToken = default(CancellationToken?)) { bool store = true; float maxDataStoresPerSecond = _maxDataStoresPerSecond.GetValueOrDefault(-1); // 0 (or negligible) data per second: don't store. if max data per second is not set, the following inequality will be false. if (Math.Abs(maxDataStoresPerSecond) < DATA_RATE_EPSILON) { store = false; } // non-negligible (or default -1) data per second: check data rate else if (maxDataStoresPerSecond > 0) { _incomingDataRateCalculator.Add(datum); // recalculate the sampling modulus after accumulating a full sample size in the data rate calculator if ((_incomingDataRateCalculator.TotalAdded % _incomingDataRateCalculator.SampleSize) == 0) { double incomingDataPerSecond = _incomingDataRateCalculator.DataPerSecond; double extraDataPerSecond = incomingDataPerSecond - maxDataStoresPerSecond; // if we're not over the limit then store all samples if (extraDataPerSecond <= 0) { _samplingModulus = 1; _samplingModulusMatchAction = SamplingModulusMatchAction.Store; } // otherwise calculate a modulus that will get as close as possible to the desired rate given the empirical rate else { double samplingModulusMatchRate = extraDataPerSecond / incomingDataPerSecond; _samplingModulusMatchAction = SamplingModulusMatchAction.Drop; if (samplingModulusMatchRate > 0.5) { samplingModulusMatchRate = 1 - samplingModulusMatchRate; _samplingModulusMatchAction = SamplingModulusMatchAction.Store; } if (_samplingModulusMatchAction == SamplingModulusMatchAction.Store) { // round the (store) modulus down to oversample -- more is better, right? _samplingModulus = (int)Math.Floor(1 / samplingModulusMatchRate); } else { // round the (drop) modulus up to oversample -- more is better, right? _samplingModulus = (int)Math.Ceiling(1 / samplingModulusMatchRate); } } } bool isModulusMatch = (_incomingDataRateCalculator.TotalAdded % _samplingModulus) == 0; if ((_samplingModulusMatchAction == SamplingModulusMatchAction.Store && !isModulusMatch) || (_samplingModulusMatchAction == SamplingModulusMatchAction.Drop && isModulusMatch)) { store = false; } } if (store) { return(base.StoreDatumAsync(datum, cancellationToken)); } else { return(Task.FromResult(false)); } }