Ideas needed to analyze real-time data at specific intervals with memory / processor efficiency

I have some environmental sensors and I want to detect sudden changes in temperature and slow trends over time ... however, I would like to do most of the math based on what is in memory with parameters that may look like this: (changes are possible )

(note: items in parens are calculated in real time when adding data)

  • 5 minutes (derivative, max., Min., Aug.) + 36 data points for most of the current 3 hours.
  • 10 minutes (derivative, max., Min., Aug.) + 0 data points, calculation based on a 5-minute sample
  • 30 minutes (derivative, max., Min., Aug.) + 0 data points, calculation based on a 5-minute sample
  • Hourly (derivative, max., Min., Aug.) + 24 date-points for most of the current 1 days.
  • Daily (derivative, max., Min., Avg) + 32 data points for most of the current month.
  • Monthly (derivative, max, min, avg) + 12 databases for the last year

Each datapoint is a byte with two bytes. Thus, each sensor will consume up to 124 Floats, plus 24 calculated variables. I would like as many sensors as the .NET embededd device would allow.

Since I use the built-in device for this project, my memory is limited, as well as my I / O and processor power.

How could you implement this in .NET? So far I have created a couple of structures and called it " TrackableFloat", where inserting a value causes the old one to drop out of the array and recalculate.

, , , , / .

, - : (, 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
1
+1

Source: https://habr.com/ru/post/1788256/


All Articles