C# 如何监控IObservable<;双倍>;对于超出范围的长时间
我有一个C# 如何监控IObservable<;双倍>;对于超出范围的长时间,c#,system.reactive,C#,System.reactive,我有一个IObservable,它以一定的间隔给出从传感器读取的值。我想在传感器的值超出范围很长一段时间后发出信号 作为一个具体的例子,假设可观察到的是一个温度传感器。我想监测温度何时超过100°C 5秒钟。也就是说,从IObservable生成一个可观察或事件,当温度超过100°C并持续5秒时触发一次。如果任何数量的样品的温度读数高于100°C且持续时间少于5秒,则此操作无效。第一组样品温度均高于100°C后5秒,应发出信号。如果该值继续高于100°C,则在温度降至100°C以下并再次超过该值
IObservable
,它以一定的间隔给出从传感器读取的值。我想在传感器的值超出范围很长一段时间后发出信号
作为一个具体的例子,假设可观察到的是一个温度传感器。我想监测温度何时超过100°C 5秒钟。也就是说,从IObservable
生成一个可观察或事件,当温度超过100°C并持续5秒时触发一次。如果任何数量的样品的温度读数高于100°C且持续时间少于5秒,则此操作无效。第一组样品温度均高于100°C后5秒,应发出信号。如果该值继续高于100°C,则在温度降至100°C以下并再次超过该值5秒之前,不应重新发出信号
对于反应式扩展来说,这似乎应该很简单,但是作为一个新手,我找不到任何东西。我看了一遍,但什么也没找到。我可能只是不知道要寻找的正确术语。应该可以通过使用内置运算符(函数式)来实现,但通过实现带有命令式逻辑的自定义运算符来实现则更加困难
public static IObservable<Unit> Alarm<T>(this IObservable<T> source,
T threshold, TimeSpan delay, IComparer<T> comparer = null)
{
comparer = comparer ?? Comparer<T>.Default;
return Observable.Create<Unit>(o =>
{
Stopwatch stopwatch = new Stopwatch();
int alarmState = 0; // 0: OK, 1: above threshold, 2: signal transmitted
return source.Subscribe(x =>
{
if (comparer.Compare(x, threshold) >= 0)
{
if (alarmState == 0)
{
alarmState = 1;
stopwatch.Restart();
}
else if (alarmState == 1 && stopwatch.Elapsed >= delay)
{
alarmState = 2;
o.OnNext(Unit.Default);
}
}
else
{
alarmState = 0;
}
}, o.OnError, o.OnCompleted);
});
}
公共静态IObservable报警(此IObservable源,
T阈值,时间间隔延迟,IComparer比较器=null)
{
比较器=比较器??比较器。默认值;
返回可观察的。创建(o=>
{
秒表秒表=新秒表();
int alarmState=0;//0:正常,1:高于阈值,2:信号已传输
返回source.Subscribe(x=>
{
如果(比较器比较(x,阈值)>=0)
{
如果(alarmState==0)
{
alarmState=1;
stopwatch.Restart();
}
else if(alarmState==1&&stopwatch.appeased>=延迟)
{
报警状态=2;
o、 OnNext(单位默认值);
}
}
其他的
{
alarmState=0;
}
},o.OnError,o.OnCompleted);
});
}
我考虑了一下,意识到我们可能想得太多了
让我们从一个可观察的阈值开始:
var threshold =
source
.Select(temp => temp > 100)
.DistinctUntilChanged();
当更改为大于或小于100时,将生成一个值。如果它继续高于100或保持低于100,则不会产生任何新值
现在让我们来定义:
var alarmUp =
threshold
.Throttle(TimeSpan.FromSeconds(5))
.Where(cond => cond == true);
在这里,如果条件在5秒钟内没有改变,油门
操作员会吐出一个值。现在它可以是true
(>100)持续5秒,或者false
(<100)。
我们只对它的真实性感兴趣
在这两种情况之间,如果有任何变化,油门操纵器将被重置,因此该状态必须保持至少5秒钟。当出现新值时,您应该使用
.Switch()
,以便忽略以前出现的任何值的结果
以下是您需要的查询:
IObservable<Unit> query =
source
.Select(x => x > 100.0)
.DistinctUntilChanged()
.Select(x => x
? Observable.Timer(TimeSpan.FromSeconds(5.0)).Select(x => Unit.Default)
: Observable.Never<Unit>())
.Switch();
这不符合OP的要求。如果源可观测值仅产生一个高于
100
的值,则该操作符在5.0
秒后不会触发。事实上,它永远不会开火。答案需要一个5.0
第二个计时器才能按照OP的要求工作。@Enigmativity这确实是我的解决方案中的一个缺陷,谢谢你指出。我没有提到这一点,因为OP规定传感器应该以某种固定的间隔产生值。无论如何都比我的好,应该优先考虑。谢谢。在这种情况下,我实际上更喜欢节流阀解决方案<代码>开关
功能更强大,可用于节流
的更多场景,因此学习它很好。向上投票。这是我最初尝试编写的解决方案,但失败了。:-)回答得很好。关于我刚刚学到的操作符的一些信息:忽略一个可观察序列中的元素,该序列在指定的相对时间内后跟另一个元素。在ReactiveX词汇表中称为。
IObservable<Unit> query =
source
.Select(x => x > 100.0)
.DistinctUntilChanged()
.Select(x => x
? Observable.Timer(TimeSpan.FromSeconds(5.0))
: Observable.Never<long>())
.Switch()
.Select(x => Unit.Default);