private double CalculateNowCast(List <double> thisList) { // // https://en.wikipedia.org/wiki/NowCast_(air_quality_index) // const int NrOfHoursForNowCast = 12; // Standard 12 const int NrOfMinutesInHour = 60; // bool PartialHourValid = false; int arraySize; double Cmin, Cmax; // the min and max concentrations in μg/m3 for this calculation double Omega; // The ratio Cmin/Cmax for this calculation double[] HourlyAverages = new double[NrOfHoursForNowCast]; // To hold the hourly averages of PM values of the last 12 hrs double[] thisArray; // To hold thisList as an array if (thisList.Count < 2 * NrOfMinutesInHour) { return(0.0); // Less than 2 hrs in the list, then skip this and return no value } Sup.LogTraceVerboseMessage($"DoAirLink/CalcNowCast: List contains {thisList.Count} elements present."); thisList.Reverse(); // Make the last hour at the start of the array so i=0 is really the most recent observation if (thisList.Count < NrOfHoursForNowCast * 60) { thisArray = thisList.ToArray(); } else { thisArray = thisList.Take(NrOfHoursForNowCast * 60).ToArray(); } thisList.Reverse(); // reverse the list to the original situation so that it functions correctly when adding new observations arraySize = thisArray.Length; int NrOfFullHours = arraySize / NrOfMinutesInHour; int NrOfMinutesLeft = arraySize % NrOfMinutesInHour; // IF NrOfFullHours == 12 this must always be 0. That should follow from the algorithm // so I don't check (if fail it is a bug, no paranoia mode) Sup.LogTraceVerboseMessage($"DoAirLink/CalcNowCast: NrOfFullHours {NrOfFullHours} / NrOfMinutesLeft = {NrOfMinutesLeft}"); for (int i = 0; i < NrOfFullHours; i++) { HourlyAverages[i] = thisArray[(i * 60)..(i * 60 + 59)].Average();