/// <summary> /// проверка на соответствие нормальному закону распределния ряда. озвращая критерий согласия Пирсона для этого ряда /// http://www.ekonomstat.ru/kurs-lektsij-po-teorii-statistiki/403-proverka-sootvetstvija-rjada-raspredelenija.html /// https://life-prog.ru/2_84515_proverka-po-kriteriyu-hi-kvadrat.html критерий пирсона /// https://math.semestr.ru/group/example-normal-distribution.php для нормального распределения /// </summary> /// <param name="range">ряд</param> /// <param name="parameter">проверяемый параметр</param> /// <returns></returns> private static double checkNormalLaw(RawRange range, MeteorologyParameters parameter) { GradationInfo <GradationItem> grads; switch (parameter) { case MeteorologyParameters.Speed: grads = new GradationInfo <GradationItem>(0, SPEED_GRADATION_STEP, range.Max((item) => { return(item.Speed); })); //градации скорости break; case MeteorologyParameters.Direction: StatisticalRange <WindDirections16> srwd = StatisticEngine.GetDirectionExpectancy(range, GradationInfo <WindDirections16> .Rhumb16Gradations); return(0); case MeteorologyParameters.Temperature: grads = new GradationInfo <GradationItem>(0, TEMPERATURE_GRADATION_STEP, range.Max((item) => { return(item.Temperature); })); //градации температуры break; case MeteorologyParameters.Wetness: grads = new GradationInfo <GradationItem>(0, WETNESS_GRADATION_STEP, range.Max((item) => { return(item.Wetness); })); //градации влажности break; default: throw new WindEnergyException("Этот параметр не реализован"); } //РАСЧЕТ ДЛЯ ВСЕХ, КРОМЕ НАПРАВЛЕНИЙ StatisticalRange <GradationItem> stat_range = StatisticEngine.GetExpectancy(range, grads, parameter); //статистический ряд // TODO: расчет критерия пирсона для ряда return(0); }
/// <summary> /// преобразует ряд наблюдений в статистику /// </summary> /// <param name="range"></param> public Dataset(RawRange range, MeteorologyParameters param, IHoursModel model) : this() { for (int i = 1; i <= 12; i++) //цикл по месяцам { switch (param) { case MeteorologyParameters.AllSkyInsolation: double aver = (from t in range where t.Date.Month == i select t.AllSkyInsolation).Average(); DataHours <double> hours = model.GetData(aver, param); Months month = (Months)i; this[month] = hours; break; case MeteorologyParameters.ClearSkyInsolation: double aver2 = (from t in range where t.Date.Month == i select t.ClearSkyInsolation).Average(); DataHours <double> hours2 = model.GetData(aver2, param); Months month2 = (Months)i; this[month2] = hours2; break; default: throw new Exception("Этот параметр не реализован"); } } }
public DataHours <double> GetData(double dailySum, MeteorologyParameters allSkyInsolation) { DataHours <double> res = new DataHours <double>(); for (int i = 0; i < 24; i++) { res.Add(i, dailySum / 24d); } return(res); }
/// <summary> /// возвращает минимальное ограничение для заданого параметра /// </summary> /// <param name="paramter">тип параметра</param> /// <returns></returns> internal double GetMinimal(MeteorologyParameters paramter) { switch (paramter) { case MeteorologyParameters.Direction: double min = directionInclude.Min(new Func <Diapason <double>, double>((diapason) => { return(diapason.From); })); return(min); case MeteorologyParameters.Speed: double mins = speedInclude.Min(new Func <Diapason <double>, double>((diapason) => { return(diapason.From); })); return(mins); default: throw new Exception("Этот параметр не реализован"); } }
/// <summary> /// создание нового интерполятора с заданными значениями на основе существующего базового ряда наблюдения /// </summary> /// <param name="func">известные значения функции в заданной точке</param> /// <param name="baseRange">базовый ряд (с ближайшей МС), на основе которого будет происходить восстановление</param> /// <param name="parameterType">тип мтеорологического параметра</param> /// <param name="replaceExistMeasurements">Заменять существующие измерения в исходном ряде на расчетные</param> public NearestMSInterpolateMethod(Dictionary <double, double> func, RawRange baseRange, MeteorologyParameters parameterType, bool replaceExistMeasurements) { if (func.Keys.Count == 0) { Empty = true; return; } Empty = false; this.parameterType = parameterType; this.func = func; this.replaceExistMeasurements = replaceExistMeasurements; this.nearestRange = baseRange; //расчет диапазона сделанных измерений baseRange = new RawRange(baseRange.OrderBy(x => x.Date).ToList()); interpolationDiapason.From = Math.Max(baseRange[0].DateArgument, func.Keys.Min()); //максимальную дату из начал каждой функции interpolationDiapason.To = Math.Min(baseRange[baseRange.Count - 1].DateArgument, func.Keys.Max()); //минимальную дату из концов каждой функции double a = 0, b = 0, r = 0; //коэффициенты прямой и коэффициент корреляции Dictionary <double, double> baseFunc = baseRange.GetFunction(parameterType); //функция базового ряда List <double>[] tableCoeff = calcTableCoeff(func, baseFunc); //таблица для расчёта коэффициентов a, b, r a = getParameterA(tableCoeff); //коэффициенты прямой b = getParameterB(tableCoeff, a); r = getParameterR(tableCoeff); //коэффициент корреляции //проверка попадания коэфф корреляции в допустимый диапазон (если для этого параметра надо проверять диапазон) if (r < Vars.Options.MinimalCorrelationCoeff && Vars.Options.MinimalCorrelationControlParametres.Contains(parameterType)) { throw new Exception("Недостаточное коррелирование функций"); } //ФУНКЦИЯ ПОЛУЧЕНИЯ ЗНАЧЕНИЯ getRes = new Func <double, double>((x) => { //если в исходном ряде есть это значение и не надо заменять исходное, то его и возвращаем if (func.ContainsKey(x) && !replaceExistMeasurements) { return(func[x]); } //Если в базовой функции нет измерения за этой время, то возвращаем NaN //иначе расчитываем скорость по полученной зависимости. if (!baseFunc.ContainsKey(x)) { return(double.NaN); } else { if (baseFunc[x] == 0) //если в базовой функции это значение равно нулю, то возвращаем NaN, чтоб не завышать результат прибавлением b { return(double.NaN); } else { return(a * baseFunc[x] + b); } } }); }
/// <summary> /// создание нового интерполятора с заданными значениями на основе существующего интерполятора (в том случае, если для этой точки уже был создан интерполятор) /// </summary> /// <param name="func">известные значения функции</param> /// <param name="baseInterpolator">интерполятор, откуда взять ряд наблюдения для этого экземпляра</param> /// <param name="parameterType">тип параметра для восстановления</param> /// <param name="replaceExistMeasurements">Заменять существующие измерения в исходном ряде на расчетные</param> public NearestMSInterpolateMethod(Dictionary <double, double> func, NearestMSInterpolateMethod baseInterpolator, MeteorologyParameters parameterType, bool replaceExistMeasurements) : this(func, baseInterpolator.nearestRange, parameterType, replaceExistMeasurements) { }
/// <summary> /// создаёт новый интерполятор для заданной точки с заданной функций и типом расчетного параметра /// </summary> /// <param name="func">известные значения функции в заданной точке</param> /// <param name="coordinates">координаты точки, для которой известны значения func</param> /// <param name="parameterType">тип мтеорологического параметра</param> /// <param name="replaceExistMeasurements">Заменять существующие измерения в исходном ряде на расчетные</param> public NearestMSInterpolateMethod(Dictionary <double, double> func, PointLatLng coordinates, MeteorologyParameters parameterType, bool replaceExistMeasurements) : this(func, getNearestRange(func, coordinates), parameterType, replaceExistMeasurements) { }
/// <summary> /// ищет наиболее подходящую к заданной точке МС и получает её ряд. Если ряд не найден, то возвращает null /// </summary> /// <param name="coordinates"></param> /// <param name="r"></param> /// <param name="actionPercent"></param> /// <param name="Range">ряд, для которого подбирается функция</param> /// <exception cref="GetBaseRangeException">Возвращает иснформацию о параметрах, мешающих получить ближайшую МС</exception> /// <returns></returns> internal static RawRange TryGetBaseRange(RawRange Range, PointLatLng coordinates, out double r, Action <int, string> actionPercent) { bool nlaw = CheckNormalLaw(Range, Vars.Options.NormalLawPirsonCoefficientDiapason); if (!nlaw) { throw new WindEnergyException("Исходный ряд не подчиняется нормальному закону распределения"); } DateTime from = Range.Min((ri) => ri.Date).Date, to = Range.Max((ri) => ri.Date).Date; List <RP5MeteostationInfo> mts = Vars.RP5Meteostations.GetNearestMS(coordinates, Vars.Options.NearestMSRadius, false); Dictionary <double, double> funcSpeed = Range.GetFunction(MeteorologyParameters.Speed); //функция скорости на заданном ряде RawRange res = null; double rmax = double.MinValue, total_rmax = double.MinValue; RP5ru provider = new RP5ru(Vars.Options.CacheFolder + "\\rp5.ru"); for (int i = 0; i < mts.Count; i++) { if (actionPercent != null) { actionPercent.Invoke((int)((i * 1d / mts.Count) * 100d), "Поиск подходящей МС..."); } RP5MeteostationInfo m = mts[i]; //если нет диапазона измерений в БД, то загружаем с сайта if (m.MonitoringFrom == DateTime.MinValue) { provider.GetMeteostationExtInfo(ref m); } //если для этой МС нет наблюдений в этом периоде, то переходим на другую if (m.MonitoringFrom > from) { continue; } //загрузка ряда с очередной МС RawRange curRange = null; try { curRange = provider.GetRange(from, to, m); } catch (WindEnergyException wex) // если не удалось получить ряд этой МС, то переходим к следующей { continue; } curRange = new Checker().ProcessRange(curRange, new CheckerParameters(LimitsProviders.StaticLimits, curRange.Position), out CheckerInfo info, null); //исправляем ошибки //СКОРОСТЬ MeteorologyParameters parameter = MeteorologyParameters.Speed; Dictionary <double, double> funcSpeedCurrentNearest = curRange.GetFunction(parameter); //функция скорости на текущей МС //проверка на нормальный закон распределения bool normal = CheckNormalLaw(curRange, Vars.Options.NormalLawPirsonCoefficientDiapason); if (!normal) { continue; } //расчёт и проверка коэфф корреляции List <double>[] table = calcTableCoeff(funcSpeed, funcSpeedCurrentNearest); //таблица для расчет коэффициентов double current_r = getParameterR(table); //коэффициент корреляции //общий максимальный коэфф корреляции if (current_r > total_rmax) { total_rmax = current_r; } //проверяем, можно ли взять эту МС if (current_r > rmax) { //истина, если надо проверять этот параметр на допустимый диапазон корреляции bool needCheck = Vars.Options.MinimalCorrelationControlParametres.Contains(parameter); if ((needCheck && current_r >= Vars.Options.MinimalCorrelationCoeff) || !needCheck) { rmax = current_r; res = curRange; } } } r = rmax; if (res == null) { RP5MeteostationInfo mi = Vars.RP5Meteostations.GetNearestMS(coordinates); double l = EarthModel.CalculateDistance(mi.Position, coordinates); throw new GetBaseRangeException(total_rmax, Vars.Options.MinimalCorrelationCoeff, l, mts.Count, Vars.Options.NearestMSRadius, coordinates); } return(res); }
/// <summary> /// получить статистический ряд по заданным значениям и заданным градациям /// </summary> /// <param name="range"></param> /// <param name="gradations"></param> /// <param name="parameter"></param> /// <returns></returns> public static StatisticalRange <GradationItem> GetExpectancy(IList <RawItem> range, GradationInfo <GradationItem> gradations, MeteorologyParameters parameter = MeteorologyParameters.Speed) { List <double> rang; switch (parameter) { case MeteorologyParameters.Speed: rang = new List <double>(from t in range select t.Speed); break; case MeteorologyParameters.Direction: rang = new List <double>(from t in range select t.Direction); break; case MeteorologyParameters.Temperature: rang = new List <double>(from t in range select t.Temperature); break; case MeteorologyParameters.Wetness: rang = new List <double>(from t in range select t.Wetness); break; default: throw new WindEnergyException("Этот параметр не реализован"); } StatisticalRange <GradationItem> r = new StatisticalRange <GradationItem>(rang, gradations); return(r); }