0

Given a Deedle Series with time as the row index, I need to find the time at which the signal first satisfies a condition (in this case, stays below 0.005 for 50ms).

Currently I take a 50ms moving window and create a series from the start time and maximum value of each window, then get the first one whose max is < 0.005. It works well enough but can be very inefficient.

// Assume a timestep of 1ms
int numSteps = 50;

// Create a series from the first index and max of each window
var windowMaxes = mySeries.WindowInto(
    numSteps,
    s => new KeyValuePair<double, double>(s.FirstKey(), s.Max()));
var zeroes = windowMaxes.Where(kvp => kvp.Value <= 0.005);

// Set to -1 if the condition was never satisfied
var timeOfZero = zeroes.KeyCount > 0 ? zeroes.FirstKey() : -1D;

The problem is that it searches the entire series (which can get very large) even if the first window meets the condition.

Is there a simply way to do this but stop when the first window is found, instead of searching the entire Series?

1 Answers1

1

Well I couldn't find a Deedly one-liner or any handy LINQ commands to do it, so I wrote the following extension method:

public static K FirstWindowWhere<K, V>(
    this Series<K, V> series,
    Func<V, bool> condition,
    int windowSize)
{
    int consecutiveTrues = 0;
    foreach (var datum in series.Observations)
    {
        if (condition(datum.Value))
        {
            consecutiveTrues++;
        }
        else
        {
            consecutiveTrues = 0;
        }

        if (consecutiveTrues == windowSize)
        {
            return datum.Key;
        }
    }
    return default(K);
}

To call with my above condition:

double zeroTime = mySeries.FirstWindowWhere(d => d <= 0.005, numSteps);

I tried a few different methods including a nice elegant one that used Series.Between instead of Series.GetObservations but it was noticeably slower. So this will do unless someone has a simpler/better solution.