-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rewrite functions in pv_model #689
base: dev
Are you sure you want to change the base?
Changes from all commits
dbfc369
55f24cd
66cd6eb
e7473d0
1c92a27
684e9cd
eb59fd4
bb05389
e7e9bcc
bd362d9
8fbf117
993b0fd
8e8549e
88d1062
761e8eb
e725f06
b755427
ac0828e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,6 +115,7 @@ final case class PvModel private ( | |
lat, | ||
gammaE, | ||
alphaE, | ||
duration, | ||
) | ||
|
||
// === Diffuse Radiation Parameters ===// | ||
|
@@ -337,7 +338,7 @@ final case class PvModel private ( | |
val e0 = 1.000110 + | ||
0.034221 * cos(jInRad) + | ||
0.001280 * sin(jInRad) + | ||
0.000719 * cos(2d * jInRad) + | ||
0.00719 * cos(2d * jInRad) + | ||
0.000077 * sin(2d * jInRad) | ||
|
||
// solar constant in W/m2 | ||
|
@@ -409,32 +410,27 @@ final case class PvModel private ( | |
omegaSS: Angle, | ||
omegaSR: Angle, | ||
): Option[(Angle, Angle)] = { | ||
val thetaGInRad = thetaG.toRadians | ||
val omegaSSInRad = omegaSS.toRadians | ||
val omegaSRInRad = omegaSR.toRadians | ||
|
||
val omegaOneHour = toRadians(15d) | ||
val omegaHalfHour = omegaOneHour / 2d | ||
|
||
val omega1InRad = omega.toRadians // requested hour | ||
val omega2InRad = omega1InRad + omegaOneHour // requested hour plus 1 hour | ||
|
||
// (thetaG < 90°): sun is visible | ||
// (thetaG > 90°), otherwise: sun is behind the surface -> no direct radiation | ||
if ( | ||
thetaGInRad < toRadians(90) | ||
// omega1 and omega2: sun has risen and has not set yet | ||
&& omega2InRad > omegaSRInRad + omegaHalfHour | ||
&& omega1InRad < omegaSSInRad - omegaHalfHour | ||
// requested time is between sunrise and sunset (+/- one hour) | ||
omega1InRad > omegaSRInRad - omegaOneHour | ||
&& omega1InRad < omegaSSInRad | ||
) { | ||
|
||
val (finalOmega1, finalOmega2) = | ||
if (omega1InRad < omegaSRInRad) { | ||
// requested time earlier than sunrise | ||
(omegaSRInRad, omegaSRInRad + omegaOneHour) | ||
} else if (omega2InRad > omegaSSInRad) { | ||
// sunset earlier than requested time | ||
(omegaSSInRad - omegaOneHour, omegaSSInRad) | ||
(omegaSRInRad, omega2InRad) | ||
} else if (omega1InRad > omegaSSInRad - omegaOneHour) { | ||
// requested time is less than one hour before sunset | ||
(omega1InRad, omegaSSInRad) | ||
} else { | ||
(omega1InRad, omega2InRad) | ||
} | ||
|
@@ -464,13 +460,23 @@ final case class PvModel private ( | |
* @return | ||
* the beam radiation on the sloped surface | ||
*/ | ||
|
||
def calculateTimeFrame(omegas: Option[(Angle, Angle)]): Double = { | ||
omegas match { | ||
case Some((omega1, omega2)) => | ||
(omega2 - omega1).toDegrees / 15 | ||
|
||
case None => 0d | ||
} | ||
} | ||
private def calcBeamRadiationOnSlopedSurface( | ||
eBeamH: Irradiation, | ||
omegas: Option[(Angle, Angle)], | ||
delta: Angle, | ||
latitude: Angle, | ||
gammaE: Angle, | ||
alphaE: Angle, | ||
duration: Time, | ||
): Irradiation = { | ||
|
||
omegas match { | ||
|
@@ -482,6 +488,9 @@ final case class PvModel private ( | |
|
||
val omega1InRad = omega1.toRadians | ||
val omega2InRad = omega2.toRadians | ||
// variable that accounts for cases when the integration interval is shorter than 15° (1 hour equivalent), when the time is close to sunrise or sunset | ||
val timeFrame = | ||
(omega2 - omega1).toDegrees / 15d / duration.toHours // original term: (omega2 - omega1).toRadians * 180 / Math.PI / 15, since a one hour difference equals 15° | ||
|
||
val a = ((sin(deltaInRad) * sin(latInRad) * cos(gammaEInRad) | ||
- sin(deltaInRad) * cos(latInRad) * sin(gammaEInRad) * cos( | ||
|
@@ -503,7 +512,7 @@ final case class PvModel private ( | |
|
||
// in rare cases (close to sunrise) r can become negative (although very small) | ||
val r = max(a / b, 0d) | ||
eBeamH * r | ||
eBeamH * r * timeFrame | ||
case None => WattHoursPerSquareMeter(0d) | ||
} | ||
} | ||
|
@@ -533,6 +542,41 @@ final case class PvModel private ( | |
* @return | ||
* the diffuse radiation on the sloped surface | ||
*/ | ||
|
||
private def calcEpsilon( | ||
eDifH: Irradiation, | ||
eBeamH: Irradiation, | ||
thetaZ: Angle, | ||
): Double = { | ||
val thetaZInRad = thetaZ.toRadians | ||
|
||
((eDifH + eBeamH / cos(thetaZInRad)) / eDifH + (5.535d * 1.0e-6) * pow( | ||
thetaZ.toDegrees, | ||
3, | ||
)) / | ||
(1d + (5.535d * 1.0e-6) * pow(thetaZ.toDegrees, 3)) | ||
} | ||
|
||
private def calcEpsilonOld( | ||
eDifH: Irradiation, | ||
eBeamH: Irradiation, | ||
thetaZ: Angle, | ||
): Double = { | ||
val thetaZInRad = thetaZ.toRadians | ||
|
||
((eDifH + eBeamH) / eDifH + (5.535d * 1.0e-6) * pow(thetaZ.toRadians, 3)) / | ||
(1d + (5.535d * 1.0e-6) * pow(thetaZ.toRadians, 3)) | ||
} | ||
|
||
private def firstFraction( | ||
eDifH: Irradiation, | ||
eBeamH: Irradiation, | ||
thetaZ: Angle, | ||
): Double = { | ||
|
||
(eDifH + eBeamH) / eDifH | ||
} | ||
|
||
private def calcDiffuseRadiationOnSlopedSurfacePerez( | ||
eDifH: Irradiation, | ||
eBeamH: Irradiation, | ||
|
@@ -555,12 +599,12 @@ final case class PvModel private ( | |
|
||
if (eDifH.value.doubleValue > 0) { | ||
// if we have diffuse radiation on horizontal surface we have to check if we have another epsilon due to clouds get the epsilon | ||
var epsilon = ((eDifH + eBeamH) / eDifH + | ||
var epsilon = ((eDifH + eBeamH / cos(thetaZInRad)) / eDifH + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both Duffie and the original Perez use the formula as before. Where did you find the formula with cos thetaZ again? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is my reference (Duffie p. 95f). Note that "I_b,n" is not the beam radiation on a horizontal surface, but rather the beam radiation on a surface normal to the direction of the sun. This can be calculated by dividing the beam radiation on a horizontal surface "I_b" (=eBeamH in code) by cos(ThetaZ). This is also demonstrated in Duffie: example 2.16.2 |
||
(5.535d * 1.0e-6) * pow( | ||
thetaZInRad, | ||
thetaZ.toDegrees, | ||
SimonHuette marked this conversation as resolved.
Show resolved
Hide resolved
|
||
3, | ||
)) / (1d + (5.535d * 1.0e-6) * pow( | ||
thetaZInRad, | ||
thetaZ.toDegrees, | ||
3, | ||
)) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Iqbal, this is 0.000719 with three zeroes. The primary source, Spencer, also states the same. Duffie and Zheng as well. Please check again.
Furthermore, could you add the missing sources I just mentioned to the list of sources in documentation as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is Duffie p. 9, where I noticed the 2 zeros only. Can you maybe send me the PDFs of the other books, so I can look it up aswell?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly, the fifth edition of Duffie seems to differ from all earlier editions in this point. Given that the cited sources stayed the same and I didn't find any other explanation (and the layout seems broken in this edition for the first time), I assume that the change did not happen on purpose and the number with three zeros is still correct. There should be some more investigations here, though.