.. _solari_implementacija: Пример прорачуна РїСЂРѕРёР·РІРѕРґСљРµ ============================== Аналитички модел ------------------- РЈ РѕРІРѕРј одељку ћемо употребити методологиССѓ приказану Сѓ :ref:`solari_uvod` Рё Седноставни модел *PVWatts* РѕР±Сашњен Сѓ :ref:`pvwatts` употребити РЅР° Седном реалном примеру. РЈ питању СРµ соларна електрана Сѓ Р¦РµРЅС‚СЂР°Р»РЅРѕС РЎСЂР±РёСРё СЃР° 146 инсталисаних панела РЅР° РєСЂРѕРІСѓ Седне зграде. РЎРІРµ карактеристике инсталациСРµ СЃСѓ нам познате (угао нагиба, азимут, врста панела, карактеристике инвертора Рё слично). РћРґ података имамо Рё сериСРµ температуре ваздуха Рё компоненти осунчаности, тако РґР° лако можемо аналитички, РїРѕ Седначинама :math:numref:`eq:sapm-temp`, :math:numref:`eq:pvwatts` Рё :math:numref:`eq:pvwatts-inverter` РґР° израчунамо РїСЂРѕРёР·РІРѕРґСљСѓ. РЈ случаССѓ РґР° поседуСемо временску РїСЂРѕРіРЅРѕР·Сѓ, можемо приближно Рё РґР° предвидимо будућу РїСЂРѕРёР·РІРѕРґСљСѓ користећи стандардни *PVWatts* модел. Рако математика РЅРёСРµ компликована, Р·Р° програмску имплементациССѓ РѕРІРѕРі аналитичког модела користићемо РїРѕРјРѕС› библиотеке PVLIB :cite:t:`holmgren2018pvlib`. РќР° наредном листингу приказан СРµ део РєРѕРґР° РєРѕСРё СЃРµ тиче учитавања, припреме података Рё извођења *PVWatts* модела. .. _lst_pvwatts_orig: .. code-block:: python :caption: РмплементациСР° *PVWatts* (аналитичког) модела РїСЂРѕРёР·РІРѕРґСљРµ :linenos: import numpy as np import pandas as pd import pvlib from pvlib.location import Location # Ucitaj podatke o vremenu i proizvodnji solcast_data = pd.read_csv("data_21.08.16_22.10.14.csv", index_col="Time") solcast_data.index = pd.to_datetime(solcast_data.index, dayfirst=True) # Nagib, azimut i lokacija panela surface_tilt = 7 surface_azimuth = 290 location = Location(latitude=43.905410, longitude=20.341986, altitude=243, tz="Europe/Belgrade", name="Pons Cacak") # Pomeri vreme za pola sata, izracunaj poziciju sunca u svakom trenutku times = solcast_data.index - pd.Timedelta('30min') solar_position = location.get_solarposition(times) solar_position.index += pd.Timedelta('30min') # Novi dataframe sa vrednostima za vrednosti osuncanosti DNI, GHI, DHI df_poa = pvlib.irradiance.get_total_irradiance( surface_tilt=surface_tilt, surface_azimuth=surface_azimuth, dni=solcast_data['DNI'], ghi=solcast_data['GHI'], dhi=solcast_data['DHI'], solar_zenith=solar_position['apparent_zenith'], solar_azimuth=solar_position['azimuth'], model='isotropic') # Izvuci ukupnu POA vrednost iz df_poa E_data = df_poa["poa_global"] # Izvuci temperaturu vazduha T_data = solcast_data["Tamb"] # Izvuci proizvodnju P P_data = solcast_data["P"] # Nedelju dana za treniranje E_data_train = E_data.loc["2021-10-31":"2021-11-06"] T_data_train = T_data.loc["2021-10-31":"2021-11-06"] P_data_train = P_data.loc["2021-10-31":"2021-11-06"] # Sledecih nedelju dana za testiranje E_data_test = E_data.loc["2021-11-07":"2021-11-13"] T_data_test = T_data.loc["2021-11-07":"2021-11-13"] P_data_test = P_data.loc["2021-11-07":"2021-11-13"] # # Parametri modela # pdc0 = 0.375 # nominal power [kWh] Tref = 25.0 # cell reference temperature gamma_pdc = -0.005 # influence of the cell temperature on PV system pdc0_inv = 50 eta_inv_nom = 0.96 eta_inv_ref = 0.9637 pac0_inv = eta_inv_nom * pdc0_inv # maximum inverter capacity a = -2.98 # cell temperature parameter b = -0.0471 # Wind coefficient E0 = 1000 # reference irradiance deltaT = 1 # cell temperature parameter num_of_panels = 146 # Broj panela u instalaciji # # Originalni PVWAtts model # def orig_pvwatts_model(x): Ta = x[:,0:1] # Temperatura vazduha E = x[:,1:2] # Ukupna POA osuncanost Tm = E * np.exp(a+b*2) + Ta # Brzina vetra uzeta kao prosecna od 2 m/s Tc = Tm + E/E0*deltaT P_dc_temp = ((Tc-Tref) * gamma_pdc + 1.) P_dc = (E * 1.e-03 * pdc0 * P_dc_temp) * num_of_panels zeta = (P_dc+1.e-2)/pdc0_inv eta = eta_inv_nom/eta_inv_ref * (-0.0162*zeta - 0.0059/zeta + 0.9858) eta[eta<0] = 0. ac = np.minimum(eta*P_dc, pac0_inv) return ac Након стандардних импорта библиотека, учитавамо сатне сериСРµ података Рѕ времену: - ``Ta`` - температура ваздуха, - ``DNI``, ``GHI``, ``DHI`` - компоненте осунчаности Рё податке Рѕ РїСЂРѕРёР·РІРѕРґСљРё ``P`` Сѓ *Pandas* РѕРєРІРёСЂ. РќР° жалост, немамо доступне податке Рѕ Р±СЂР·РёРЅРё ветра РЅР° локациСРё, РїР° ћемо ту компоненту узети као просечну РЅР° том поднебљу, С‚С. вредност РѕРґ :math:`2\,m/s`. ФункциСР° ``pvlib.irradiance.get_total_irradiance()`` библиотеке *PVLIB* нам израчунава РїРѕР»РѕР¶Р°С СЃСѓРЅС†Р° Р·Р° било РєРѕСРё временски тренутак Рё било РєРѕССѓ локациССѓ РЅР° Земљи, Р° РЅР° РѕСЃРЅРѕРІСѓ њега Рё СѓРєСѓРїРЅСѓ осунчаност панела чиСРё СРµ РїРѕР»РѕР¶Р°С РґР°С‚ угловима ``surface_tilt`` Рё ``surface_azimuth``. Као улаз, РѕРІР° метода СѓР·РёРјР° компоненте ``DNI``, ``GHI`` Рё ``DHI`` дефинисане Сѓ одељку :ref:`solari_komponente`. Након екстракциСРµ периода РѕРґ недељу дана РѕРґ 31. октобра РґРѕ 6. новембра Рё РґСЂСѓРіРѕРі периода РѕРґ 7. РґРѕ 13. новембра, постављамо СЃРІРµ параметре РєРѕСРё СЃРµ користе Сѓ Седначинама :math:numref:`eq:sapm-temp`, :math:numref:`eq:pvwatts` Рё :math:numref:`eq:pvwatts-inverter`, онако како РЅР°Сбоље одговара СЃР°РјРѕС РёРЅСЃС‚Р°Р»Р°С†РёСРё. РЎРІРё параметри РѕСЃРёРј три СЃСѓ константе прихваћене Сѓ литератури. РўР° три параметра чиСР° вредност РјРѕР¶Рµ РґР° СЃРµ подешава СЃСѓ ``a`` Рё ``b`` РёР· израза :math:numref:`eq:sapm-temp` Рё ``gamma_pdc`` РёР· израза :math:numref:`eq:pvwatts`. РЉРёС…РѕРІРµ вредности (-2,98, -0.0471 Рё -0,005 респективно) задаСемо према врсти панела Рё начину постављања инсталациСРµ. Поређење резултата РґРѕР±РёСених чистим моделом Рё мерених вредности РјРѕР¶Рµ СЃРµ видети РЅР° :numref:`pvwatts-pons`. Очигледно СРµ РґР° постоСРё значаСРЅРѕ одступање, С‚С. модел РґР°СРµ више вредности РѕРґ мерења. Корен средње квадратне грешке (*RMSE*) РёР·РЅРѕСЃРё чак 2,46 kW. Одређени РґРѕРїСЂРёРЅРѕСЃ овако РІРёСЃРѕРєРѕС РІСЂРµРґРЅРѕСЃС‚Рё грешке СЃРёРіСѓСЂРЅРѕ СРµ последица чињенице РґР° хлађење панела услед утицаСР° ветра РЅРёСЃРјРѕ узели Сѓ РѕР±Р·РёСЂ услед недостатка података Рѕ ветру. .. _pvwatts-pons: .. figure:: pvwatts-pons.png :width: 80% Поређење чистог *PVWAtts* модела СЃР° мереном РїСЂРѕРёР·РІРѕРґСљРѕРј РќРёСедан модел РЅРёСРµ савршена слика стварности Рё РЅРµ РјРѕР¶Рµ РґР° обухвати СЃРІРµ факторе РєРѕСРё утичу РЅР° РїСЂРѕРёР·РІРѕРґСљСѓ. Чак иако СРµ модел савршен (Р° РЅРµ РјРѕР¶Рµ бити), могуће СЃСѓ РїРѕСаве грешака РїСЂРё мерењу температуре, осунчаности, Р±СЂР·РёРЅРµ ветра. Даље, РєРѕРґ самог модела имамо више параметара чиСРµ вредности узимамо РёР· литературе Рё декларациСРµ произвођача. Реалне вредности тих параметара СЃРёРіСѓСЂРЅРѕ одступаССѓ РѕРґ тих вредности Рё мењаССѓ СЃРµ током животног века уређаСР°. Подешавање параметра помоћу НМПФЗ ---------------------------------- Поставља СЃРµ питање РґР° ли вредности РєРѕСРµ РґР°СРµ модел РјРѕРіСѓ бити приближниСРµ реалним вредностима само подешавањем параметара модела. Пробаћемо РґР° искористимо чињеницу РґР° податке Рѕ РїСЂРѕРёР·РІРѕРґСљРё Р·Р° недељу РѕРґ 31. октобра имамо Рё РґР° помоћу НМПФЗ пробамо РґР° "РїРѕРјРёСЂРёРјРѕ" излаз аналитичког модела Рё мерења РїСЂРѕРёР·РІРѕРґСљРµ тако што ћемо параметар ``a`` Седначине :math:numref:`eq:pvwatts` прогласити непознатим. РћСЃРЅРѕРІРЅР° РёРґРµСР° СРµ РґР° СЃРµ НМПФЗ тренира Рё Седначином Рё подацима Рё РґР° као излаз испоручи Рё модел СЃР° мањом грешком Рё РЅРѕРІСѓ, бољу вредност параметра ``a``. РќР° следећем листингу РјРѕРіСѓ СЃРµ видети интересантни делови имплементациСРµ РѕРІРµ РёРґРµСРµ: .. code-block:: python :caption: Рнверзни проблем подешавања параметара PVWatts/SAPM модела :linenos: # Parametar "a" pustamo da se trenira a_var = dde.Variable(-4.0) # # Jednacina koju koristi PINN # def pvwatts_eq(x, y): Ta = x[:,0:1] # Temperatura vazduha E = x[:,1:2] # Ukupna POA osuncanost Tm = E * tf.exp(a_var+b*2) + Ta # Brzina vetra uzeta kao prosecna od 2 m/s Tc = Tm + E/E0*deltaT P_dc_temp = ((Tc-Tref) * gamma_pdc + 1) P_dc = (E * 1.e-03 * pdc0 * P_dc_temp) * num_of_panels zeta = (P_dc+1.e-2)/pdc0_inv eta = eta_inv_nom/eta_inv_ref * (-0.0162*zeta - 0.0059/zeta + 0.9858) eta = tf.maximum(0., tf.sign(eta)) * eta ac = tf.minimum(eta*P_dc, pac0_inv) return y - ac # Imamo 168 tacaka sa merenjima proizvodnje. Pripremi strukturu za PointSet granicni uslov train_points = np.zeros((168,2)) train_measured_production = np.zeros((168,1)) train_points[:,0] = T_data_train.to_numpy().T train_points[:,1] = E_data_train.to_numpy().T train_measured_production[:,0] = P_data_train.to_numpy().T # Imamo 168 tacaka sa merenjima za narednu nedelju za test test_points = np.zeros((168,2)) test_measured_production = np.zeros((168,1)) test_points[:,0] = T_data_test.to_numpy().T test_points[:,1] = E_data_test.to_numpy().T test_measured_production[:,0] = P_data_test.to_numpy().T # Minimumi i maksimumi T i E za kreiranje geometrije problema minT, maxT = min(train_points[:,0]), max(train_points[:,0]) minE, maxE = min(train_points[:,1]), max(train_points[:,1]) geom = dde.geometry.Rectangle([minT, minE], [maxT, maxE]) bc_y = dde.icbc.PointSetBC(train_points, train_measured_production, component=0) # Isti broj kolokacionih tacaka za jednacinu i za granicne uslove. Moze i drugacije. data = dde.data.PDE(geom, pvwatts_eq, [bc_y], 168, 168, solution = orig_pvwatts_model, num_test=100) layer_size = [2] + [30] * 5 + [1] activation = "tanh" initializer = "Glorot uniform" net = dde.nn.FNN(layer_size, activation, initializer) variable_a = dde.callbacks.VariableValue(a_var, period=1000) model = dde.Model(data, net) model.compile(optimizer="adam", lr=0.001, metrics=["l2 relative error"], external_trainable_variables=[a_var]) losshistory, train_state = model.train(iterations=20000, callbacks=[variable_a]) predicted_test = model.predict(test_points) # Predikcije manje od nule nemaju smisla. Nuluj ih. predicted_test[predicted_test<0]=0 Као Рё РєРѕРґ раниСРµ обрађених инверзних проблема РєРѕСРё користе библиотеку *DeepXDE*, постављамо параметар као вариСаблу чиСР° СЃРµ вредност РґРѕР±РёСР° процесом обучавања: .. code-block:: python a_var = dde.Variable(-4.0) РђРєРѕ погледамо функциССѓ ``pvwatts_eq(x, y)``, РѕРЅР° СРµ готово идентична функциСРё ``orig_pvwatts_model(x)`` СЃР° :numref:`lst_pvwatts_orig`. Разлика СРµ Сѓ томе што ``pvwatts_eq(x, y)`` РЅРµ враћа вредност снаге, већ функциССѓ губитка, као што СЃРјРѕ већ навикли. Још Седна разлика огледа СЃРµ Сѓ коришћењу *TensorFlow* логике уместо условног израза: .. code-block:: python eta = tf.maximum(0., tf.sign(eta)) * eta РћРІР°С РёР·СЂР°Р· РЅРёСРµ ништа РґСЂСѓРіРѕ него услов РґР° ако имамо нефизичку вредност ``eta<0`` поставимо РґР° СРµ ``eta=0``. РћРІРѕРј формулациСРѕРј избегавамо инструкциССѓ условног СЃРєРѕРєР°, РєРѕСР° СЃРµ РЅР° графичком процесору РёР·РІРѕРґРё доста СЃРїРѕСЂРёСРµ РѕРґ чистог рачуна Сѓ покретном зарезу. РЈ даљем току програма треба РґР° поставимо структуру Р·Р° посебан гранични услов ``PointSet``, РєРѕСРё СЃРјРѕ већ користили Сѓ одељку :ref:`oscilacije_inverzni` Рё :ref:`poplavni`: .. code-block:: python train_points = np.zeros((168,2)) train_measured_production = np.zeros((168,1)) train_points[:,0] = T_data_train.to_numpy().T train_points[:,1] = E_data_train.to_numpy().T train_measured_production[:,0] = P_data_train.to_numpy().T bc_y = dde.icbc.PointSetBC(train_points, train_measured_production, component=0) Рмамо СѓРєСѓРїРЅРѕ 168 тачака (7x24) мерења РїСЂРѕРёР·РІРѕРґСљРµ РєРѕСРµ ћемо искористити Сѓ покушаССѓ РґР° "спустимо" вредности РєРѕСРµ РґР°СРµ оригинални модел. ГеометриССѓ проблема РєРѕСРё решавамо дефинишемо опсегом улазних вариСабли температуре Рё СѓРєСѓРїРЅРµ осунчаности, РєРѕСРµ СЃРµ СѓР·РёРјР°ССѓ РёР· табеле података. РћРЅРґР° можемо РґР° поставимо Рё колокационе тачке РЅР° домену наредбом: .. code-block:: python data = dde.data.PDE(geom, pvwatts_eq, [bc_y], 168, 168, solution = orig_pvwatts_model, num_test=100) Р—Р° Р±СЂРѕС СЃР»СѓС‡Р°СРЅРёС… колокационих тачака унутар домена узели СЃРјРѕ исти Р±СЂРѕС С‚Р°С‡Р°РєР° колико имамо Сѓ ``PointSet`` граничном услову. РќРёСРµ РЅСѓР¶РЅРѕ РґР° Р±СЂРѕС С‚Р°С‡Р°РєР° Р±СѓРґРµ Седнак, РїР° остављамо читаоцу РґР° експериментише различитим вредностима. Остатак РєРѕРґР° СРµ мање-више исти као РєРѕРґ СЃРІРёС… РґСЂСѓРіРёС… примера РєРѕСРё користе DeepXDE Р·Р° решавање инверзних проблема. РўСѓ СРµ постављање архитектуре НМПФЗ Рё хипер-параметара, алгоритма оптимизациСРµ, стопе РѕР±СѓРєРµ, *callback* функциСРµ Р·Р° штампу тренутне вредности ``a_var`` током РѕР±СѓРєРµ Рё слично. РќР° РєСЂР°ССѓ СЃРµ анулираССѓ негативне вредности предвиђене РїСЂРѕРёР·РІРѕРґСљРµ Сер немаССѓ физичког смисла.