Пример #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);
                    }
                }
            });
        }
Пример #2
0
        /// <summary>
        /// восстановить ряд до нужного интревала наблюдений
        /// </summary>
        /// <param name="range">Ряд для восстановления</param>
        /// <param name="param">параметры восстановления</param>
        /// <param name="actionPercent">изменение процента выполнения</param>
        /// <param name="actionAfter">действие после обработки</param>
        /// <returns></returns>
        public Task <RawRange> ProcessRange(RawRange range, RestorerParameters param, Action <int, string> actionPercent, Action <RawRange, RawRange, double> actionAfter)
        {
            RawRange baseRange = null;//ряд, на основе которого будет идти восстановление

            range.PerformRefreshQuality();
            Range              = new RawRange(range.OrderBy(x => x.Date).ToList());
            this.param         = param;
            this.actionPercent = actionPercent;
            prepareIterpolators();


            //расчет каждого значения
            Task <RawRange> tsk = new Task <RawRange>(() =>
            {
                ConcurrentBag <RawItem> resultCollection = new ConcurrentBag <RawItem>();
                Parallel.ForEach(newRangeX, (p) =>
                {
                    incrementCounter();

                    StandartIntervals currentInterval = getIntervalOfDateArgument(p, range);
                    if (currentInterval == StandartIntervals.None)
                    {
                        throw new WindEnergyException("Что-то не так. Не удалось найти интервал наблюдений");
                    }

                    double speed, direct, temp, wet, press;
                    //если целевой интервал меньше текущего, то интерполируем как обычно
                    if ((int)currentInterval >= (int)param.Interval || param.Method == InterpolateMethods.NearestMeteostation)
                    {
                        speed  = methodSpeeds.GetValue(p);
                        direct = methodDirects.GetValue(p);
                        temp   = methodTemp.GetValue(p);
                        wet    = methodWet.GetValue(p);
                        press  = methodPress.GetValue(p);
                    }
                    else         //Если целевой интервал больше текущего, то надо осреднять значения за целевой интервал
                    {
                        DateTime from = new DateTime().AddMinutes(p - (int)param.Interval);
                        DateTime to   = new DateTime().AddMinutes(p);
                        RawRange part = range.GetRange(true, false, from, to, null, null);
                        if (part.Count == 0)
                        {
                            speed  = methodSpeeds.GetValue(p);
                            direct = methodDirects.GetValue(p);
                            temp   = methodTemp.GetValue(p);
                            wet    = methodWet.GetValue(p);
                            press  = methodPress.GetValue(p);
                        }
                        else
                        {
                            speed  = part.Average(item => item.Speed);
                            direct = part.Average(item => item.Direction > 0 ? item.Direction : 0);
                            temp   = part.Average(item => item.Temperature);
                            wet    = part.Average(item => item.Wetness);
                            press  = part.Average(item => item.Pressure);
                        }
                    }
                    if (double.IsNaN(speed))
                    {
                        return;
                    }
                    if (speed < 0)
                    {
                        speed = 0;
                    }

                    resultCollection.Add(new RawItem(p, speed, direct, temp, wet, press));
                });

                RawRange res     = new RawRange(resultCollection.OrderBy(item => item.DateArgument));
                res.Position     = range.Position;
                res.Meteostation = range.Meteostation;
                res.Height       = range.Height;
                if (actionAfter != null)
                {
                    actionAfter.Invoke(res, baseRange, r);
                }
                return(res);
            });

            tsk.Start();
            return(tsk);
        }
Пример #3
0
        /// <summary>
        /// загрузить файл данных с сайта и открыть ряд наблюдений
        /// </summary>
        /// <param name="fromDate">с какой даты</param>
        /// <param name="toDate">до какой даты</param>
        /// <param name="info">Метеостанция, с которой загружается ряд</param>
        /// <param name="onPercentChange"></param>
        /// <param name="checkStop"></param>
        /// <returns></returns>
        public RawRange GetRange(DateTime fromDate, DateTime toDate, RP5MeteostationInfo info, Action <double> onPercentChange = null, Func <bool> checkStop = null)
        {
            if (toDate < fromDate)
            {
                throw new WindEnergyException("Даты указаны неверно");
            }

            switch (Vars.Options.RP5SourceEngine)
            {
            case RP5SourceType.LocalDBSearch:
                return(Vars.RP5Database.GetRange(fromDate, toDate, info, onPercentChange, checkStop));

            case RP5SourceType.OnlineAPI:
                if (toDate - fromDate > TimeSpan.FromDays(365 * LOAD_STEP_YEARS))     // если надо скачать больше трёх лет, то скачиваем по частям
                {
                    TimeSpan span = toDate - fromDate;

                    RawRange res1 = new RawRange();
                    DateTime dt;
                    int      i     = 0;
                    int      total = (int)(span.TotalDays / (365 * LOAD_STEP_YEARS)) + 1;
                    for (dt = fromDate; dt <= toDate; dt += TimeSpan.FromDays(365 * LOAD_STEP_YEARS))
                    {
                        if (checkStop != null)
                        {
                            if (checkStop.Invoke())
                            {
                                break;
                            }
                        }

                        if (onPercentChange != null)
                        {
                            double pc = ((i / (double)total) * 100d);
                            onPercentChange.Invoke(pc);
                        }
                        RawRange r = GetRange(dt, dt + TimeSpan.FromDays(365 * LOAD_STEP_YEARS), info, onPercentChange, checkStop);
                        res1.Add(r);
                        res1.Name         = r.Name;
                        res1.Position     = r.Position;
                        res1.Meteostation = r.Meteostation;
                        res1.Height       = 10; //высота всегда 10м
                        i++;
                    }
                    //DateTime fr = dt - TimeSpan.FromDays(365 * LOAD_STEP_YEARS);
                    //RawRange r1 = GetRange(fr, toDate, info);
                    return(res1);
                }

                #region отправка статистики загрузки

                string dataS, linkS;
                switch (info.MeteoSourceType)
                {
                case MeteoSourceType.Airport:
                    dataS = "cc_id={0}&cc_str={1}&stat_p=1&s_date1={2}&s_ed3={4}&s_ed4={4}&s_ed5={5}&s_date2={3}&s_ed9=0&s_ed10=-1&s_pe=1&lng_id=2&s_dtimehi=-Период---";
                    linkS = "https://rp5.ru/responses/reStatistMetar.php";
                    dataS = string.Format(dataS,
                                          info.ID,                              //cc_id
                                          info.CC_Code,                         //cc_str
                                          fromDate.Date.ToString("dd.MM.yyyy"), //from
                                          toDate.Date.ToString("dd.MM.yyyy"),   //to
                                          DateTime.Now.Month,                   //f_ed3 - только месяц
                                          DateTime.Now.Day                      //f_ed5 - только день
                                          );
                    break;

                case MeteoSourceType.Meteostation:
                    dataS = "wmo_id={0}&stat_p=1&s_date1={1}&s_ed3={3}&s_ed4={3}&s_ed5={4}&s_date2={2}&s_ed9=0&s_ed10=-1&s_pe=1&lng_id=2&s_dtimehi=-срок---";
                    linkS = "https://rp5.ru/responses/reStatistSynop.php";
                    dataS = string.Format(dataS,
                                          info.ID,                              //wmo_id
                                          fromDate.Date.ToString("dd.MM.yyyy"), //from
                                          toDate.Date.ToString("dd.MM.yyyy"),   //to
                                          DateTime.Now.Month,                   //f_ed3 - только месяц
                                          DateTime.Now.Day                      //f_ed5 - только день
                                          );
                    break;

                default: throw new Exception("Этот тип метеостанций не реализован");
                }
                string strS = this.SendStringPostRequest(linkS, dataS, referer: "https://rp5.ru/", cookies: this.CookieData, customHeaders: this.Headers);

                #endregion

                #region получение ссылки на файл
                string data, link;
                //получение ссылки на файл
                switch (info.MeteoSourceType)
                {
                case MeteoSourceType.Airport:
                    data = "metar={0}&a_date1={1}&a_date2={2}&f_ed3={3}&f_ed4={4}&f_ed5={5}&f_pe={6}&f_pe1={7}&lng_id=2";
                    link = "https://rp5.ru/responses/reFileMetar.php";
                    break;

                case MeteoSourceType.Meteostation:
                    data = "wmo_id={0}&a_date1={1}&a_date2={2}&f_ed3={3}&f_ed4={4}&f_ed5={5}&f_pe={6}&f_pe1={7}&lng_id=2";
                    link = "https://rp5.ru/responses/reFileSynop.php";
                    break;

                default: throw new Exception("Этот тип метеостанций не реализован");
                }

                data = string.Format(data,
                                     info.ID,                              //id
                                     fromDate.Date.ToString("dd.MM.yyyy"), //from
                                     toDate.Date.ToString("dd.MM.yyyy"),   //to
                                     DateTime.Now.Month,                   //f_ed3 - только месяц
                                     DateTime.Now.Month,                   //f_ed4 - только месяц
                                     DateTime.Now.Day,                     //f_ed5 - только день
                                     1,                                    //f_pe
                                     2                                     //f_pe1- кодировка (1 - ansi, 2 - utf8, 3 - Unicode)
                                     );

                string str = this.SendStringPostRequest(link, data, referer: "https://rp5.ru/", cookies: this.CookieData, customHeaders: this.Headers);


                //ОШИБКИ rp5.ru
                //запросы к reFileSynop.php
                //FS004 несуществующий wmo_id
                //FS002 ошибки в исходных данных (параметрах запроса)
                //FS000 Ошибка авторизации
                //FS001-
                //запросы к reStatistSynop.php
                //S000 Ошибка авторизации
                //FM000 Время жизни статистики истекло для этой сессии
                if (str.Contains("FS004"))
                {
                    throw new WindEnergyException("Для этого id нет архива погоды", ErrorReason.FS004);
                }
                if (str.Contains("FS002"))
                {
                    throw new WindEnergyException("Ошибка в исходных данных", ErrorReason.FS002);
                }
                if (str.Contains("FS000"))
                {
                    throw new WindEnergyException("Ошибка авторизации", ErrorReason.FS000);
                }
                if (str.Contains("FS001-"))
                {
                    throw new WindEnergyException("Неправильный метод запроса. Ожидается POST", ErrorReason.FS001);
                }
                if (str.Contains("FM000"))
                {
                    throw new WindEnergyException("Время жизни статистики истекло для этой сессии", ErrorReason.FM000);
                }
                if (str.Contains("FM004"))
                {
                    throw new WindEnergyException("Внутренняя ошибка. Архив недоступен или не существует", ErrorReason.FM004);
                }

                int start = str.IndexOf("href=") + 5;
                str = str.Substring(start);
                int    end = str.IndexOf(">");
                string lnk = str.Substring(0, end);
                lnk = lnk.Split(' ')[0] ?? "";

                bool checkLink = Uri.TryCreate(lnk, UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
                if (!checkLink)
                {
                    throw new WindEnergyException("В парсере ответа rp5 произошла ошибка. Скорее всего, парсер устарел, обратитесь к разработчику");
                }

                #endregion

                #region  загрузка файла с сервера

                string    tmp_dl_file = Vars.LocalFileSystem.GetTempFileName();
                WebClient webcl       = new WebClient();
                webcl.DownloadFile(lnk, tmp_dl_file);
                webcl.Dispose();

                //распаковка
                string tmp_unpack_file = tmp_dl_file + ".csv";
                LocalFileSystem.UnGZip(tmp_dl_file, tmp_unpack_file);

                //открытие файла
                RawRange res = LoadCSV(tmp_unpack_file, info);

                res              = new RawRange(res.OrderBy(x => x.Date).ToList());
                res.Name         = info.Name;
                res.Position     = info.Position;
                res.Meteostation = info;
                res.Height       = 10;                                                  //высота всегда 10м
                new Task(() => Vars.RP5Meteostations.TryAddMeteostation(info)).Start(); //если такой метеостанции нет в БД, то добавляем
                return(res);

                #endregion

            default: throw new Exception("Этот тип БД не реализован");
            }
        }