Ejemplo n.º 1
0
        /// <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);
                    }
                }
            });
        }
Ejemplo n.º 2
0
        /// <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);
        }