c# - 需要以内存/CPU 效率分析特定时间间隔内的近实时数据的想法

标签 c# math real-time .net-micro-framework

我有一些环境传感器,我想检测温度的突然变化,以及随时间推移的缓慢趋势......但是我想根据内存中的内容进行大部分数学运算,参数可能如下所示: (可能会有变化)

(注意:括号中的项目是在添加数据时实时计算的)

  • 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 事件

我认为有人会认为这是一个有趣的问题,并且很想听听他们将如何实现它。

  1. 您会使用类还是结构?

  2. 您将如何触发计算? (最有可能的事件)

  3. 如何触发警报?

  4. 您将如何分层存储数据?

  5. 有图书馆已经在做这样的事情了吗? (也许这应该是我的第一个问题)

  6. 如何有效地计算导数?

这是我的第一个尝试,它没有完全符合规范,但非常有效。有兴趣听听您的想法。

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;
                    }
                }
            }
        }
    }
}

最佳答案

您应该考虑查看 CEP类似图书馆 Nesper .

关于c# - 需要以内存/CPU 效率分析特定时间间隔内的近实时数据的想法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4813556/

相关文章:

c# - ActionResult 到字符串

c# - 在迁移期间将标识设置为先前创建的列

c# - 计算 X 位掩码的最快方法?

mongodb - 实时数据馈送 + NodeJS 和 MongoDB

C# 8.0 单元测试 switch 表达式未涵盖

c# - 通过电子邮件发送日志文件?统一

c - strtoll 和 division 没有返回正确的数字

C 努力将无符号整数打包到 uint64_t 中

c++ - 为实时操作配置 SQLite

ruby-on-rails - MongoDB 中的实时聚合策略