我有一些环境传感器,我想检测温度的突然变化,以及随时间推移的缓慢趋势......但是我想根据内存中的内容进行大部分数学运算,参数可能如下所示: (可能会有变化)
(注意:括号中的项目是在添加数据时实时计算的)
- 5 分钟(导数、最大值、最小值、平均值)+ 最近 3 小时的 36 个数据点
- 10 分钟(导数、最大值、最小值、平均值)+ 0 个数据点,计算基于 5 分钟样本
- 30 分钟(导数、最大值、最小值、平均值)+ 0 个数据点,计算基于 5 分钟样本
- 每小时(导数、最大值、最小值、平均值)+ 最近 1 天的 24 个数据点
- 每日(导数、最大值、最小值、平均值)+ 当前月份的 32 个数据点
- 每月(导数、最大值、最小值、平均值)+ 过去一年的 12 个数据点
每个数据点都是一个两字节的 float 。所以每个传感器将消耗多达 124 个 float ,加上 24 个计算变量。我希望在 .NET 嵌入式设备允许的情况下支持尽可能多的传感器。
由于我在这个项目中使用的是嵌入式设备,因此我的内存受到限制,IO 和 CPU 能力也受到限制。
您将如何在 .NET 中实现它?到目前为止,我已经创建了几个结构并将其称为“TrackableFloat
”,其中插入一个值会导致旧值从数组中删除并完成重新计算。
The only thing that makes this more complicated than it would be, is that for any sensor does not report back data, then that datapoint needs to be excluded/ignored from all subsequent realtime calulations.
总而言之,如果任何值:(导数、最大值、最小值、平均值)达到预定义的设置,则会触发 .NET 事件
我认为有人会认为这是一个有趣的问题,并且很想听听他们将如何实现它。
您会使用类还是结构?
您将如何触发计算? (最有可能的事件)
如何触发警报?
您将如何分层存储数据?
有图书馆已经在做这样的事情了吗? (也许这应该是我的第一个问题)
如何有效地计算导数?
这是我的第一个尝试,它没有完全符合规范,但非常有效。有兴趣听听您的想法。
enum UnitToTrackEnum
{
Minute,
FiveMinute,
TenMinute,
FifteenMinute,
Hour,
Day,
Week,
Month,
unknown
}
class TrackableFloat
{
object Gate = new object();
UnitToTrackEnum trackingMode = UnitToTrackEnum.unknown;
int ValidFloats = 0;
float[] FloatsToTrack;
public TrackableFloat(int HistoryLength, UnitToTrackEnum unitToTrack)
{
if (unitToTrack == UnitToTrackEnum.unknown)
throw new InvalidOperationException("You must not have an unknown measure of time to track.");
FloatsToTrack = new float[HistoryLength];
foreach (var i in FloatsToTrack)
{
float[i] = float.MaxValue;
}
trackingMode = unitToTrack;
Min = float.MaxValue;
Max = float.MinValue;
Sum = 0;
}
public void Add(DateTime dt, float value)
{
int RoundedDTUnit = 0;
switch (trackingMode)
{
case UnitToTrackEnum.Minute:
{
RoundedDTUnit = dt.Minute;
break;
}
case UnitToTrackEnum.FiveMinute:
{
RoundedDTUnit = System.Math.Abs(dt.Minute / 5);
break;
}
case UnitToTrackEnum.TenMinute:
{
RoundedDTUnit = System.Math.Abs(dt.Minute / 10);
break;
}
case UnitToTrackEnum.FifteenMinute:
{
RoundedDTUnit = System.Math.Abs(dt.Minute / 15);
break;
}
case UnitToTrackEnum.Hour:
{
RoundedDTUnit = dt.Hour;
break;
}
case UnitToTrackEnum.Day:
{
RoundedDTUnit = dt.Day;
break;
}
case UnitToTrackEnum.Week:
{
//RoundedDTUnit = System.Math.Abs( );
break;
}
case UnitToTrackEnum.Month:
{
RoundedDTUnit = dt.Month;
break;
}
case UnitToTrackEnum.unknown:
{
throw new InvalidOperationException("You must not have an unknown measure of time to track.");
}
default:
break;
}
bool DoRefreshMaxMin = false;
if (FloatsToTrack.Length < RoundedDTUnit)
{
if (value == float.MaxValue || value == float.MinValue)
{
// If invalid data...
lock (Gate)
{
// Get rid of old data...
var OldValue = FloatsToTrack[RoundedDTUnit];
if (OldValue != float.MaxValue || OldValue != float.MinValue)
{
Sum -= OldValue;
ValidFloats--;
if (OldValue == Max || OldValue == Min)
DoRefreshMaxMin = true;
}
// Save new data
FloatsToTrack[RoundedDTUnit] = value;
}
}
else
{
lock (Gate)
{
// Get rid of old data...
var OldValue = FloatsToTrack[RoundedDTUnit];
if (OldValue != float.MaxValue || OldValue != float.MinValue)
{
Sum -= OldValue;
ValidFloats--;
}
// Save new data
FloatsToTrack[RoundedDTUnit] = value;
Sum += value;
ValidFloats++;
if (value < Min)
Min = value;
if (value > Max)
Max = value;
if (OldValue == Max || OldValue == Min)
DoRefreshMaxMin = true;
}
}
// Function is placed here to avoid a deadlock
if (DoRefreshMaxMin == true)
RefreshMaxMin();
}
else
{
throw new IndexOutOfRangeException("Index " + RoundedDTUnit + " is out of range for tracking mode: " + trackingMode.ToString());
}
}
public float Sum { get; set; }
public float Average
{
get
{
if (ValidFloats > 0)
return Sum / ValidFloats;
else
return float.MaxValue;
}
}
public float Min { get; set; }
public float Max { get; set; }
public float Derivative { get; set; }
public void RefreshCounters()
{
lock (Gate)
{
float sum = 0;
ValidFloats = 0;
Min = float.MaxValue;
Max = float.MinValue;
foreach (var i in FloatsToTrack)
{
if (i != float.MaxValue || i != float.MinValue)
{
if (Min == float.MaxValue)
{
Min = i;
Max = i;
}
sum += i;
ValidFloats++;
if (i < Min)
Min = i;
if (i > Max)
Max = i;
}
}
Sum = sum;
}
}
public void RefreshMaxMin()
{
if (ValidFloats > 0)
{
Min = float.MaxValue;
Max = float.MinValue;
lock (Gate)
{
foreach (var i in FloatsToTrack)
{
if (i != float.MaxValue || i != float.MinValue)
{
if (i < Min)
Min = i;
if (i > Max)
Max = i;
}
}
}
}
}
}
最佳答案
关于c# - 需要以内存/CPU 效率分析特定时间间隔内的近实时数据的想法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4813556/