【发布时间】:2011-01-27 06:53:41
【问题描述】:
我有一些环境传感器,我想检测温度的突然变化,以及随时间推移的缓慢趋势......但是我想根据内存中的内容进行大部分数学运算,参数可能如下所示: (可能会发生变化)
(注意:括号中的项目是在添加数据时实时计算的)
- 5 分钟(导数、最大值、最小值、平均值)+ 最近 3 小时的 36 个数据点
- 10 分钟(导数、最大值、最小值、平均值)+ 0 个数据点,计算基于 5 分钟样本
- 30 分钟(导数、最大值、最小值、平均值)+ 0 个数据点,计算基于 5 分钟样本
- 每小时(微分、最大值、最小值、平均值)+ 最近 1 天的 24 个数据点
- 最近一个月的每日(微分、最大值、最小值、平均值)+ 32 个数据点
- 每月(微分、最大值、最小值、平均值)+ 过去一年的 12 个数据点
每个数据点都是一个两字节浮点数。所以每个传感器将消耗多达 124 个浮点数,加上 24 个计算变量。我想支持 .NET 嵌入式设备允许的尽可能多的传感器。
由于我在此项目中使用嵌入式设备,因此我的内存受到限制,我的 IO 和 CPU 能力也受到限制。
您将如何在 .NET 中实现这一点?到目前为止,我已经创建了几个结构并将其称为“TrackableFloat”,其中插入一个值会导致旧的值从数组中删除并完成重新计算。
唯一让这更重要的东西 比想象的要复杂,是吗 对于任何传感器都不会报告 数据,那么该数据点需要是 排除/忽略所有后续 实时计算。
说完了,如果任何值:(derivative, max,min,avg) 达到预定义的设置,则触发 .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;
}
}
}
}
}
}
【问题讨论】:
-
这些 2 字节浮点数是什么格式?您是否使用它们进行计算或转换为普通浮点数?这是什么类型的 CPU?
标签: c# math real-time .net-micro-framework