Skip to content

EntitiesBlocks Energetický model malého hotelu

fyziktom edited this page Feb 25, 2023 · 2 revisions

Jak již bylo zmíněno v předešlých článcích, knihovna EntitiesBlocks může být použitá pro výpočet výroby a spotřeby energií. Jako příklad bude v tomto článku uvedený model malého hotelu. Jedná se o zjednodušený model, který však může poskytnout základní pohled na jednotlivé spotřeby. Díky tomu je možné se efektivně zaměřit na optimalizaci spotřeby, která hraje v rámci celku největší roli. Případně si podle spotřeby naplánovat i alternativní zdroj energie, jak bude ukázáno v rámci příkladu, kde je i zahrnuta fotovoltaická elektrárna, která pokrývá část spotřeby hotelu.

Celý příklad je umístěný v rámci projektu TestVEDrivetsLite.

Po spuštění aplikace lze najít test v seznamu funkcí. Test má název "EB_SmallHotelDemo" a nevyžaduje nyní žádné zadání parametrů. Ty jsou na začátku funkce nyní natvrdo zapsané. Spuštění testu vypadá následovně:

Spuštěný test EB_SmallHotelDemo

Nyní k postupu jak takový skript vytvořit. Prvně je potřeba nadefinovat potřebné konstanty. Mezi ně patří například lokace hotelu (to je potřeba kvůli výpočtu simulátoru fotovoltaické elektrárny). Dále začátek simulace (zde zvolen 3 leden 2022 protože je to pondělí). Dále počet dní, které chceme simulovat a také Timeframe do kterého budou rozpadnuté bloky ve výsledku. Tedy pokud zvolím 1 den simulace a Timeframe Hour, tak na konci obdržím 24 bloků (pro každou hodinu dne jeden blok).

// SET Coordinates of PVE
Coordinates coord = new Coordinates(12.097178, -68.914773);
// SET Start of the simulation
var start = new DateTime(2022, 1, 3); // 3rd of January 2022 is Monday
// SET Number of days which you want to simulate
var daysOfSimulation = 1;
// SET output timeframe which will be calculated as step
var outputTimeframe = BlockTimeframe.Hour;

Další konstanty se týkají především jednotlivých zařízení, které budeme později přidávat:

var owner = "hotel";
var powerOfAC = 1.5;
var powerOfFridge = 0.12;
var numberOfRooms = 30;
var averageOccupancy = 0.6;
var numberOfOffices = 2;

Názvy jsou dost vypovádající. Nicméně za zmínku zde stojí alespoň proměnná averageOccupancy, která reprezentuje průměrnou procentuální obsazenost pokojů (zde 60%).

Pro vytvoření simulace je potřeba inicializovat základní BaseEntitiesHandler (vychází z CommonEntitiesHandleru) objekt:

var eGrid = new BaseEntitiesHandler();         

Do tohoto objektu budeme postupně přidávat entity. Prvně doporučuji vytvořit jednu hlavní entitu reprezentující celou síť:

var name = "network";
var networkId = string.Empty;
var network = new GroupNetwork() { Type = EntityType.Consumer, Name = name, ParentId = owner };
var res = eGrid.AddEntity(network, name, owner);
if (res.Item1)
   networkId = res.Item2.Item2;

Následně lze vytvořit entity reprezentující pokoje a přidat je do základní sítě. Zde jsou vytvořeny dvě entity: jedna slouží jako obecná skupina pro pokoje a druhá (dceřiná) reprezentuje 30 pokojů (lze je zadat i samostatně, ale nebylo pro tento příklad potřeba).

name = "rooms";
var roomsGroupId = string.Empty;
var roomsGroup = new GroupNetwork() { Type = EntityType.Consumer, Name = name, ParentId = networkId };
res = eGrid.AddEntity(roomsGroup, name, owner);
if (res.Item1)
   roomsGroupId = res.Item2.Item2;

name = "allrooms";
var allroomsId = string.Empty;
var allRoomsEnt = new Device() { Type = EntityType.Consumer, Name = name, ParentId = roomsGroupId };
res = eGrid.AddEntity(allRoomsEnt, name, owner);
if (res.Item1)
   allroomsId = res.Item2.Item2;

eGrid.AddSubEntityToEntity(networkId, roomsGroupId);
eGrid.AddSubEntityToEntity(roomsGroupId, allroomsId);

Pro získání dat o spotřebě pokojů jsou ještě přidány simulátory (klimatizace a lednička) do entity allRoomsEnt:

double[] acRun = new double[24]
{
	0.2, 0.2, 0.2, 0.2, 0.2, 0.3, 0.3, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.4, 0.6, 0.6, 0.4, 0.4, 0.4, 0.3
 //  00,  01,  02,  03,  04,  05, 06,  07,  08,  09,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23 
};

double[] fridgeRun = new double[24]
{
	0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2
 //  00,  01,  02,  03,  04,  05, 06,  07,  08,  09,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23 
};

var acSim = new DeviceSimulator(acRun, powerOfAC * numberOfRooms * averageOccupancy);
_ = allRoomsEnt.AddSimulator(acSim);
var fridgeSim = new DeviceSimulator(fridgeRun, powerOfFridge * numberOfRooms * averageOccupancy);
_ = allRoomsEnt.AddSimulator(fridgeSim);

Podobně jsou přidány i další oblasti spotřeby jako jsou společné prostory (kuchyň, prádelna, elektrické klece na komáry), nebo kanceláře (ty jsou důležité, protože mají hlavní spotřebu ve dne, což je opačně než pokoje), apod.

Po přidání všech entit je potřeba přidat ještě simulátor solární elektrárny. V prnvím kroku se vytvoří objekt pro simulátor a také entita pro simulátor. Pozor tato entita je typu Source a předešlé jsou Consumer!!!

var PVESim = new PVPanelsGroupsHandler();

name = "pvesource";
var pvesourceId = string.Empty;
var pvesource = new PVESource() { Type = EntityType.Source, Name = name, ParentId = networkId };
res = eGrid.AddEntity(pvesource, name, owner);
if (res.Item1)
    pvesourceId = res.Item2.Item2;

eGrid.AddSubEntityToEntity(networkId, pvesourceId);

Po vytvoření objektů je možné přidat fotovoltaické panely od simulátoru elektrárny:

var panelAzimuthE = MathHelpers.DegreeToRadians(-20);
var panelAzimuthS = MathHelpers.DegreeToRadians(0);
var panelAzimuthW = MathHelpers.DegreeToRadians(20);

var eastPanelsId = PVESim.AddGroup("East");
var southPanelsId = PVESim.AddGroup("South");
var westPanelsId = PVESim.AddGroup("West");

// setup common panel parameters
if (PVESim != null)
{
	var panel = new PVPanel()
	{
		Name = "test",
		Azimuth = 0,
		BaseAngle = MathHelpers.DegreeToRadians(15),
		DirtRatio = 0.05 / 365,
		Efficiency = 1,
		Height = 2000,
		Width = 1000,
		Latitude = coord.Latitude,
		Longitude = coord.Longitude,
		PeakPower = 0.3,
		PanelPeakAngle = MathHelpers.DegreeToRadians(90)
	};
	PVESim.SetCommonPanel(panel);
}

var numOfPanelsInString = 20;

// add panels in this PVE Simulator
PVESim.CommonPanel.Azimuth = panelAzimuthE;
_ = PVESim.AddPanelToGroup(eastPanelsId, PVESim.CommonPanel, numOfPanelsInString).ToList();
PVESim.CommonPanel.Azimuth = panelAzimuthS;
_ = PVESim.AddPanelToGroup(southPanelsId, PVESim.CommonPanel, numOfPanelsInString).ToList();
PVESim.CommonPanel.Azimuth = panelAzimuthW;
_ = PVESim.AddPanelToGroup(westPanelsId, PVESim.CommonPanel, numOfPanelsInString).ToList();

A nakonec se přidá simulátor do entity:

// add PVE simulator to entity
eGrid.AddSimulatorToEntity(pvesourceId, PVESim);

Pro přehled je možné si vypsat do konzole strukturu stromu entit:

await Console.Out.WriteLineAsync("-------------------Entities Tree------------------------");
var tree = eGrid.GetTree(networkId);
TreeViewHelpers.PrintTree(tree, "\n", false);

Entity Tree

V tuto chvíli je již možné si získat bilanci sítě pro specifikovaný časový rozsah a timeframe (viz konstanty na začátku programu):

// calculate bilance in specific range
var bilance = eGrid.GetConsumptionOfEntity(networkId,
                                           outputTimeframe,
                                           start,
                                           start.AddDays(daysOfSimulation),
                                           true,
                                           true,
                                           new List<BlockDirection>() { BlockDirection.Created, BlockDirection.Consumed },
                                           new List<BlockType>() { BlockType.Simulated });

V tomto kroku je získána celá bilance, tedy vytvořené i spotřebované bloky. Díky tomu, že je parametr funkce takeConsumptionAsInvert nastaven na true, je funkci řečeno, že spotřebu má vynásobit "-1", aby se automaticky odečetla od spotřeby. V případě nadprodukce energie tedy dostanu v bloku kladné číslo a vpřípadě nadspotřeby dostanu záporné číslo. Příklad je následující výpis simulace jednoho dne:

Výpis jednoho dne energo bilance hotelu.

V případě zájmu o samostatné složky lze zadat specifické BlockDirection:

// calculate consumption in specific range
var consumption = eGrid.GetConsumptionOfEntity(networkId,
					       outputTimeframe,
					       start,
					       start.AddDays(daysOfSimulation),
					       true,
					       true,
					       new List<BlockDirection>() { BlockDirection.Consumed },
					       new List<BlockType>() { BlockType.Simulated });

await DrawBlocks("Consumption", consumption, start, start.AddDays(daysOfSimulation));

// calculate production in specific range
var production = eGrid.GetConsumptionOfEntity(networkId,
					      outputTimeframe,
					      start,
					      start.AddDays(daysOfSimulation),
					      true,
					      false,
					      new List<BlockDirection>() { BlockDirection.Created },
					      new List<BlockType>() { BlockType.Simulated });

await DrawBlocks("Production", production, start, start.AddDays(daysOfSimulation));

Jak je v kódu vidět, tak v jednom případě se poptávají jen bloky s BlockDirection.Consumed a v druhém BlockDirection.Created.

Takto jsou postupně získány i další spořeby i pro specifické entity (nikoliv pro celou sít jak v předešlém případě). Díky tomu je možné lépe prozkoumat jednotlivé sekce spotřeby. Příkladem může být třeba prádelna. Hned první parametr funkce určuje jaká entita má být analyzována:

// calculate consumption of laundry in specific range
var consumptionOfLaundry = eGrid.GetConsumptionOfEntity(laundryId,
                                                       outputTimeframe,
                                                       start,
                                                       start.AddDays(daysOfSimulation),
                                                       true,
                                                       true,
                                                       new List<BlockDirection>() { BlockDirection.Consumed },
                                                       new List<BlockType>() { BlockType.Simulated });

await DrawBlocks("Consumption Of Laundry", consumptionOfLaundry, start, start.AddDays(daysOfSimulation));

Výpis výpočtu denní spotřeby z této entity vypadá následovně:

Denní spotřeba prádelny

Jak je vidět na hodnotách, tak prádelna funguje jen v pracovní dobu a to ještě až poté co hosté opustí pokoje. Základní profil prádelny byl definován spolu s jejím simulátorem. Celkem se skládá ze dvou profilů:

double[] washingMachine = new double[24]
            {
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
             //  00,  01,  02,  03,  04,  05, 06,  07,  08,  09,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23 
            };

double[] dryer = new double[24]
{
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
    //  00,  01,  02,  03,  04,  05, 06,  07,  08,  09,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23 
};

var washingMachineSimulator = new DeviceSimulator(washingMachine, 1 * averageOccupancy, Week.WorkDays);
_ = laundryEnt.AddSimulator(washingMachineSimulator);
var dryerSimulator = new DeviceSimulator(dryer, 1 * averageOccupancy, Week.WorkDays);
_ = laundryEnt.AddSimulator(dryerSimulator);

Tímto způsobem si lze definovat i simulátory pro osvětlení, podobně je v demu přidaná pumpa pro bazén, apod.

Po získání všech potřebných dat lze sestavit dokument s výstupem dat pro dodatečnou analýzu:

var header = "Date\t" +
             "Start\t" +
             "End\t" +
             "Bilance\t" +
             "Consumption\t" +
             "Production\t" +
             "Rooms\t" +
             "Offices\t" +
             "Shared Spaces\t" +
             "Laundry\t" +
             "Mosquito Traps";

FileHelpers.AppendLineToTextFile(header, filename);
for (var i = 0; i < bilance.Count; i++)
{
    var line = $"{bilance[i].StartTime.ToString("yyyy:MM:dd")}\t" +
               $"{bilance[i].StartTime.ToString("hh:mm:ss")}\t" +
               $"{bilance[i].EndTime.ToString("hh:mm:ss")}\t" +
               $"{Math.Round(bilance[i].Amount, 2)}\t" +
               $"{Math.Round(consumption[i].Amount, 2)}\t" +
               $"{Math.Round(production[i].Amount, 2)}\t" +
               $"{Math.Round(consumptionOfRooms[i].Amount, 2)}\t" +
               $"{Math.Round(consumptionOfOffices[i].Amount, 2)}\t" +
               $"{Math.Round(consumptionOfShared[i].Amount, 2)}\t" +
               $"{Math.Round(consumptionOfLaundry[i].Amount, 2)}\t" +
               $"{Math.Round(consumptionOfMosquitoTraps[i].Amount, 2)}";

    FileHelpers.AppendLineToTextFile(line, filename);
}

Ten lze načíst například do Excelu, kde je možné si udělat další fázi analýzy:

Excel analýza dat denní graf

Excel analýza dat rozložení spotřeby

Clone this wiki locally