Skip to content

Commit ae16711

Browse files
allenlawrence94Casey Zak
andauthored
Bifacial option in Mermoud Lejeune module model (#622)
* feat(): Expose bifacial model for mlm module model * test: test values from mlm bifacial model * fix: add nominal module efficiency calculation for Mermoud Lejuene model * fix: handle divide by 0 in mlm iam calculation * test: fixed performance ratio tests now that nominal module efficiency is calculated Co-authored-by: Casey Zak <[email protected]>
1 parent 8e9dcb0 commit ae16711

File tree

6 files changed

+9270
-14
lines changed

6 files changed

+9270
-14
lines changed

shared/lib_mlmodel.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -186,19 +186,31 @@ bool mlmodel_module_t::operator() (pvinput_t &input, double T_C, double opvoltag
186186
}
187187

188188
// Total effective irradiance
189-
double S;
189+
double S_front, S_total, S_eff_front, S_eff_total;
190190
if(input.radmode != 3){ // Skip module cover effects if using POA reference cell data
191-
S = (f_IAM_beam * input.Ibeam + f_IAM_diff * input.Idiff + groundRelfectionFraction * f_IAM_gnd * input.Ignd) * f_AM;
191+
S_front = input.Ibeam + input.Idiff + input.Ignd;
192+
S_total = S_front + input.Irear; // Note the rear irradiance has already taken bifaciality into consideration
193+
S_eff_front = (f_IAM_beam * input.Ibeam + f_IAM_diff * input.Idiff + groundRelfectionFraction * f_IAM_gnd * input.Ignd) * f_AM;
194+
S_eff_total = S_eff_front + input.Irear * f_AM;
195+
if (S_front > 1e-8) { // TODO: should sunup catch this?
196+
out.AOIModifier = S_eff_front / S_front;
197+
}
198+
else {
199+
out.AOIModifier = 1.0;
200+
}
192201
}
193202
else if(input.usePOAFromWF){ // Check if decomposed POA is required, if not use weather file POA directly
194-
S = input.poaIrr;
203+
S_total = S_eff_total = input.poaIrr;
204+
out.AOIModifier = 1.0;
195205
}
196206
else { // Otherwise use decomposed POA
197-
S = (f_IAM_beam * input.Ibeam + f_IAM_diff * input.Idiff + groundRelfectionFraction * f_IAM_gnd * input.Ignd) * f_AM;
207+
S_total = input.poaIrr;
208+
S_eff_total = input.Ibeam + input.Idiff + input.Ignd + input.Irear;
209+
out.AOIModifier = 1.0;
198210
}
199211

200212
// Single diode model acc. to [1]
201-
if (S >= 1)
213+
if (S_eff_total >= 1)
202214
{
203215
double n=0.0, a=0.0, I_L=0.0, I_0=0.0, R_sh=0.0, I_sc=0.0;
204216
double V_oc = V_oc_ref; // V_oc_ref as initial guess
@@ -217,16 +229,16 @@ bool mlmodel_module_t::operator() (pvinput_t &input, double T_C, double opvoltag
217229
for (int i = 1; i <= iterations; i = i + 1) {
218230
if (T_mode == T_MODE_FAIMAN) {
219231
// T_cell = input.Tdry + (T_c_fa_alpha * G_total * (1 - eff)) / (T_c_fa_U0 + input.Wspd * T_c_fa_U1);
220-
T_cell = input.Tdry + (T_c_fa_alpha * S * (1 - eff)) / (T_c_fa_U0 + input.Wspd * T_c_fa_U1);
232+
T_cell = input.Tdry + (T_c_fa_alpha * S_eff_total* (1 - eff)) / (T_c_fa_U0 + input.Wspd * T_c_fa_U1);
221233
}
222234

223235
n = n_0 + mu_n * (T_cell - T_ref);
224236
a = N_series * k * (T_cell + T_0) * n / q;
225-
I_L = (S / S_ref) * (I_Lref + alpha_isc * (T_cell - T_ref));
226-
//I_L = (S / S_ref) * (I_Lref + alpha_isc / N_parallel * (T_cell - T_ref));
237+
I_L = (S_eff_total/ S_ref) * (I_Lref + alpha_isc * (T_cell - T_ref));
238+
//I_L = (S_eff_total/ S_ref) * (I_Lref + alpha_isc / N_parallel * (T_cell - T_ref));
227239
I_0 = I_0ref * pow(((T_cell + T_0) / (T_ref + T_0)), 3) * exp((q * E_g) / (n * k) * (1 / (T_ref + T_0) - 1 / (T_cell + T_0)));
228240

229-
R_sh = R_shref + (R_sh0 - R_shref) * exp(-R_shexp * (S / S_ref));
241+
R_sh = R_shref + (R_sh0 - R_shref) * exp(-R_shexp * (S_eff_total/ S_ref));
230242

231243
V_oc = openvoltage_5par_rec(V_oc, a, I_L, I_0, R_sh, D2MuTau, Vbi);
232244
I_sc = I_L / (1 + R_s / R_sh);
@@ -243,7 +255,7 @@ bool mlmodel_module_t::operator() (pvinput_t &input, double T_C, double opvoltag
243255
else I = current_5par_rec(V, 0.9*I_L, a, I_L, I_0, R_s, R_sh, D2MuTau, Vbi);
244256
P = V*I;
245257
}
246-
eff = P / ((Width * Length) * (input.Ibeam + input.Idiff + input.Ignd));
258+
eff = P / ((Width * Length) * S_total);
247259
}
248260

249261
out.Power = P;
@@ -253,7 +265,6 @@ bool mlmodel_module_t::operator() (pvinput_t &input, double T_C, double opvoltag
253265
out.Voc_oper = V_oc;
254266
out.Isc_oper = I_sc;
255267
out.CellTemp = T_cell;
256-
out.AOIModifier = S / (input.Ibeam + input.Idiff + input.Ignd);
257268
}
258269

259270
return out.Power >= 0;

shared/lib_pv_io_manager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,10 @@ Module_IO::Module_IO(compute_module* cm, std::string cmName, double dcLoss)
12161216
else if (modulePowerModel == MODULE_PVYIELD)
12171217
{
12181218
// Mermoud/Lejeune single-diode model
1219+
isBifacial = cm->as_boolean("mlm_is_bifacial");
1220+
bifaciality = cm->as_double("mlm_bifaciality");
1221+
bifacialTransmissionFactor = cm->as_double("mlm_bifacial_transmission_factor");
1222+
groundClearanceHeight = cm->as_double("mlm_bifacial_ground_clearance_height");
12191223
size_t elementCount1 = 0;
12201224
size_t elementCount2 = 0;
12211225
ssc_number_t* arrayIncAngle = 0;

ssc/cmod_pvsamv1.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ static var_info _cm_vtab_pvsamv1[] = {
399399
{ SSC_INPUT, SSC_ARRAY, "mlm_IAM_c_cs_incAngle", "Spline IAM - Incidence angles", "deg", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
400400
{ SSC_INPUT, SSC_ARRAY, "mlm_IAM_c_cs_iamValue", "Spline IAM - IAM values", "-", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
401401
{ SSC_INPUT, SSC_NUMBER, "mlm_groundRelfectionFraction", "Ground reflection fraction", "-", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
402+
{ SSC_INPUT, SSC_NUMBER, "mlm_is_bifacial", "Modules are bifacial", "0/1", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
403+
{ SSC_INPUT, SSC_NUMBER, "mlm_bifacial_transmission_factor", "Bifacial transmission factor", "0-1", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
404+
{ SSC_INPUT, SSC_NUMBER, "mlm_bifaciality", "Bifaciality factor", "%", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
405+
{ SSC_INPUT, SSC_NUMBER, "mlm_bifacial_ground_clearance_height", "Module ground clearance height", "m", "", "Mermoud Lejeune Single Diode Model", "module_model=5", "", "" },
406+
402407

403408
// inverter model
404409
{ SSC_INPUT, SSC_NUMBER, "inverter_model", "Inverter model specifier", "", "0=cec,1=datasheet,2=partload,3=coefficientgenerator,4=PVYield", "Inverter", "*", "INTEGER,MIN=0,MAX=4", "" },
@@ -2997,6 +3002,13 @@ double cm_pvsamv1::module_eff(int mod_type)
29973002
eff = 100.0 * ((vmp * imp) / area) / 1000.0;
29983003
}
29993004
break;
3005+
case 5: // Mermoud Lejeune
3006+
{
3007+
double area = as_double("mlm_Length") * as_double("mlm_Width");
3008+
double vmp = as_double("mlm_V_mp_ref");
3009+
double imp = as_double("mlm_I_mp_ref");
3010+
eff = 100.0 * ((vmp * imp) / area) / 1000.0;
3011+
}
30003012
}
30013013

30023014
if (eff == 0.0) eff = -1;

0 commit comments

Comments
 (0)