public static void WriteDay() // Записывает данные текущего дня (мощности каждого энергоблока, их состояние и потребление топлива) в файл out.csv { string print = Convert.ToString(PTU1.nowPower) + ";" + Convert.ToString(PTU2.nowPower) + ";" + Convert.ToString(PGU1.nowPower) + ";" + Convert.ToString(PGU2.nowPower) + ";" + Convert.ToString(GTU1.nowPower) + ";" + Convert.ToString(GTU2.nowPower) + ";" + "Р" + ";"; if (PTU2.on) { print += "Р;Р;"; } else if (PTU2.start) { print += "П;Р;"; } else { print += "О;Р;"; } if (PGU2.on) { print += "Р;Р;"; } else if (PGU2.start) { print += "П;Р;"; } else { print += "О;Р;"; } if (GTU2.on) { print += "Р;"; } else if (GTU2.start) { print += "П;"; } else { print += "О;"; } print += Convert.ToString(PTU1.nowPower / PTU1.EfficiencySolo(PTU1.nowPower) * gas) + ";" + Convert.ToString(PTU2.start ? (0.3 * PTU2.nominalPower / PTU1.EfficiencySolo(0.3 * PTU2.nominalPower) * gas) : (PTU2.on ? (PTU2.nowPower / PTU1.EfficiencySolo(PTU2.nowPower) * gas) : 0)) + ";" + Convert.ToString(PGU1.nowPower / PGU1.EfficiencySolo(PGU1.nowPower) * gas) + ";" + Convert.ToString(PGU2.start ? (0.3 * PGU2.nominalPower / PGU1.EfficiencySolo(0.3 * PGU2.nominalPower) * gas) : (PGU2.on ? (PGU2.nowPower / PGU1.EfficiencySolo(PGU2.nowPower) * gas) : 0)) + ";" + Convert.ToString(GTU1.nowPower / GTU1.EfficiencySolo(GTU1.nowPower) * gas) + ";" + Convert.ToString(GTU2.start ? (0.3 * GTU2.nominalPower / GTU1.EfficiencySolo(0.3 * GTU1.nominalPower) * gas) : (GTU2.on ? (GTU2.nowPower / PTU1.EfficiencySolo(GTU2.nowPower) * gas) : 0)) + ";"; string path = @"..\..\..\Data\out.csv"; string lastData; using (StreamReader sr = new StreamReader(path, System.Text.Encoding.UTF8)) //Считываем данные о загрузки из файла. { lastData = sr.ReadToEnd(); } using (StreamWriter sw = new StreamWriter(path, false, System.Text.Encoding.UTF8)) //Считываем данные о загрузки из файла. { sw.Write(lastData); sw.WriteLine(print); } }
public static void NewHour(int mode, int hourNum) // Основной метод, в котором рассматриваются данные о новом часе и при необходимости запускается переход на новую фазу { PTU2.hours = (PTU2.hours != 0) ? (PTU2.hours + 1) : 0; // Если вторая установка не включена, то увеличить время с последнего запуска на час PGU2.hours = (PGU2.hours != 0) ? (PGU2.hours + 1) : 0; // Если вторая установка не включена, то увеличить время с последнего запуска на час PTU2.on = (PTU2.hours == 0); PTU2.start = (PTU2.hours < 0); PGU2.on = (PGU2.hours == 0); PGU2.start = (PGU2.hours < 0); // Если время равно 0, то переводим установки в включенное состояние из сотояния пуска if (GTU2.start) { GTU2.start = false; GTU2.on = true; } mode = 4 * (PTU2.on ? 1 : 0) + 2 * (PGU2.on ? 1 : 0) + (GTU2.on ? 1 : 0); double[] powers = getData(hourNum); if (hourNum == 671) { PowerDistr.Distrib(powers[0]); return; } double max = powers[0], min = powers[0]; // Переменные, находящие максимальную и минимальную потребляемую мощности int k = Math.Min(24, 672 - hourNum); for (int i = 1; i < k; i++) { max = Math.Max(max, powers[i]); min = Math.Min(min, powers[i]); } if (max <= FindComb.maxPower[mode + ((mode + 1) % 2)]) { if (min >= FindComb.minPower[mode]) // Система может работать ближайшие сутки без изменения режима ПТУ2/ПГУ2 { } else { if (PTU2.on) { if (powers[0] <= FindComb.maxPower[mode - 4]) // Если можем отключить энергоблок в данный час { int countof = 0; // Счетчик числа часов, в течение которых может быть отключен энергоблок for (int i = 1; i < k; i++) { if (powers[i] <= FindComb.maxPower[mode - 4] && i == countof + 1) { countof++; } } if (countof >= 4) { PTU2.on = false; // Отключаем энергоблок, т.к. он имеет наименьший КПД PTU2.hours = 1; mode -= 4; } } } if (PGU2.on) { if (powers[0] < FindComb.minPower[mode]) // Если в системе все еще остается переизбыток энергии { PGU2.on = false; // Отключаем энергоблок PGU2.hours = 1; mode -= 2; } } } } else { if (!PGU2.on && !PGU2.start) { int time = -1; for (int i = 0; i < k; i++) { if (powers[i] > FindComb.maxPower[mode + ((mode + 1) % 2)] && time == -1) { time = i; // Находим время, когда возникнет нехватка } } if (!(((PGU2.hours <= 8) ? 4 : ((PGU2.hours + 1 <= 72) ? 5 : 7)) <= time)) // Если в следующем часу будет поздно запускать энергоблок { PGU2.start = true; PGU2.hours = -((PGU2.hours <= 8) ? 4 : ((PGU2.hours + 1 <= 72) ? 5 : 7)); // Запускаем энергоблок } } if (!PTU2.on && !PTU2.start) { if (max > FindComb.maxPower[mode + ((mode + 1) % 2)]) // Если после запуска энергоблока ПГУ все равно есть нехватка мощности { int time = -1; for (int i = 0; i < k; i++) { if (powers[i] > FindComb.maxPower[mode + ((mode + 1) % 2)] && time == -1) { time = i; // Находим время, когда возникнет нехватка } } if (!(((PTU2.hours <= 8) ? 4 : ((PTU2.hours + 1 <= 72) ? 8 : 11)) <= time)) // Если в следующем часу будет поздно запускать энергоблок { PTU2.start = true; PTU2.hours = -((PTU2.hours <= 8) ? 4 : ((PTU2.hours + 1 <= 72) ? 8 : 11)); // Запускаем энергоблок } } } } if (GTU2.on) { double freePower = powers[0] - PGU1.nominalPower * (PGU2.on ? 2 : 1) - 0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) - 0.1 * GTU1.nominalPower; // Находим избыток энергии, после базового распределения (ПГУ - 100%, остальные - минимальная загрузка) if (freePower > 0) { if (freePower < 1.5 * GTU1.nominalPower) { if (GTU1.EfficiencySolo(0.1 * GTU1.nominalPower + freePower - 80) < PTU1.Efficiency(0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) + freePower)) { mode--; GTU2.on = false; } } } }// Включение/выключение ГТУ2 else { if (powers[1] > FindComb.minPower[mode + 1]) // Рассматриваем следующий час, чтобы понять необходимость включать второй энергоблок ГТУ { double freePower = powers[1] - PGU1.nominalPower * (PGU2.on ? 2 : 1) - 0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) - 0.1 * GTU1.nominalPower; // Находим избыток энергии, после базового распределения (ПГУ - 100%, остальные - минимальная загрузка) if (freePower > 0) { if (freePower > 1.5 * GTU1.nominalPower) { mode++; GTU2.start = true; } else if (GTU1.EfficiencySolo(0.1 * GTU1.nominalPower + freePower - 80) > PTU1.Efficiency(0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) + freePower)) { mode++; GTU2.start = true; } } } } PowerDistr.Distrib(powers[0]); if (PGU2.hours == -1) { mode += 2; } if (PTU2.hours == -1) { mode += 4; } if (hourNum != 671) { NewHour(mode, hourNum + 1); } }
public static void Distrib(double power) // Распределение энергии на основе текущей комбинации энергоблоков { double freePower = power - 0.3 * PTU1.nominalPower - 0.3 * PGU1.nominalPower - 0.05 * GTU1.nominalPower; if (PTU2.on) { PTU2.nowPower = 0.3 * PTU2.nominalPower; freePower -= 0.3 * PTU2.nominalPower; } else { PTU2.nowPower = 0; } if (PGU2.on) { PGU2.nowPower = 0.3 * PGU2.nominalPower; freePower -= 0.3 * PGU2.nominalPower; } else { PGU2.nowPower = 0; } if (GTU2.on) { GTU2.nowPower = 0.05 * GTU2.nominalPower; freePower -= 0.05 * GTU2.nominalPower; } // Определение нераспределенной мощности else { GTU2.nowPower = 0; } PTU1.nowPower = PTU1.nominalPower * 0.3; PGU1.nowPower = PGU1.nominalPower * 0.3; GTU1.nowPower = GTU1.nominalPower * 0.05; if (freePower > 0.7 * PGU1.nominalPower) { freePower -= 0.7 * PGU1.nominalPower; PGU1.nowPower = PGU1.nominalPower; if (PGU2.on) { if (freePower > 0.7 * PGU2.nominalPower) { freePower -= 0.7 * PGU2.nominalPower; PGU2.nowPower = PGU2.nominalPower; } else { PGU2.nowPower += freePower; freePower = 0; } } if (GTU2.on) { if (freePower > 1.9 * GTU1.nominalPower) { freePower -= 2 * 0.95 * GTU1.nominalPower; GTU1.nowPower = GTU1.nominalPower; GTU2.nowPower = GTU2.nominalPower; if (freePower > 0.7 * PTU1.nominalPower) { PTU1.nowPower = PTU1.nominalPower; freePower -= 0.7 * PTU1.nominalPower; PTU2.nowPower += freePower; freePower = 0; } else { PTU1.nowPower += freePower; freePower = 0; } } else if (freePower > 1.5 * GTU1.nominalPower) // При загрузке в 80% КПД энергоблоков выше, чем максимальный КПД энергоблоков ПТУ { GTU1.nowPower = GTU1.nominalPower; freePower -= 0.95 * GTU1.nominalPower; GTU2.nowPower += freePower; freePower = 0; } else if (GTU1.Efficiency(0.1 * GTU1.nominalPower + freePower) > PTU1.Efficiency((0.3 + 0.3 * Convert.ToDouble(PTU2.on)) * PTU1.nominalPower + freePower)) { if (freePower > 0.95 * GTU1.nominalPower) { GTU1.nowPower = GTU1.nominalPower; freePower -= 0.95 * GTU1.nominalPower; GTU2.nowPower += freePower; freePower = 0; } else { GTU1.nowPower += freePower; freePower = 0; } } else { PTU1.nowPower += freePower; freePower = 0; } } else { if (freePower > 0.95 * GTU1.nominalPower) { GTU1.nowPower = GTU1.nominalPower; freePower -= 0.95 * GTU1.nominalPower; if (freePower > 0.7 * PTU1.nominalPower) { PTU1.nowPower = PTU1.nominalPower; freePower -= 0.7 * PTU1.nominalPower; PTU2.nowPower += freePower; freePower = 0; } else { PTU1.nowPower += freePower; freePower = 0; } } else if (GTU1.Efficiency(0.05 * GTU1.nominalPower + freePower) > PTU1.Efficiency((0.3 + 0.3 * Convert.ToDouble(PTU2.on)) * PTU1.nominalPower + freePower)) { GTU1.nowPower += freePower; freePower = 0; } else { PTU1.nowPower += freePower; freePower = 0; } } } else { PGU1.nowPower += freePower; freePower = 0; } WriteDay(); }
public static double[] minPower = { 103, 107, 139, 143, 166, 170, 202, 206 }; // Массивы, содержащие максимальные и минимальные границы для каждой комбинации энергоблоков public static void System(double[] powers) //Метод, реализующий выбор комбинации на момент старта. Получает на вход 24 значения мощностей, потребляемых в системой в каждый часиз прогноза { double max = powers[0], min = powers[0]; // Переменные, находящие максимальную и минимальную потребляемую мощности for (int i = 0; i < 24; i++) { max = Math.Max(max, powers[i]); min = Math.Max(min, powers[i]); } int mode = 0; if (max <= FindComb.maxPower[mode + ((mode + 1) % 2)]) { if (min >= FindComb.minPower[mode]) // Система может работать ближайшие сутки без изменения режима ПТУ2/ПГУ2 { } else { if (PTU2.on) { if (powers[0] <= FindComb.maxPower[mode - 4]) // Если можем отключить энергоблок в данный час { int countof = 0; // Счетчик числа часов, в течение которых может быть отключен энергоблок for (int i = 1; i < 24; i++) { if (powers[i] <= FindComb.maxPower[mode - 4] && i == countof + 1) { countof++; } } if (countof >= 4) { PTU2.on = false; // Отключаем энергоблок, т.к. он имеет наименьший КПД PTU2.hours = 1; mode -= 4; } } } if (PGU2.on) { if (powers[0] < FindComb.minPower[mode]) // Если в системе все еще остается переизбыток энергии { PGU2.on = false; // Отключаем энергоблок PGU2.hours = 1; mode -= 2; } } } } else { if (!PGU2.on && !PGU2.start) { PGU2.on = true; // Если в течение первых суток не хватает мощности, то включаем второй ПГУ PGU2.hours = 0; } if (!PTU2.on && !PTU2.start) { if (max > FindComb.maxPower[mode + ((mode + 1) % 2)]) // Если после запуска энергоблока ПГУ все равно есть нехватка мощности { PTU2.on = true; PTU2.hours = 0; // Если мощности все еще не хватает, то включаем второй ПТУ } } } if (GTU2.on) { double freePower = powers[0] - PGU1.nominalPower * (PGU2.on ? 2 : 1) - 0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) - 0.1 * GTU1.nominalPower; // Находим избыток энергии, после базового распределения (ПГУ - 100%, остальные - минимальная загрузка) if (freePower > 0) { if (freePower < 1.5 * GTU1.nominalPower) { if (GTU1.EfficiencySolo(0.1 * GTU1.nominalPower + freePower - 80) < PTU1.Efficiency(0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) + freePower)) { mode--; GTU2.on = false; } } } }// Включение/выключение ГТУ2 else { if (powers[1] > FindComb.minPower[mode + 1]) // Рассматриваем следующий час, чтобы понять необходимость включать второй энергоблок ГТУ { double freePower = powers[1] - PGU1.nominalPower * (PGU2.on ? 2 : 1) - 0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) - 0.1 * GTU1.nominalPower; // Находим избыток энергии, после базового распределения (ПГУ - 100%, остальные - минимальная загрузка) if (freePower > 0) { if (freePower > 1.5 * GTU1.nominalPower) { mode++; GTU2.start = true; } else if (GTU1.EfficiencySolo(0.1 * GTU1.nominalPower + freePower - 80) > PTU1.Efficiency(0.3 * PTU1.nominalPower * (PTU2.on ? 2 : 1) + freePower)) { mode++; GTU2.start = true; } } } } ModeStartSetup(mode); //Устанавливаем системе выбранные параметры PowerDistr.Distrib(powers[0]); DayGo.NewHour(mode, 1); }