8 - Electrical Mismatch Method#

Nonuniform rear-irradiance on bifacial PV systems can cause additional mismatch loss, which may not be appropriately captured in PV energy production estimates and software.


The analysis.py module in bifacial_radiance comes with functions to calculate power output, electrical mismatch, and some other irradiance calculations. This is the procedure used for this proceedings and submitted journals, which have much more detail on the procedure.

Ideally mismatch losses M should be calculated for the whole year, and then the mismatch loss factor to apply to Grear “Lrear” required by due diligence softwares can be calculated:


In this journal we will explore calculating mismatch loss M for a reduced set of hours. A procedure similar to that in Tutorial 3 will be used to generate various hourly irradiance measurements in the results folder, which the mismatch.py module will load and analyze. Analysis is done with PVMismatch, so this must be installed.


1. Run an hourly simulation
2. Do mismatch analysis on the results.

1. Run an hourly simulation#

This will generate the results over which we will perform the mismatch analysis. Here we are doing only 1 day to make this faster.

import bifacial_radiance
import os
from pathlib import Path

testfolder = str(Path().resolve().parent.parent / 'bifacial_radiance' / 'TEMP'/ 'Tutorial_08')
if not os.path.exists(testfolder):

simulationName = 'tutorial_8'
moduletype = "test-module"
albedo = 0.25
lat = 37.5
lon = -77.6

# Scene variables
nMods = 20
nRows = 7
hub_height = 1.5 # meters
gcr = 0.33

# Traking parameters
cumulativesky = False
limit_angle = 60
angledelta = 0.01
backtrack = True

#makeModule parameters
x = 1
y = 2
xgap = 0.01
zgap = 0.05
ygap = 0.0  # numpanels=1 anyways so it doesnt matter anyway
numpanels = 1
axisofrotationTorqueTube = True
diameter = 0.1
tubetype = 'Oct'
material = 'black'
tubeParams = {'diameter':diameter,

# Analysis parmaeters
startdate = '11_06_08'       # Options: mm_dd, mm_dd_HH, mm_dd_HHMM, YYYY-mm-dd_HHMM
enddate = '11_06_10'
sensorsy = 12

demo = bifacial_radiance.RadianceObj(simulationName, path=testfolder)
epwfile = demo.getEPW(lat,lon)
metdata = demo.readWeatherFile(epwfile, starttime=startdate, endtime=enddate)
mymodule = demo.makeModule(name=moduletype, x=x, y=y, xgap=xgap,
                           ygap = ygap, zgap=zgap, numpanels=numpanels, tubeParams=tubeParams)
pitch = mymodule.sceney/gcr
sceneDict = {'pitch':pitch,'hub_height':hub_height, 'nMods': nMods, 'nRows': nRows}
demo.set1axis(limit_angle = limit_angle, backtrack = backtrack, gcr = gcr, cumulativesky = cumulativesky)
demo.makeScene1axis(module=mymodule, sceneDict=sceneDict)
demo.analysis1axis(sensorsy = sensorsy);
path = C:\Users\sayala\Documents\GitHub\bifacial_radiance\bifacial_radiance\TEMP\Tutorial_08
Making path: images
Making path: objects
Making path: results
Making path: skies
Making path: EPWs
Making path: materials
Loading albedo, 1 value(s), 0.250 avg
1 nonzero albedo values.
Getting weather file: USA_VA_Richmond.724010_TMY2.epw
 ... OK!
8760 line in WeatherFile. Assuming this is a standard hourly WeatherFile for the year for purposes of saving Gencumulativesky temporary weather files in EPW folder.
Coercing year to 2021
Filtering dates
Saving file EPWs\metdata_temp.csv, # points: 8760
Calculating Sun position for Metdata that is right-labeled  with a delta of -30 mins. i.e. 12 is 11:30 sunpos

Module Name: test-module
Module test-module updated in module.json
Creating ~3 skyfiles.
Created 3 skyfiles in /skies/

Making ~3 .rad files for gendaylit 1-axis workflow (this takes a minute..)
3 Radfiles created in /objects/

Making 3 octfiles in root directory.
Created 1axis_2021-11-06_0800.oct
Created 1axis_2021-11-06_0900.oct
Created 1axis_2021-11-06_1000.oct
Linescan in process: 1axis_2021-11-06_0800_Front
Linescan in process: 1axis_2021-11-06_0800_Back
Saved: results\irr_1axis_2021-11-06_0800.csv
Index: 2021-11-06_0800. Wm2Front: 216.65623333333335. Wm2Back: 6.056324916666667
Linescan in process: 1axis_2021-11-06_0900_Front
Linescan in process: 1axis_2021-11-06_0900_Back
Saved: results\irr_1axis_2021-11-06_0900.csv
Index: 2021-11-06_0900. Wm2Front: 372.0084583333333. Wm2Back: 34.88220833333333
Linescan in process: 1axis_2021-11-06_1000_Front
Linescan in process: 1axis_2021-11-06_1000_Back
Saved: results\irr_1axis_2021-11-06_1000.csv
Index: 2021-11-06_1000. Wm2Front: 335.59078333333326. Wm2Back: 40.30060916666667
Saving a cumulative-results file in the main simulation folder.This adds up by sensor location the irradiance over all hours or configurations considered.
Warning: This file saving routine does not clean results, so if your setup has ygaps, or 2+modules or torque tubes, doing a deeper cleaning and working with the individual results files in the results folder is highly suggested.

Saving Cumulative results
Saved: cumulative_results_.csv

2. Do mismatch analysis on the results#

There are various things that we need to know about the module at this stage.

  • Orientation: If it was simulated in portrait or landscape orientation.

  • Number of cells in the module: options right now are 72 or 96

  • Bifaciality factor: this is how well the rear of the module performs compared to the front of the module, and is a spec usually found in the datasheet.

Also, if the number of sampling points (sensorsy) from the result files does not match the number of cells along the panel orientation, downsampling or upsamplinb will be peformed. For this example, the module is in portrait mode (y > x), so there will be 12 cells along the collector width (numcellsy), and that’s why we set sensorsy = 12 during the analysis above.

These are the re-sampling options. To downsample, we suggest sensorsy >> numcellsy (for example, we’ve tested sensorsy = 100,120 and 200) - Downsamping by Center - Find the center points of all the sensors passed - Downsampling by Average - averages irradiances that fall on what would consist on the cell - Upsample

[ ]:
resultfolder = os.path.join(testfolder, 'results')
writefiletitle = "Mismatch_Results.csv"

portraitorlandscape='portrait' # Options are 'portrait' or 'landscape'
bififactor=0.9 # Bifaciality factor DOES matter now, as the rear irradiance values will be multiplied by this factor.
numcells= 72# Options are 72 or 96 at the moment.
downsamplingmethod = 'byCenter' # Options are 'byCenter' or 'byAverage'.
bifacial_radiance.mismatch.analysisIrradianceandPowerMismatch(testfolder=resultfolder, writefiletitle=writefiletitle, portraitorlandscape=portraitorlandscape,
                                                              bififactor=bififactor, numcells=numcells)

print ("Your hourly mismatch values are now saved in the file above! :D")

We hope to add more content to this journal for next release so check back! Particularly how to use the Mad_fn to make the mismatch calculation faster, as per the proceedings and publication above!