Skip to content

Commit 2fc6e69

Browse files
authored
Merge pull request #1455 from open-ideas/issue1436_addPvtModel
Issue1436 add pvt model
2 parents 2080e26 + 872edb9 commit 2fc6e69

89 files changed

Lines changed: 5194 additions & 3 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
# Set default behaviour, in case users don't have core.autocrlf set.
22
* text=auto
3-
43
# Explicitly declare text files we want to always be normalized and converted
54
# to native line endings on checkout.
65
*.mo text
76
*.mos text
87
*.mop text
98
*.py text
109
*.txt text
11-
1210
# Declare files that will always have CRLF line endings on checkout.
1311
#*.sln text eol=crlf
14-
1512
# Denote all files that are truly binary and should not be modified.
1613
*.png binary
1714
*.jpg binary
15+
IDEAS/Resources/Data/Fluid/PVTCollectors/Validation/PVT_UN/PVT_UN_measurements.txt filter=lfs diff=lfs merge=lfs -text

.github/workflows/github-actions.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ jobs:
7878
run: make test-dymola PACKAGE=\"IDEAS.Fluid.MixingVolumes\" INTERACTIVE=false
7979
- name: Test IDEAS.Fluid.Movers
8080
run: make test-dymola PACKAGE=\"IDEAS.Fluid.Movers\" INTERACTIVE=false
81+
- name: Test IDEAS.Fluid.PVTCollectors
82+
run: make test-dymola PACKAGE=\"IDEAS.Fluid.PVTCollectors.BaseClasses.Examples\" INTERACTIVE=false
83+
&& make test-dymola PACKAGE=\"IDEAS.Fluid.PVTCollectors.Examples\" INTERACTIVE=false
8184
- name: Test IDEAS.Fluid.Sensors
8285
run: make test-dymola PACKAGE=\"IDEAS.Fluid.Sensors\" INTERACTIVE=false
8386
- name: Test IDEAS.Fluid.SolarCollectors
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
within IDEAS.Fluid.PVTCollectors.BaseClasses;
2+
model ElectricalPVT
3+
"Calculate the electrical power output of a PVT using the PVWatts v5 approach"
4+
extends Modelica.Blocks.Icons.Block;
5+
extends IDEAS.Fluid.SolarCollectors.BaseClasses.PartialParameters;
6+
7+
// Parameters
8+
parameter Modelica.Units.SI.Irradiance HGloHorNom = 1000 "global horizontal irradiances";
9+
parameter Modelica.Units.SI.Efficiency eleLosFac = 0.09 "PV loss factor";
10+
parameter Modelica.Units.SI.Temperature TpvtRef = 298.15 "Reference cell temperature";
11+
parameter Real gamma "Temperature coefficient [1/K]";
12+
parameter Modelica.Units.SI.Power P_nominal "Nominal PV power";
13+
parameter Modelica.Units.SI.Area A "PV area";
14+
parameter Modelica.Units.SI.Efficiency eta0 "Zero-loss efficiency";
15+
parameter Modelica.Units.SI.DimensionlessRatio tauAlpEff "Effective transmittance–absorptance product";
16+
parameter Modelica.Units.SI.CoefficientOfHeatTransfer c1 "First-order heat loss coefficient";
17+
parameter Modelica.Units.SI.Efficiency etaEl "Electrical efficiency";
18+
19+
parameter Modelica.Units.SI.CoefficientOfHeatTransfer UAbsFluid =
20+
((tauAlpEff - etaEl) * (c1 + abs(gamma)*HGloHorNom)) / ((tauAlpEff - etaEl) - eta0)
21+
"Heat transfer coefficient between the fluid and the PV cells, calculated from datasheet parameters";
22+
23+
// Inputs
24+
Modelica.Blocks.Interfaces.RealInput Tflu[nSeg]
25+
"Fluid temperatures per segment [K]"
26+
annotation (Placement(transformation(extent={{-140,40},{-100,80}}),
27+
iconTransformation(extent={{-140,40},{-100,80}})));
28+
Modelica.Blocks.Interfaces.RealInput Qth[nSeg]
29+
"Thermal power density per segment [W/m2]"
30+
annotation (Placement(transformation(extent={{-140,-20},{-100,20}}),
31+
iconTransformation(extent={{-140,-20},{-100,20}})));
32+
Modelica.Blocks.Interfaces.RealInput HGloTil
33+
"Global tilted irradiance [W/m2]"
34+
annotation (Placement(transformation(extent={{-140,-80},{-100,-40}}),
35+
iconTransformation(extent={{-140,-80},{-100,-40}})));
36+
37+
// Outputs (user-facing)
38+
Modelica.Blocks.Interfaces.RealOutput Pel
39+
"Total electrical power output [W]"
40+
annotation (Placement(transformation(extent={{100,40},{140,80}}),
41+
iconTransformation(extent={{100,40},{140,80}})));
42+
Modelica.Blocks.Interfaces.RealOutput TavgCel
43+
"Average PV module temperature [K]"
44+
annotation (Placement(transformation(extent={{100,-20},{140,20}}),
45+
iconTransformation(extent={{100,-20},{140,20}})));
46+
Modelica.Blocks.Interfaces.RealOutput TavgFlu
47+
"Average fluid temperature [K]"
48+
annotation (Placement(transformation(extent={{100,-80},{140,-40}}),
49+
iconTransformation(extent={{100,-80},{140,-40}})));
50+
51+
protected
52+
// internal variables (not exposed as connectors)
53+
Modelica.Units.SI.Temperature temMod "Average cell/module temperature ";
54+
Modelica.Units.SI.Temperature temMea "Average fluid temperature";
55+
Modelica.Units.SI.Temperature TCel[nSeg];
56+
Modelica.Units.SI.Temperature TDif[nSeg];
57+
Modelica.Units.SI.Power Pel_int[nSeg];
58+
59+
equation
60+
for i in 1:nSeg loop
61+
TCel[i] = Tflu[i] +Qth[i] / UAbsFluid;
62+
TDif[i] = TCel[i] - TpvtRef;
63+
Pel_int[i] = (A_c/nSeg) * (P_nominal/A) * (HGloTil/HGloHorNom) *
64+
(1 + gamma * TDif[i]) * (1 - eleLosFac);
65+
end for;
66+
67+
Pel = sum(Pel_int);
68+
temMod = sum(TCel) / nSeg;
69+
temMea = sum(Tflu) / nSeg;
70+
TavgCel = temMod;
71+
TavgFlu = temMea;
72+
73+
annotation (
74+
defaultComponentName="eleGen",
75+
Documentation(info="<html>
76+
<p>
77+
This component computes the electrical power output of a photovoltaic-thermal (PVT) collector using the PVWatts v5 methodology (Dobos, 2014), adapted for PVT systems.
78+
It is part of a validated, open-source Modelica implementation that relies solely on manufacturer datasheet parameters, as described in Meertens et al. (2025).
79+
</p>
80+
<p>
81+
The model calculates the electrical output for each segment <i>i ∈ {1, ..., n<sub>seg</sub>}</i> as:
82+
</p>
83+
<p align=\"center\" style=\"font-style:italic;\">
84+
P<sub>el,i</sub> = (A<sub>c</sub> / n<sub>seg</sub>) &#183 (P<sub>nom</sub> / A)
85+
&#183 (G<sub>tilt</sub> / G<sub>nom</sub>) &#183 (1 + &gamma; &#183 &Delta;T<sub>i</sub>) &#183 (1 - eleLosFac)
86+
</p>
87+
<p>
88+
where:
89+
<ul>
90+
<li>
91+
<i>&Delta;T<sub>i</sub> = T<sub>cell,i</sub> - T<sub>ref</sub></i>: temperature difference between PV cell and reference temperature
92+
</li>
93+
<li>
94+
<i>P<sub>nom</sub></i>: nominal PV power under STC [W]
95+
</li>
96+
<li>
97+
<i>A</i>: gross collector area [m²]
98+
</li>
99+
<li>
100+
<i>A<sub>c</sub></i>: effective collector area (equal to A if not otherwise specified)
101+
</li>
102+
<li>
103+
<i>G<sub>tilt</sub></i>: global irradiance on the tilted collector plane [W/m²]
104+
</li>
105+
<li>
106+
<i>G<sub>nom</sub></i>: nominal irradiance (typically 1000 W/m²)
107+
</li>
108+
<li>
109+
<i>&gamma;</i>: temperature coefficient of power [%/K]
110+
</li>
111+
<li>
112+
<i>eleLosFac</i>: lumped system loss factor
113+
</li>
114+
</ul>
115+
</p>
116+
<p>
117+
The PV cell temperature is estimated from the fluid temperature and thermal power density using:
118+
</p>
119+
<p align=\"center\" style=\"font-style:italic;\">
120+
T<sub>cell,i</sub> = T<sub>m,i</sub> + q<sub>th,i</sub> / U<sub>AbsFluid</sub>
121+
</p>
122+
<p>
123+
The internal heat transfer coefficient <i>UAbsFluid</i> is approximately calculated from datasheet parameters.
124+
For the mathematical description and visualisation, see <a href='modelica://IDEAS.Fluid.PVTCollectors.UsersGuide'>IDEAS.Fluid.PVTCollectors.UsersGuide</a>.
125+
</p>
126+
127+
<h5>Electrical performance and losses</h5>
128+
<p>
129+
The electrical submodel includes an overall system loss factor <code>eleLosFac</code>.
130+
PVWatts reports a total electrical power loss of 14%, resulting from the following mechanisms:
131+
</p>
132+
<table border=\"1\" cellpadding=\"4\">
133+
<tr>
134+
<th style=\"text-align:left;\">Electrical power loss mechanism</th>
135+
<th style=\"text-align:center;\">Default value</th>
136+
</tr>
137+
<tr>
138+
<td style=\"text-align:left;\">Soiling</td>
139+
<td style=\"text-align:center;\">2 %</td>
140+
</tr>
141+
<tr>
142+
<td style=\"text-align:left;\">Shading</td>
143+
<td style=\"text-align:center;\">3 %</td>
144+
</tr>
145+
<tr>
146+
<td style=\"text-align:left;\">Mismatch</td>
147+
<td style=\"text-align:center;\">2 %</td>
148+
</tr>
149+
<tr>
150+
<td style=\"text-align:left;\">Wiring</td>
151+
<td style=\"text-align:center;\">2 %</td>
152+
</tr>
153+
<tr>
154+
<td style=\"text-align:left;\">Connections</td>
155+
<td style=\"text-align:center;\">0.5 %</td>
156+
</tr>
157+
<tr>
158+
<td style=\"text-align:left;\">Light‑induced degradation</td>
159+
<td style=\"text-align:center;\">1.5 %</td>
160+
</tr>
161+
<tr>
162+
<td style=\"text-align:left;\">Nameplate rating</td>
163+
<td style=\"text-align:center;\">1 %</td>
164+
</tr>
165+
<tr>
166+
<td style=\"text-align:left;\">Availability</td>
167+
<td style=\"text-align:center;\">3 %</td>
168+
</tr>
169+
<tr>
170+
<th style=\"text-align:left;\">Total</th>
171+
<th style=\"text-align:center;\">14 %</th>
172+
</tr>
173+
</table>
174+
<p>
175+
For well-maintained, unshaded modules, experimental validation (Meertens et al., 2025)
176+
found that using <code>eleLosFac = 9%</code> gives excellent agreement with
177+
measured electrical output. For PVT collectors with a high positive tolerance on the
178+
electrical output, this system loss factor can even be lower.
179+
Users may adjust <code>eleLosFac</code> to account for site-specific soiling or shading effects.
180+
</p>
181+
182+
<h4>Implementation Notes</h4>
183+
<p>
184+
This model is designed for (unglazed) PVT collectors and supports discretization into multiple segments to capture temperature gradients along the flow path.
185+
It is compatible with the thermal model based on ISO 9806:2013 and is suitable for dynamic simulations where irradiance and fluid temperatures vary over time.
186+
</p>
187+
188+
<h4>References</h4>
189+
<ul>
190+
<li>
191+
Dobos, A. P. (2014). <i><a href='https://docs.nrel.gov/docs/fy14osti/62641.pdf'>PVWatts Version 5 Manual</a></i>. NREL/TP-6A20-62641
192+
</li>
193+
<li>
194+
Meertens, L., Jansen, J., Helsen, L. (2025).
195+
<i>Development and Experimental Validation of an Unglazed Photovoltaic-Thermal Collector Modelica Model that only needs Datasheet Parameters</i>,
196+
submitted to the 16th International Modelica & FMI Conference, Lucerne, Switzerland, Sep 8–10, 2025.
197+
</li>
198+
</ul>
199+
</html>",
200+
revisions="<html>
201+
<ul>
202+
<li>
203+
July 7, 2025, by Lone Meertens:<br/>
204+
First implementation PVT model.
205+
This is for <a href=\"https://github.com/open-ideas/IDEAS/issues/1436\">#1436</a>.
206+
</li>
207+
</ul>
208+
</html>"));
209+
210+
end ElectricalPVT;
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
within IDEAS.Fluid.PVTCollectors.BaseClasses.Examples;
2+
model ISO9806HeatLoss
3+
"Example showing the use of ISO9806QuasiDynamicHeatLoss"
4+
extends Modelica.Icons.Example;
5+
replaceable package Medium = IDEAS.Media.Water "Medium in the system";
6+
7+
parameter IDEAS.Fluid.PVTCollectors.Data.GenericQuasiDynamic per=
8+
IDEAS.Fluid.PVTCollectors.Data.Uncovered.UI_Validation()
9+
"Performance data" annotation (choicesAllMatching=true);
10+
Modelica.Blocks.Sources.Sine T1(
11+
amplitude=15,
12+
f=0.1,
13+
offset=273.15 + 10) "Temperature of the first segment"
14+
annotation (Placement(transformation(extent={{-92,-22},{-72,-2}})));
15+
Modelica.Blocks.Sources.Sine T2(
16+
f=0.1,
17+
amplitude=15,
18+
offset=273.15 + 15) "Temperature of the second segment"
19+
annotation (Placement(transformation(extent={{-68,-36},{-48,-16}})));
20+
Modelica.Blocks.Sources.Sine T3(
21+
f=0.1,
22+
amplitude=15,
23+
offset=273.15 + 20) "Temperature of the third segment"
24+
annotation (Placement(transformation(extent={{-90,-52},{-70,-32}})));
25+
ISO9806QuasiDynamicHeatLoss heaLosQuaDyn(
26+
nSeg=3,
27+
redeclare package Medium = Medium,
28+
c1=per.c1,
29+
c2=per.c2,
30+
c3=per.c3,
31+
c4=per.c4,
32+
c6=per.c6,
33+
A_c=per.A) annotation (Placement(transformation(extent={{18,-2},{38,18}})));
34+
35+
IDEAS.Fluid.SolarCollectors.BaseClasses.EN12975HeatLoss heaLosSteSta(
36+
A_c=per.A,
37+
nSeg=3,
38+
redeclare package Medium = Medium,
39+
a1=per.c1,
40+
a2=per.c2)
41+
annotation (Placement(transformation(extent={{18,-68},{38,-48}})));
42+
Modelica.Blocks.Sources.Sine TEnv(
43+
f=0.01,
44+
offset=273.15 + 10,
45+
amplitude=15) "Temperature of the surrounding environment"
46+
annotation (Placement(transformation(extent={{-80,24},{-60,44}})));
47+
Modelica.Blocks.Sources.Sine winSpePla(
48+
f=1/(24*3600),
49+
phase=0,
50+
offset=3,
51+
amplitude=5) "wind speed in the collector plane"
52+
annotation (Placement(transformation(extent={{60,58},{80,78}})));
53+
Modelica.Blocks.Sources.RealExpression HHorIR(y=400) "long wave irradiance"
54+
annotation (Placement(transformation(extent={{-1.5,58},{17.5,74}})));
55+
Modelica.Blocks.Interfaces.RealOutput QLos_flow_QuaDyn[3]
56+
"Heat loss rate at current conditions"
57+
annotation (Placement(transformation(extent={{60,-2},{80,18}})));
58+
Modelica.Blocks.Interfaces.RealOutput QLos_flow_SteSta[3]
59+
"Heat loss rate at current conditions"
60+
annotation (Placement(transformation(extent={{62,-68},{82,-48}})));
61+
Modelica.Blocks.Sources.RealExpression HGloTil(y=800) "Global irradiance on the tilted surface"
62+
annotation (Placement(transformation(extent={{26.5,58},{45.5,74}})));
63+
equation
64+
connect(winSpePla.y, heaLosQuaDyn.winSpePla);
65+
connect(HHorIR.y, heaLosQuaDyn.HHorIR);
66+
connect(HGloTil.y, heaLosQuaDyn.HGloTil);
67+
connect(T3.y, heaLosQuaDyn.TFlu[3]) annotation (Line(points={{-69,-42},{-44,-42},
68+
{-44,2},{-20,2},{-20,2.66667},{16,2.66667}},
69+
color={0,0,127}));
70+
connect(T2.y, heaLosQuaDyn.TFlu[2]) annotation (Line(points={{-47,-26},{-44,-26},
71+
{-44,2},{16,2}}, color={0,0,127}));
72+
connect(TEnv.y, heaLosQuaDyn.TEnv) annotation (Line(points={{-59,34},{8,34},{8,
73+
14},{16,14}}, color={0,0,127}));
74+
connect(heaLosSteSta.TEnv, TEnv.y) annotation (Line(points={{16,-52},{8,-52},{
75+
8,34},{-59,34}}, color={0,0,127}));
76+
connect(T1.y, heaLosSteSta.TFlu[1]) annotation (Line(points={{-71,-12},{-68,
77+
-12},{-68,2},{-44,2},{-44,-64.6667},{16,-64.6667}},
78+
color={0,0,127}));
79+
connect(T2.y, heaLosSteSta.TFlu[2]) annotation (Line(points={{-47,-26},{-44,-26},
80+
{-44,-64},{16,-64}}, color={0,0,127}));
81+
connect(T3.y, heaLosSteSta.TFlu[3]) annotation (Line(points={{-69,-42},{-44,
82+
-42},{-44,-63.3333},{16,-63.3333}},
83+
color={0,0,127}));
84+
connect(T1.y, heaLosQuaDyn.TFlu[1]) annotation (Line(points={{-71,-12},{-68,-12},
85+
{-68,1.33333},{16,1.33333}}, color={0,0,127}));
86+
connect(heaLosQuaDyn.QLos_flow, QLos_flow_QuaDyn)
87+
annotation (Line(points={{39,8},{70,8}}, color={0,0,127}));
88+
connect(heaLosSteSta.QLos_flow, QLos_flow_SteSta)
89+
annotation (Line(points={{39,-58},{72,-58}}, color={0,0,127}));
90+
annotation (
91+
Documentation(info="<html>
92+
<p>
93+
This example demonstrates the implementation of
94+
<a href=\"modelica://IDEAS.Fluid.PVTCollectors.BaseClasses.ISO9806QuasiDynamicHeatLoss\">
95+
IDEAS.Fluid.PVTCollectors.BaseClasses.ISO9806QuasiDynamicHeatLoss</a>,
96+
which calculates the quasi-dynamic heat loss of a PVT or solar thermal collector
97+
according to the ISO 9806:2013 standard.
98+
</p>
99+
<p>
100+
In addition to showcasing the ISO 9806-based model, this example also compares its behavior
101+
to the steady-state heat loss model
102+
<a href=\"modelica://IDEAS.Fluid.SolarCollectors.BaseClasses.EN12975HeatLoss\">
103+
IDEAS.Fluid.SolarCollectors.BaseClasses.EN12975HeatLoss</a>,
104+
which is based on the now-superseded EN 12975 standard.
105+
</p>
106+
<p>
107+
This comparison highlights the differences between the steady-state and quasi-dynamic
108+
approaches, particularly in how they account for environmental factors such as wind speed
109+
and long-wave irradiance.
110+
</p>
111+
</html>",
112+
revisions="<html>
113+
<ul>
114+
<li>
115+
July 2, 2025, by Lone Meertens:<br/>
116+
First implementation of ISO 9806 quasi-dynamic heat loss example.
117+
This is for <a href=\"https://github.com/open-ideas/IDEAS/issues/1436\">1436</a>.
118+
</li>
119+
</ul>
120+
</html>"),
121+
__Dymola_Commands(file="modelica://IDEAS/Resources/Scripts/Dymola/Fluid/PVTCollectors/BaseClasses/Examples/ISO9806HeatLoss.mos"
122+
"Simulate and plot"),
123+
experiment(
124+
StartTime=0,
125+
StopTime=86400,
126+
Interval=60,
127+
Tolerance=1e-06,
128+
__Dymola_Algorithm="dassl"));
129+
end ISO9806HeatLoss;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
within IDEAS.Fluid.PVTCollectors.BaseClasses;
2+
package Examples
3+
"Collection of models that illustrate model use and test models"
4+
extends Modelica.Icons.ExamplesPackage;
5+
6+
annotation (preferredView="info", Documentation(info="<html>
7+
<p>
8+
This package contains examples for the use of models that can be found in
9+
<a href=\"modelica://IDEAS.Fluid.PVTCollectors.BaseClasses\">
10+
IDEAS.Fluid.PvtCollectors.BaseClasses.</a>
11+
</p>
12+
</html>"));
13+
end Examples;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ISO9806HeatLoss

0 commit comments

Comments
 (0)