Подпишитесь, когда два события с предварительными условиями были запущены в течение промежутка времени - PullRequest
2 голосов
/ 06 января 2012

У меня есть событие ValueChanged.Я хочу подписаться на него, используя Rx, только когда Value> 5, за которым следует Value <-5, и оба были запущены в течение 5 секунд. </p>

Мне удалось создать наблюдаемое, которое работает с условием Value.Как я могу проверить, были ли они запущены в течение 5 секунд?

Вот мой код:


IObservable<MyEventArgs> data = Observable.FromEventPattern<...

var up = data.Where(ev => ev.Value > 0.5).Take(1);
var down = data.SkipUntil(up).Where(ev => ev.Value < -0.5).Take(1);

down.Subscribe(ar => { Console.WriteLine("OK"); });

[править]: Это изображение, представляющее мои входные данные, и когда ожидаемый результат должен произойтиenter image description here

[править]: Еще кое-что:

Зачем мне это?;-) Я пытаюсь использовать акселерометр WP7, чтобы обнаружить движение вверх / вниз, которое произошло в течение 'n' секунд и вызвало, по крайней мере, 0,5G (вверх) и менее -0,5G (вниз)

Спасибо, Бартек

Ответы [ 3 ]

1 голос
/ 07 января 2012

На основе «вверх» и «вниз», как указано выше, как насчет следующего кода:

  var  updown=down.Zip(up,(d,u)=> d).Timeout( TimeSpan.FromSeconds( 5 ) ).Retry();
  updown.Subscribe( ar => { Console.WriteLine( "OK" ); } );

Я еще не проверял это, но, возможно, стоит попробовать это.

1 голос
/ 06 января 2012

Как насчет этого:

data.TimeStamp(anAppropriateSchedulerPerhapsDispatcherSchedulerOrTaskPool)
    .Buffer(2 /*items*/, /*advance by*/ 1)
    .Where(x => x[0].Value > 5 && x[1].Value < -5 && 
        x[1].Timestamp - x[0].Timestamp < TimeSpan.FromSeconds(5));
    .Subscribe(x => Console.WriteLine("Found it!"));
0 голосов
/ 07 января 2012

Оператор Join - это то, что вы ищете.

Исходя из вашего рисунка, я предположил, что вы хотите, чтобы окно было фиксированной продолжительностью от первого последовательного высокого или низкого значения. Функция RisingEdges (лучшее название, которое я смог придумать в короткие сроки) фильтрует источник, наблюдаемый по этим первым последовательным значениям.

<Extension()>
Public Function RisingEdges(Of T)(source As IObservable(Of T),
                                  level As Func(Of T, Boolean)
                                 ) As IObservable(Of T)
    Return source.Select(Function(v) Tuple.Create(v, level(v))) _
                 .DistinctUntilChanged(Function(vb) vb.Item2) _
                 .Where(Function(vb) vb.Item2) _
                 .Select(Function(vb) vb.Item1)
End Function

Оттуда вы можете использовать оператор Join, чтобы найти случаи, когда эти края расположены близко друг к другу.

<Extension()>
Public Function FindClosePeaks(Of T)(source As IObservable(Of T),
                                     high As Func(Of T, Boolean), 
                                     low As Func(Of T, Boolean),
                                     windowDuration As TimeSpan
                                    ) As IObservable(Of Tuple(Of T, T))
    Return Observable.Join(source.RisingEdges(high),
                           source.RisingEdges(low),
                           Function(h) Observable.Timer(windowDuration),
                           Function(l) Observable.Timer(windowDuration),
                           Function(h, l) Tuple.Create(h, l))
End Function

Остерегайтесь использования этой функции с холодными наблюдаемыми, поскольку на нее будет две подписки. В зависимости от источника, это может быть приемлемо, или вам может потребоваться сделать его «горячим» с помощью Publish.

Мне не совсем понятно, что вы искали в качестве конечного результата, но, надеюсь, это должно приблизить вас к тому, что вы хотите.

...