public const double NOMINAL_AIR_DENSITY = 1.2041; // кг/м3 /// <summary> /// расчет мощностной характеристики на основе основных параметров ВЭУ /// </summary> /// <param name="selectedEquipment"></param> /// <returns></returns> public static Dictionary <double, double> CalculatePerformanceCharacteristic(EquipmentItemInfo selectedEquipment) { if (!selectedEquipment.EnoughDataToCalculateCharacteristic) { throw new WindEnergyException("Недостаточно данных для расчета мощностной характеристики"); } LinearInterpolateMethod interpolator = new LinearInterpolateMethod(new Dictionary <double, double>() { { 0, 0 }, { selectedEquipment.MinWindSpeed, 0 }, { selectedEquipment.NomWindSpeed, selectedEquipment.Power }, { selectedEquipment.MaxWindSpeed, selectedEquipment.Power }, { selectedEquipment.MaxWindSpeed + MIN_WIND_SPEED_STEP, 0 }, { 31, 0 }, }); Dictionary <double, double> res = new Dictionary <double, double>(); for (double speed = 1; speed <= 30; speed++) { res.Add(speed, interpolator.GetValue(speed)); } return(res); }
/// <summary> /// выбор микроклиматического коэффициента рельефа по средней скорости и стратификации атмосферы /// </summary> /// <param name="speed">скорость ветра </param> /// <param name="microclimateCoefficient"></param> /// <param name="atmosphereStratification"></param> /// <returns></returns> private static double selectMicroclimateCoefficient(double speed, MicroclimateItemInfo microclimateCoefficient, AtmosphereStratification atmosphereStratification) { Diapason <double> diap; double res; if (speed <= 5) { diap = atmosphereStratification == AtmosphereStratification.Stable ? microclimateCoefficient.Stable_3_5 : microclimateCoefficient.Unstable_3_5; res = LinearInterpolateMethod.LinearInterpolation(3, 5, diap.From, diap.To, speed); } else { diap = atmosphereStratification == AtmosphereStratification.Stable ? microclimateCoefficient.Stable_6_20 : microclimateCoefficient.Unstable_6_20; res = LinearInterpolateMethod.LinearInterpolation(6, 20, diap.From, diap.To, speed); } if (res < 0) { throw new Exception("Отрицательный коэффициент после интерполяции"); } return(res); }
private void buttonSave_Click(object sender, EventArgs e) { if (Result.Count == 0) { _ = MessageBox.Show(this, "Для сохранения надо добавить хотя бы одну точку в характеристику", "Редактирование мощностной характеристики", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } Result[0] = 0; Result[maxSpeed + 1] = 0; LinearInterpolateMethod interpolator = new LinearInterpolateMethod(Result); for (int i = 1; i <= maxSpeed; i++) { Result[i] = interpolator.GetValue(i); } _ = Result.Remove(0); _ = Result.Remove(maxSpeed + 1); this.DialogResult = DialogResult.OK; Close(); }
/// <summary> /// подготовка функций для интерполирования /// </summary> private void prepareIterpolators() { if (param.Method == InterpolateMethods.NearestMeteostation && param.Coordinates.IsEmpty) { throw new Exception("Для этого метода интерполяции необходимо указать расчетную точку на карте"); } //ПОДГОТОВКА ФУНКЦИЙ Dictionary <double, double> speedFunc = new Dictionary <double, double>(), //функция скорости directsFunc = new Dictionary <double, double>(), //функция направления wetFunc = new Dictionary <double, double>(), //функция влажности tempFunc = new Dictionary <double, double>(), //функция температуры pressFunc = new Dictionary <double, double>(); //функция давления //заполнение известными значениями функции foreach (var item in Range) { double timeStamp = item.DateArgument; if (speedFunc.ContainsKey(timeStamp)) { throw new ApplicationException("В ряде наблюдений есть повторяющиеся даты. Восстановление невозможно, попробуйте проверить ряд на ошибки."); } if (!double.IsNaN(item.Speed)) { speedFunc.Add(timeStamp, item.Speed); } if (!double.IsNaN(item.Direction) && item.Direction > 0) { directsFunc.Add(timeStamp, item.Direction); } if (!double.IsNaN(item.Wetness)) { wetFunc.Add(timeStamp, item.Wetness); } if (!double.IsNaN(item.Temperature)) { tempFunc.Add(timeStamp, item.Temperature); } if (!double.IsNaN(item.Pressure)) { pressFunc.Add(timeStamp, item.Pressure); } } //ПОДГОТОВКА ИНТЕРПОЛЯТОРОВ //создание интерполяторов функций скорости, направления, температуры, влажности switch (param.Method) { case InterpolateMethods.Linear: methodSpeeds = new LinearInterpolateMethod(speedFunc); methodDirects = new LinearInterpolateMethod(directsFunc); methodTemp = new LinearInterpolateMethod(tempFunc); methodWet = new LinearInterpolateMethod(wetFunc); methodPress = new LinearInterpolateMethod(pressFunc); break; case InterpolateMethods.Stepwise: methodSpeeds = new StepwiseInterpolateMethod(speedFunc); methodDirects = new StepwiseInterpolateMethod(directsFunc); methodTemp = new StepwiseInterpolateMethod(tempFunc); methodWet = new StepwiseInterpolateMethod(wetFunc); methodPress = new StepwiseInterpolateMethod(pressFunc); break; case InterpolateMethods.NearestMeteostation: if (param.BaseRange != null) { //проверяем заданный ряд на возможность восстановления с помощью него bool f = NearestMSInterpolateMethod.CheckNormalLaw(param.BaseRange, Vars.Options.NormalLawPirsonCoefficientDiapason); if (f) { baseRange = param.BaseRange; } else { throw new WindEnergyException("Этот ряд не может быть использован так как он не подчиняется нормальному закону распределения"); } } else { //ищем подходящую МС из ближайших и получаем её ряд. Если подходит, то ошибки нет baseRange = NearestMSInterpolateMethod.TryGetBaseRange(Range, param.Coordinates, out r, null); } methodSpeeds = new NearestMSInterpolateMethod(speedFunc, baseRange, MeteorologyParameters.Speed, param.ReplaceExistMeasurements); methodDirects = new LinearInterpolateMethod(directsFunc); methodTemp = new LinearInterpolateMethod(tempFunc); methodWet = new LinearInterpolateMethod(wetFunc); methodPress = new LinearInterpolateMethod(pressFunc); break; default: throw new Exception("Этот метод не реализован"); } //новый интервал наблюдений в минутах int newInterval = (int)param.Interval; //метки времени для нового ряда newRangeX = new List <double>(); double start = speedFunc.Keys.Min(); double end = speedFunc.Keys.Max(); for (double i = start; i <= end; i += newInterval) { newRangeX.Add(i); } }
/// <summary> /// основной расчет для ВЭУ по заданному ряду /// </summary> /// <param name="range"></param> /// <param name="equipment"></param> /// <param name="h"></param> /// <param name="startHeight"></param> /// <param name="ams">выбранная АМС для пересчета на высоту или null, если не надо проводить пересчет</param> /// <param name="needRecalcWithAirDensity"></param> /// <returns></returns> public async static Task <PowerCalculatorResult> Calculate(RawRange range, EquipmentItemInfo equipment, double h, double startHeight, SuitAMSResultItem ams, bool needRecalcWithAirDensity) { //пересчитать ряд на высоту h (считаем, что ряд на высоте startHeight) //расчитать Ni для каждого наблюдения //расчитать основные показатели Э, kиум, Эуд, hиум //расчитать кривую обеспеченности //проверка, надо ли пересчитывать скорости ветра на высоту RawRange altedRange; if (ams != null) { altedRange = await RangeElevator.ProcessRange(range, new ElevatorParameters() { ToHeight = h, Coordinates = range.Position, HellmanCoefficientSource = HellmanCoefficientSource.AMSAnalog, SelectedAMS = ams, FromHeight = startHeight }); } else { altedRange = range; } //если надо, то пересчитываем мощностную характеристику с учетом плотности воздуха Dictionary <double, double> characteristic; if (needRecalcWithAirDensity) { characteristic = RecalcPerfomanceCharacteristicWithAirDensity(range.AirDensity, equipment.PerformanceCharacteristic, equipment); } else { characteristic = equipment.PerformanceCharacteristic; } //расчет мощности для каждого наблюдения и годовой выработки LinearInterpolateMethod interpolator = new LinearInterpolateMethod(characteristic); Dictionary <double, double> production = new Dictionary <double, double>(); Dictionary <DateTime, double> productionRange = new Dictionary <DateTime, double>(); Dictionary <Months, double> energyByMonth = new Dictionary <Months, double>(); double totalE = 0; for (int i = 0; i < altedRange.Count; i++) { RawItem item = altedRange[i]; double N; if (!interpolator.InBounds(item.Speed)) { N = 0; //мощность в кВт } else { N = interpolator.GetValue(item.Speed); //мощность в кВт } production.Add(item.DateArgument, N); productionRange.Add(item.Date, N); //расчет выработки if (i > 0) { double energyBit = N * (item.DateArgument - altedRange[i - 1].DateArgument) / 60; //перевод в часы (DateArgumet в минутах) totalE += energyBit; //суммарная выработка в кВт*ч //выработка по месяцам Months month = (Months)item.Date.Month; if (energyByMonth.ContainsKey(month)) { energyByMonth[month] += energyBit; } else { energyByMonth.Add(month, energyBit); } } } //поскольку ряд мб произвольной длины, то надо привести выработку к среднегодовой //коэффициент пересчета к одному году double yearKoeff = 8760 / ((altedRange.Last().Date - altedRange.First().Date).TotalHours); double E = totalE * yearKoeff; //коэфф использования установленной мощности double kium = E / (equipment.Power * 8760); //выработка уже приведена к году, используем как есть //удельная выработка double Edensity = E / (Math.PI * Math.Pow(equipment.Diameter, 2) / 4); // Эгод/Fом //число часов использования установленной мощности double hium = E / equipment.Power; //выработка уже приведена к году, используем как есть PowerCalculatorResult result = new PowerCalculatorResult() { YearEnergy = E, TotalEnergy = totalE, EnergyByMonth = energyByMonth, EDensity = Edensity, Kium = kium, Hium = hium, SupportingPower = calculateSupportingPower(production), Production = productionRange, Equipment = equipment, TowerHeight = h, Range = range }; return(result); }