我正在尝试定期合并两个传感器数据流,而我在Rx中无法正常执行此操作。我提出的最好的是下面的示例,但我怀疑这是Rx的最佳使用。
有更好的方法吗?
我尝试了Sample(),但传感器以不规则的间隔,慢(> 1秒)和快(<1秒)产生值。 Sample()似乎只处理快速数据。
Observable<SensorA> sensorA = ... /* hot */
Observable<SensorB> sensorB = ... /* hot */
SensorA lastKnownSensorA;
SensorB lastKnownSensorB;
sensorA.Subscribe(s => lastKnownSensorA = s);
sensorB.Subscribe(s => lastKnownSensorB = s);
var combined = Observable.Interval(TimeSpan.FromSeconds(1))
.Where(t => _lastKnownSensorA != null)
.Select(t => new SensorAB(lastKnownSensorA, lastKnownSensorB)
答案 0 :(得分:4)
我认为@JonasChapuis的答案可能就是你所追求的,但有几个问题可能会有问题:
CombineLatest
在所有源都发出至少一个值之前不会发出值,这可能会导致从更快的源中丢失数据直到该点。可以使用StartWith
在每个传感器流上播种null object或默认值来减轻这种情况。
Sample
将不会发出值。我无法从这个问题中判断出这是否可取,但如果没有,那就有一个有趣的诀窍来解决这个问题,使用&#34; pace&#34;流,如下所述创建固定频率,而不是Sample
获得的最大频率。
要解决CombineLatest
问题,请为传感器流确定适当的空值 - 我通常通过类型上的静态Null
属性使这些值可用 - 这使得意图非常明确。对于值类型,使用Nullable<T>
也是一个不错的选择:
Observable<SensorA> sensorA = ... .StartWith(SensorA.Null);
Observable<SensorB> sensorB = ... .StartWith(SensorB.Null);
N.B。不要将StartWith
仅应用于CombinedLatest
...的输出,而这不会导致帮助!
现在,如果您需要定期结果(自然可能包括最近读数的重复),请创建一个&#34;步伐&#34;以所需间隔发出的流:
var pace = Observable.Interval(TimeSpan.FromSeconds(1));
然后按如下方式组合,省略结果中的步速值:
var sensorReadings = Observable.CombineLatest(
pace, sensorA, sensorB,
(_, a, b) => new SensorAB(a,b));
如果您想以特定流的速度推动输出,那么还非常有效地了解MostRecent
运算符,它可以非常有效地与Zip
结合使用。请参阅这些答案,我演示了这种方法:How to combine a slow moving observable with the most recent value of a fast moving observable以及处理多个流的更有趣的调整:How do I combine three observables such that
答案 1 :(得分:2)
每次使用CombineLatest()
运算符合并传感器的最新值时,如何生成值,然后Sample()
以确保每秒一次测量的最大频率?
sensorA.CombineLatest(sensorB, (a, b) => new {A=a, B=b}).Sample(TimeSpan.FromSeconds(1))