def solve_MJ(EgBot, EgMid, EgTop): db_junction0 = Junction(kind='DB', T=T, Eg=EgBot, A=1, R_shunt=np.inf, n=3.5) db_junction1 = Junction(kind='DB', T=T, Eg=EgMid, A=1, R_shunt=np.inf, n=3.5) db_junction2 = Junction(kind='DB', T=T, Eg=EgTop, A=1, R_shunt=np.inf, n=3.5) my_solar_cell = SolarCell([db_junction2, db_junction1, db_junction0], T=T, R_series=0) solar_cell_solver(my_solar_cell, 'iv', user_options={'T_ambient': T, 'db_mode': 'top_hat', 'voltages': V, 'light_iv': True, 'internal_voltages': np.linspace(-6, 5, 1100), 'wavelength': wl, 'mpp': True, 'light_source': light}) return my_solar_cell
def test_layer_and_junction(qw_mat, b_mat, i_gaas, layer1, layer2, layer3): assert layer1.width == width1 assert layer1.role == role1 assert layer1.material == qw_mat assert layer1.geometry == wkt_box assert layer1.__dict__['new_property'] == 'new_property' assert layer2.width == width2 assert layer2.role == role2 assert layer2.material == b_mat assert layer2.geometry == wkt_box assert layer3.width == width3 assert layer3.role == role3 assert layer3.material == i_gaas assert layer3.geometry == wkt_box sn = random.uniform(1e6, 1e7) sp = random.uniform(1e6, 1e7) junction1 = Junction([layer1, layer2, layer3], sn=sn, sp=sp, T=t, kind='PDD') assert junction1.__len__() == 3 assert junction1.__dict__ == {'sn': sn, 'sp': sp, 'T': t, 'kind': 'PDD'} assert junction1[0] == layer1 assert junction1[1] == layer2 assert junction1[2] == layer3 tunnel1 = TunnelJunction([layer1, layer2, layer3], sn=sn, sp=sp, T=t, kind='PDD') assert tunnel1.__len__() == 3 assert tunnel1.__dict__ == { 'sn': sn, 'sp': sp, 'T': t, 'kind': 'PDD', 'R': 1e-16, 'pn': True } assert tunnel1[0] == layer1 assert tunnel1[1] == layer2 assert tunnel1[2] == layer3
def test_get_depletion_widths(): from solcore.analytic_solar_cells.depletion_approximation import get_depletion_widths from solcore.structure import Junction xi = np.power(10, np.random.uniform(-10, -6)) Vbi = np.random.uniform(0, 3) es = np.random.uniform(1, 20) * vacuum_permittivity Na = np.power(10, np.random.uniform(22, 25)) Nd = np.power(10, np.random.uniform(22, 25)) V = np.linspace(-6, 4, 20) V = np.where(V < Vbi - 0.001, V, Vbi - 0.001) test_junc = Junction() wn_e = (-xi + np.sqrt(xi**2 + 2. * es * (Vbi - V) / q * (1 / Na + 1 / Nd))) / (1 + Nd / Na) wp_e = (-xi + np.sqrt(xi**2 + 2. * es * (Vbi - V) / q * (1 / Na + 1 / Nd))) / (1 + Na / Nd) wn_r, wp_r = get_depletion_widths(test_junc, es, Vbi, V, Na, Nd, xi) assert wn_r == approx(wn_e) assert wp_r == approx(wp_e)
def test_process_junction_pn(): from solcore.analytic_solar_cells.depletion_approximation import identify_layers, identify_parameters from solcore import material from solcore.structure import Layer, Junction from solcore.state import State Na = np.power(10, np.random.uniform(22, 25)) Nd = np.power(10, np.random.uniform(23, 26)) options = State() options.T = np.random.uniform(250, 350) Lp = np.power(10, np.random.uniform(-9, -6)) # Diffusion length Ln = np.power(10, np.random.uniform(-9, -6)) # Diffusion length GaAs_n = material("GaAs")(Nd=Nd, hole_diffusion_length=Ln) GaAs_p = material("GaAs")(Na=Na, electron_diffusion_length=Lp) p_width = np.random.uniform(500, 1000)*1e-9 n_width = np.random.uniform(3000, 5000)*1e-9 test_junc = Junction([Layer(p_width, GaAs_p, role="emitter"), Layer(n_width, GaAs_n, role="base")]) id_top, id_bottom, pRegion, nRegion, iRegion, pn_or_np = identify_layers(test_junc) xn, xp, xi, sn, sp, ln, lp, dn, dp, Nd_c, Na_c, ni, es = identify_parameters(test_junc, options.T, pRegion, nRegion, iRegion) ni_expect = GaAs_n.ni assert [id_top, id_bottom] == approx([0, 1]) assert pn_or_np == 'pn' assert [xn, xp, xi, sn, sp, ln, lp, dn, dp, Nd_c, Na_c, ni, es] == approx([n_width, p_width, 0, 0, 0, Lp, Ln, GaAs_n.hole_mobility * kb * options.T / q, GaAs_p.electron_mobility * kb * options.T / q, Nd, Na, ni_expect, GaAs_n.permittivity])
def test_process_junction_set_in_junction(): from solcore.analytic_solar_cells.depletion_approximation import identify_layers, identify_parameters from solcore import material from solcore.structure import Layer, Junction from solcore.state import State options = State() options.T = np.random.uniform(250, 350) Lp = np.power(10, np.random.uniform(-9, -6)) # Diffusion length Ln = np.power(10, np.random.uniform(-9, -6)) # Diffusion length sn = np.power(10, np.random.uniform(0, 3)) sp = np.power(10, np.random.uniform(0, 3)) se = np.random.uniform(1, 20) * vacuum_permittivity GaAs_n = material("GaAs")() GaAs_p = material("GaAs")() GaAs_i = material("GaAs")() p_width = np.random.uniform(500, 1000) n_width = np.random.uniform(3000, 5000) i_width = np.random.uniform(100, 300) * 1e-9 mun = np.power(10, np.random.uniform(-5, 0)) mup = np.power(10, np.random.uniform(-5, 0)) Vbi = np.random.uniform(0, 3) test_junc = Junction([ Layer(p_width, GaAs_p, role="emitter"), Layer(i_width, GaAs_i, role="intrinsic"), Layer(n_width, GaAs_n, role="base") ], sn=sn, sp=sp, permittivity=se, ln=Ln, lp=Lp, mup=mup, mun=mun, Vbi=Vbi) id_top, id_bottom, pRegion, nRegion, iRegion, pn_or_np = identify_layers( test_junc) xn, xp, xi, sn_c, sp_c, ln, lp, dn, dp, Nd_c, Na_c, ni, es = identify_parameters( test_junc, options.T, pRegion, nRegion, iRegion) ni_expect = GaAs_n.ni assert [id_top, id_bottom] == approx([0, 2]) assert pn_or_np == 'pn' assert [xn, xp, xi, sn_c, sp_c, ln, lp, dn, dp, Nd_c, Na_c, ni, es] == approx([ n_width, p_width, i_width, sn, sp, Ln, Lp, mun * kb * options.T / q, mup * kb * options.T / q, 1, 1, ni_expect, se ])
def test_identify_layers_exceptions(): from solcore.analytic_solar_cells.depletion_approximation import identify_layers from solcore import material from solcore.structure import Layer, Junction Na = np.power(10, np.random.uniform(22, 25)) Nd = np.power(10, np.random.uniform(22, 25)) Lp = np.power(10, np.random.uniform(-9, -6)) # Diffusion length Ln = np.power(10, np.random.uniform(-9, -6)) # Diffusion length GaAs_n = material("GaAs")(Nd=Nd, hole_diffusion_length=Ln) GaAs_p = material("GaAs")(Na=Na, electron_diffusion_length=Lp) GaAs_i = material("GaAs")() Ge_n = material("Ge")(Nd=Nd, hole_diffusion_length=Ln) n_width = np.random.uniform(500, 1000) * 1e-9 p_width = np.random.uniform(3000, 5000) * 1e-9 i_width = np.random.uniform(300, 500) * 1e-9 test_junc = Junction([ Layer(n_width, GaAs_n, role="emitter"), Layer(p_width, GaAs_p, role="neither") ]) with raises(RuntimeError): identify_layers(test_junc) test_junc = Junction([ Layer(n_width, GaAs_n, role="emitter"), Layer(i_width, GaAs_i, role="intrinsic"), Layer(p_width, GaAs_p, role="nothing") ]) with raises(RuntimeError): identify_layers(test_junc) test_junc = Junction([ Layer(n_width, Ge_n, role="emitter"), Layer(p_width, GaAs_p, role="base") ]) with raises(AssertionError): identify_layers(test_junc)
def junction(nd_top, na_top, nd_bottom, na_bottom): from solcore.structure import Junction, Layer from solcore import si, material from solcore.solar_cell import SolarCell from solcore.constants import vacuum_permittivity from solcore.solar_cell_solver import prepare_solar_cell from solcore.optics import solve_beer_lambert Lp = np.power(10, np.random.uniform(-8, -6)) Ln = np.power(10, np.random.uniform(-8, -6)) AlInP = material("AlInP") InGaP = material("GaInP") window_material = AlInP(Al=0.52) top_cell_n_material = InGaP( In=0.48, Nd=nd_top, Na=na_top, hole_diffusion_length=Lp, electron_diffusion_length=Ln, ) top_cell_p_material = InGaP( In=0.48, Nd=nd_bottom, Na=na_bottom, hole_diffusion_length=Lp, electron_diffusion_length=Ln, ) rel_perm = np.random.uniform(1, 20) for mat in [top_cell_n_material, top_cell_p_material]: mat.permittivity = rel_perm * vacuum_permittivity n_width = np.random.uniform(500, 1000) * 1e-9 p_width = np.random.uniform(3000, 5000) * 1e-9 test_junc = SolarCell([ Junction( [ Layer(si("25nm"), material=window_material, role="window"), Layer(n_width, material=top_cell_n_material, role="emitter"), Layer(p_width, material=top_cell_p_material, role="base"), ], sn=1, sp=1, kind="DA", ) ]) options = da_options() options.light_source = da_light_source() prepare_solar_cell(test_junc, options) solve_beer_lambert(test_junc, options) return test_junc, options
def test_get_depletion_widths_set_in_junction(): from solcore.analytic_solar_cells.depletion_approximation import get_depletion_widths from solcore.structure import Junction wn = np.random.uniform(1, 100) wp = np.random.uniform(1, 100) test_junc = Junction(wn=wn, wp=wp) wn_r, wp_r = get_depletion_widths(test_junc, 0, 0, 0, 0, 0, 0) assert wn_r == approx(wn) assert wp_r == approx(wp)
def solve_MJ(EgBot, EgMid, EgTop): db_junction0 = Junction(kind="DB", T=T, Eg=EgBot, A=1, R_shunt=np.inf, n=3.5) db_junction1 = Junction(kind="DB", T=T, Eg=EgMid, A=1, R_shunt=np.inf, n=3.5) db_junction2 = Junction(kind="DB", T=T, Eg=EgTop, A=1, R_shunt=np.inf, n=3.5) my_solar_cell = SolarCell([db_junction2, db_junction1, db_junction0], T=T, R_series=0) solar_cell_solver( my_solar_cell, "iv", user_options={ "T_ambient": T, "db_mode": "top_hat", "voltages": V, "light_iv": True, "internal_voltages": np.linspace(-6, 5, 1100), "wavelength": wl, "mpp": True, "light_source": light, }, ) return my_solar_cell
def prepare_test_cell(): from solcore import material, si from solcore.structure import Junction, Layer, TunnelJunction from solcore.solar_cell import SolarCell GaAs = material("GaAs")() MgF2 = material("MgF2")() TiO2 = material("TiO2")() Ge = material("Ge")() widths = np.random.rand(9) * 200 solar_cell = SolarCell([ Layer(si(widths[0], "nm"), material=MgF2), Layer(si(widths[1], "nm"), material=TiO2), Junction( [ Layer(si(widths[2], "nm"), material=GaAs, role="window"), Layer(si(widths[3], "nm"), material=GaAs, role="emitter"), Layer(si(widths[4], "nm"), material=GaAs, role="base"), ], kind="DA", ), TunnelJunction([ Layer(si(widths[5], "nm"), material=GaAs), Layer(si(widths[6], "nm"), material=GaAs), ]), Junction( [ Layer(si(widths[7], "nm"), material=Ge, role="emitter"), Layer(si(widths[8], "nm"), material=Ge, role="base"), ], kind="PDD", ), ]) return solar_cell, widths
def default_GaAs(T): # We create the other materials we need for the device window = material('AlGaAs')(T=T, Na=5e24, Al=0.8) p_GaAs = material('GaAs')(T=T, Na=1e24) n_GaAs = material('GaAs')(T=T, Nd=8e22) bsf = material('GaAs')(T=T, Nd=2e24) output = Junction([ Layer(width=si('30nm'), material=window, role="Window"), Layer(width=si('150nm'), material=p_GaAs, role="Emitter"), Layer(width=si('3000nm'), material=n_GaAs, role="Base"), Layer(width=si('200nm'), material=bsf, role="BSF") ], sn=1e6, sp=1e6, T=T, kind='PDD') return output
def AlGaAs(T): # We create the other materials we need for the device window = material("AlGaAs")(T=T, Na=5e24, Al=0.8) p_AlGaAs = material("AlGaAs")(T=T, Na=1e24, Al=0.4) n_AlGaAs = material("AlGaAs")(T=T, Nd=8e22, Al=0.4) bsf = material("AlGaAs")(T=T, Nd=2e24, Al=0.6) output = Junction( [ Layer(width=si("30nm"), material=window, role="Window"), Layer(width=si("150nm"), material=p_AlGaAs, role="Emitter"), Layer(width=si("1000nm"), material=n_AlGaAs, role="Base"), Layer(width=si("200nm"), material=bsf, role="BSF"), ], sn=1e6, sp=1e6, T=T, kind="PDD", ) return output
def test_get_depletion_widths_onesided(): from solcore.analytic_solar_cells.depletion_approximation import get_depletion_widths from solcore.structure import Junction xi = np.power(10, np.random.uniform(-10, -6)) Vbi = np.random.uniform(0, 3) es = np.random.uniform(1, 20) * vacuum_permittivity Na = np.power(10, np.random.uniform(22, 25)) Nd = np.power(10, np.random.uniform(22, 25)) V = np.linspace(-6, 4, 20) V = np.where(V < Vbi - 0.001, V, Vbi - 0.001) test_junc = Junction(depletion_approximation="one-sided abrupt") wn_e = np.sqrt(2 * es * (Vbi - V) / (q * Nd)) wp_e = np.sqrt(2 * es * (Vbi - V) / (q * Na)) wn_r, wp_r = get_depletion_widths(test_junc, es, Vbi, V, Na, Nd, xi) assert wn_r == approx(wn_e) assert wp_r == approx(wp_e)
def AlGaAs(): from solcore import material from solcore.structure import Layer, Junction from solcore import si T = 298 # We create the other materials we need for the device window = material("AlGaAs")(T=T, Na=5e24, Al=0.8) p_AlGaAs = material("AlGaAs")(T=T, Na=1e24, Al=0.4) n_AlGaAs = material("AlGaAs")(T=T, Nd=8e22, Al=0.4) bsf = material("AlGaAs")(T=T, Nd=2e24, Al=0.6) return Junction( [ Layer(width=si("30nm"), material=window, role="Window"), Layer(width=si("150nm"), material=p_AlGaAs, role="Emitter"), Layer(width=si("1000nm"), material=n_AlGaAs, role="Base"), Layer(width=si("200nm"), material=bsf, role="BSF"), ], sn=1e6, sp=1e6, T=T, kind="PDD", )
Layer(si(79, 'nm'), SiN, geometry=[{ 'type': 'circle', 'mat': Ag, 'center': (0, 0), 'radius': 110, 'angle': 0 }]) ] solar_cell = SolarCell([ Junction([ Layer(material=window_material, width=si('19nm'), role='window'), Layer(material=top_cell_p_material, width=si('43.5nm'), kind='emitter'), Layer(material=top_cell_n_material, width=si('43.5nm'), kind='base'), Layer(material=bsf_material, width=si('18nm')) ], kind='PDD') ] + grating1 + grating2, substrate=Ag) solar_cell_solver(solar_cell, 'qe', user_options=options) #solar_cell_solver(solar_cell, 'iv', user_options=options) EQE_data = np.loadtxt('data/V2A_9_EQE.dat', skiprows=129) solar_cell_optical = SolarCell([ Layer(material=InGaP_nk, width=si('19nm')), Layer(material=GaAs_nk, width=si('43.5nm')),
# We add some other properties to the materials, assumed the same in all cases, for simplicity. # If different, we should have added them above in the definition of the materials. for mat in all_materials: mat.hole_mobility = 3.4e-3 mat.electron_mobility = 5e-2 ARC = [Layer(si('80nm'), material=ARC1), Layer(si('33nm'), material=ARC2)] top_junction = [ Junction([ Layer(si("18nm"), material=top_window_material, role='window'), Layer(si("100nm"), material=top_cell_n_material, role='emitter'), Layer(si("891.248nm"), material=top_cell_p_material, role='base'), Layer(si("111.445nm"), material=top_cell_TJ_material, role='TJ') ], sn=1, sp=1, kind='DA') ] middle_junction = [ Junction([ Layer(si("18nm"), material=mid_window_material, role='window'), Layer(si("100nm"), material=mid_cell_n_material, role='emitter'), Layer(si("1632.091nm"), material=mid_cell_p_material, role='base'), Layer(si("10nm"), material=mid_BSF_material, role='BSF'), Layer(si("91.084nm"), material=mid_cell_TJ_material, role='TJ') ], sn=1, sp=1,
# Height of the metal fingers (m) h = 2.2e-6 # Contact resistance (Ohm m2) Rcontact = 3e-10 # Resistivity metal fingers (Ohm m) Rline = 2e-8 # Bias (V) vini = 0 vfin = 1.3 step = 0.01 T = 298 db_junction = Junction(kind='2D', T=T, reff=1, jref=300, Eg=0.66, A=1, R_sheet_top=100, R_sheet_bot=1e-16, R_shunt=1e16, n=3.5) db_junction2 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.4, A=1, R_sheet_top=100, R_sheet_bot=1e-16, R_shunt=1e16, n=3.5) db_junction3 = Junction(kind='2D', T=T, reff=0.5, jref=300, Eg=1.8, A=1, R_sheet_top=100, R_sheet_bot=100, R_shunt=1e16, n=3.5) # For a single junction, this will have >28800 nodes and for the full 3J it will be >86400, so it is worth to # exploit symmetries whenever possible. A smaller number of nodes also makes the solver more robust. my_solar_cell = SolarCell([db_junction2], T=T) wl = np.linspace(350, 2000, 301) * 1e-9 light_source = LightSource(source_type='standard', version='AM1.5g', x=wl, output_units='photon_flux_per_m', concentration=100) options = {'light_iv': True, 'wavelength': wl, 'light_source': light_source, 'optics_method': 'BL'}
# We add some other properties to the materials, assumed the same in all cases, for simplicity. # If different, we should have added them above in the definition of the materials. for mat in all_materials: mat.hole_mobility = 5e-2 mat.electron_mobility = 3.4e-3 mat.hole_mobility = 3.4e-3 mat.electron_mobility = 5e-2 mat.relative_permittivity = 9 # And, finally, we put everything together, adding also the surface recombination velocities. We also add some shading # due to the metallisation of the cell = 8%, and indicate it has an area of 0.7x0.7 mm2 (converted to m2) solar_cell = SolarCell( [ Junction([Layer(si("25nm"), material=window_material, role='window'), Layer(si("100nm"), material=top_cell_n_material, role='emitter'), Layer(si("600nm"), material=top_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), Junction([Layer(si("200nm"), material=mid_cell_n_material, role='emitter'), Layer(si("3000nm"), material=mid_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), Junction([Layer(si("400nm"), material=bot_cell_n_material, role='emitter'), Layer(si("100um"), material=bot_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), ], reflectivity=ref, shading=0.08, cell_area=0.7 * 0.7 / 1e4) wl = np.linspace(300, 1800, 700) * 1e-9 solar_cell_solver(solar_cell, 'qe', user_options={'wavelength': wl}) plt.figure(1) plt.plot(wl * 1e9, solar_cell[0].eqe(wl) * 100, 'b', label='GaInP') plt.plot(wl * 1e9, solar_cell[1].eqe(wl) * 100, 'g', label='InGaAs')
def run_solar_cell_model(task, model): """ :param model: :return: a Solar cell object """ # First, we take care of the options # ---------------------------------- options = copy.copy(model['Global']) options.update(model['Electrical']) options.update(model['Optical']) T = float(options['T']) # We have to validate the options and check they have the correct format and type array_based_options = ['voltages', 'internal_voltages', 'position', 'wavelength'] float_options = ['T', 'T_ambient'] bool_options = ['mpp', 'light_iv', 'radiative_coupling'] try: for p in options: # For the options that should be arrays, we create the arrays. The wavelength need ot be converted to meters if p in array_based_options: c = options[p].split(', ') ini = float(c[0]) end = float(c[1]) num = int(c[2]) options[p] = np.linspace(ini, end, num) * 1e-9 ** (p == 'wavelength') # For the options that need to be floats elif p in float_options: options[p] = float(options[p]) elif p in bool_options: options[p] = options[p].lower() in ['true', 'yes', 't', 1] except Exception as err: print('ERROR parsing the solver options: Option format not recognised') print(err) raise # Now we create the layers and junctions to the solar cell object # --------------------------------------------------------------- sc_data = model['Solar cell'] all_layers = [] all_materials = [] for i in sc_data['structure']: current_element = sc_data[i[0]] # First the individual layers if 'Layer' in current_element['type']: layer_properties = {} width = current_element['width'] * 1e-9 # Set the composition and get the properties, converting them to the correct units for key in current_element['options']: if key in ['element', 'x']: layer_properties[current_element['options']['element']] = current_element['options']['x'] else: layer_properties[key] = current_element['options'][key] * conversion[key] all_materials.append(material(current_element['material'])(T=T, **layer_properties)) all_layers.append(Layer(width, all_materials[-1], role=current_element['name'])) continue # Unless it is an individual layer, we have junctions properties = {} for p in properties_junctions[current_element['type']]: properties[p] = default_junction_properties[p] properties.update(**current_element['options']) kind = current_element['type'].split('-')[-1] if 'TJ' in current_element['type']: new_junction = TunnelJunction(name=current_element['name'], kind=kind, T=T, **properties) else: new_junction = Junction(name=current_element['name'], kind=kind, T=T, **properties) # Now we add the layers, if any for l in i[1:]: current_child = sc_data[l] width = current_child['width'] * 1e-9 layer_properties = {} # Set the composition and get the properties, converting them to the correct units for key in current_child['options']: if key in ['element', 'x']: layer_properties[current_child['options']['element']] = current_child['options']['x'] else: layer_properties[key] = current_child['options'][key] * conversion[key] all_materials.append(material(current_child['material'])(T=T, **layer_properties)) new_junction.append(Layer(width, all_materials[-1], role=current_child['name'])) all_layers.append(new_junction) # Now we have to create the solar cell # ------------------------------------ reflectivity = create_reflectivity(sc_data['reflectivity']) if sc_data['reflectivity'] != '' else None try: substrate = material(sc_data['substrate'])(T=T, **{sc_data['element']: sc_data['composition']}) except KeyError: substrate = material(sc_data['substrate'])(T=T) sc = SolarCell(layers=all_layers, name=sc_data['name'], substrate=substrate, T=T, cell_area=sc_data['size'], shading=sc_data['shading'], R_series=sc_data['r_series'], reflectivity=reflectivity) # With all said and done, we can run the solver # --------------------------------------------- solar_cell_solver(sc, task, user_options=options) print('Done!') return sc
def make_cell(self, x): #x[0]: total InGaP thickness #x[1]: total InGaAs thickness #x[2]: total SiGeSn thickness #x[3]: total Ge thickness #x[4]: InGaP n thickness #x[5]: InGaAs n thickness #x[6]: SiGeSn n thickness #x[7]: Ge n thickness e_charge = si('1eV') # materials SiGeSn = material('SiGeSn') GaAs = material('GaAs') InGaP = material('GaInP') Ge = material('Ge') MgF2 = material('MgF2')() Ta2O5 = material('410', nk_db=True)() AlInP = material("AlInP") window_material = AlInP(Al=0.52) GaInP_mobility_h = 0.03 # GaInP_lifetime_h = 1e-8 GaInP_D_h = GaInP_mobility_h * kb * 300 / e_charge GaInP_L_h = np.sqrt(GaInP_D_h * GaInP_lifetime_h) GaInP_mobility_e = 0.015 GaInP_lifetime_e = 1e-8 GaInP_D_e = GaInP_mobility_e * kb * 300 / e_charge GaInP_L_e = np.sqrt(GaInP_D_e * GaInP_lifetime_e) top_cell_n_material = InGaP(In=0.5, Nd=si("2e18cm-3"), hole_diffusion_length=GaInP_L_h, relative_permittivity=11.75, hole_mobility=GaInP_mobility_h) top_cell_p_material = InGaP(In=0.5, Na=si("2e17cm-3"), electron_diffusion_length=GaInP_L_e, relative_permittivity=11.75, electron_mobility=GaInP_mobility_e) # MID CELL - GaAs GaAs_mobility_h = 0.85 # GaAs_lifetime_h = 1e-8 GaAs_D_h = GaAs_mobility_h * kb * 300 / e_charge GaAs_L_h = np.sqrt(GaAs_D_h * GaAs_lifetime_h) GaAs_mobility_e = 0.08 GaAs_lifetime_e = 1e-8 GaAs_D_e = GaAs_mobility_e * kb * 300 / e_charge GaAs_L_e = np.sqrt(GaAs_D_e * GaAs_lifetime_e) mid_cell_n_material = GaAs(Nd=si("1e18cm-3"), hole_diffusion_length=GaAs_L_h, relative_permittivity=13.1, hole_mobility=GaAs_mobility_h) mid_cell_p_material = GaAs(Na=si("1e17cm-3"), electron_diffusion_length=GaAs_L_e, relative_permittivity=13.1, electron_mobility=GaAs_mobility_e) SiGeSn.band_gap = si('0.77eV') # from PL measurement SiGeSn_L_h = si('0.35um') SiGeSn_L_e = si('5um') SiGeSn_lifetime_e = 1e-6 SiGeSn_lifetime_h = 1e-6 SiGeSn_mobility_h = SiGeSn_L_h**2 * e_charge / (SiGeSn_lifetime_h * kb * 300) SiGeSn_mobility_e = SiGeSn_L_e**2 * e_charge / (SiGeSn_lifetime_e * kb * 300) pen_cell_n_material = SiGeSn(Nd=si("1e18cm-3"), hole_diffusion_length=SiGeSn_L_h, relative_permittivity=16, hole_mobility=SiGeSn_mobility_h) pen_cell_p_material = SiGeSn(Na=si("1e17cm-3"), electron_diffusion_length=SiGeSn_L_e, relative_permittivity=16, electron_mobility=SiGeSn_mobility_e) # Ge_mobility_h = 0.38 # Ge_lifetime_h = 1e-6 # Ge_D_h = Ge_mobility_h*kb*300/e_charge # Ge_L_h = np.sqrt(Ge_D_h*Ge_lifetime_h) Ge_L_h = si('500nm') Ge_mobility_h = Ge_L_h**2 * e_charge / (Ge_lifetime_h * kb * 300) Ge_mobility_e = 0.18 Ge_lifetime_e = 1e-6 Ge_D_e = Ge_mobility_e * kb * 300 / e_charge Ge_L_e = np.sqrt(Ge_D_e * Ge_lifetime_e) bot_cell_n_material = Ge(Nd=si("2e18cm-3"), hole_diffusion_length=Ge_L_h, relative_permittivity=16, hole_mobility=Ge_mobility_h) bot_cell_p_material = Ge(Na=si("1e17cm-3"), electron_diffusion_length=Ge_L_e, relative_permittivity=16, electron_mobility=Ge_mobility_e) # And, finally, we put everything together, adding also the surface recombination velocities. We also add some shading # due to the metallisation of the cell = 8%, and indicate it has an area of 0.7x0.7 mm2 (converted to m2) solar_cell = SolarCell( [ # Layer(si('110nm'), material = MgF2), Layer(si('55nm'), material = ZnS), Layer(si(self.ARC[0], 'nm'), material=MgF2), Layer(si(self.ARC[1], 'nm'), material=Ta2O5), Junction([ Layer( si(25, 'nm'), material=window_material, role='window'), Layer(si(x[4], 'nm'), material=top_cell_n_material, role='emitter'), Layer(si(x[0] - x[4], 'nm'), material=top_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), Junction([ Layer(si(x[5], 'nm'), material=mid_cell_n_material, role='emitter'), Layer(si(x[1] - x[5], 'nm'), material=mid_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), Junction([ Layer(si(x[6], 'nm'), material=pen_cell_n_material, role='emitter'), Layer(si(x[2] - x[6], 'nm'), material=pen_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), Junction([ Layer(si(x[7], 'nm'), material=bot_cell_n_material, role='emitter'), Layer(si(x[3] - x[7], 'nm'), material=bot_cell_p_material, role='base'), ], sn=1, sp=1, kind='DA'), ], shading=0.0, substrate=bot_cell_n_material) return solar_cell
n_GaAs = material('GaAs')(T=T, Nd=si('2e17cm-3')) # for the GaAs cell base AlAs, GaAs = material('AlAs')(T=T), material('GaAs')(T=T) # for the DBR SiO2 = material('SiO2', sopra=True)(T=T) # for the spacer layer TiO2 = material('TiO2', sopra=True)(T=T) # for the nanoparticles # some parameters for the QE solver for mat in [n_GaAs, p_GaAs]: mat.hole_mobility, mat.electron_mobility, mat.permittivity = 3.4e-3, 5e-2, 9 n_GaAs.hole_diffusion_length, p_GaAs.electron_diffusion_length = si( "500nm"), si("5um") # Define the different parts of the structure we will use. For the GaAs junction, we use the depletion approximation GaAs_junction = [ Junction([ Layer(width=si('100nm'), material=p_GaAs, role="emitter"), Layer(width=si('400nm'), material=n_GaAs, role="base") ], T=T, kind='DA') ] # this creates 10 repetitions of the AlAs and GaAs layers, to make the DBR structure DBR = 10 * [ Layer(width=si("73nm"), material=AlAs), Layer(width=si("60nm"), material=GaAs) ] # The layer with nanoparticles NP_layer = [ Layer(si('50nm'), Air, geometry=[{
Vin = np.linspace(-6, 2, 600) V = np.linspace(-1.5, 4, 500) wl = np.linspace(350, 2000, 301) * 1e-9 light_source = LightSource(source_type='standard', version='AM1.5g', x=wl, output_units='photon_flux_per_m', concentration=1) color = ['b', 'g', 'r'] label = ['Top', 'Mid', 'Bot'] fig, ax = plt.subplots(1, 2, sharey='all', figsize=(7, 4.5)) for k, rad in enumerate([False, True]): # Input data for the 2D kind of junction db_junction = Junction(kind='2D', T=T, reff=0.3, jref=300, Eg=0.66, A=1, R_shunt=np.inf, n=3.5) db_junction2 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.4, A=1, R_shunt=np.inf, n=3.5) db_junction3 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.8, A=1, R_shunt=np.inf, n=3.5) my_solar_cell = SolarCell([db_junction3, db_junction2, db_junction], T=T, R_series=0) solar_cell_solver(my_solar_cell, 'iv', user_options={'T_ambient': T, 'voltages': V, 'light_iv': True, 'wavelength': wl, 'light_source': light_source, 'radiative_coupling': rad, 'mpp': True, 'internal_voltages': Vin}) # This is the total junction IV ax[k].plot(my_solar_cell.iv['IV'][0], my_solar_cell.iv['IV'][1], marker='o', color=colours("Black"), ls='-', markerfacecolor='none', markeredgecolor=colours("Black")) # This is the junciton IV when it is in the MJ device, including coupling if it is enabled.
import numpy as np from solcore.solar_cell import SolarCell from solcore.light_source import LightSource from solcore.spice.pv_module_solver import solve_pv_module import matplotlib.pyplot as plt from solcore.structure import Junction T = 298 # First we define the properties of the MJ solar cell that the solar module is made of. We use junctions of kind 2-diode db_junction = Junction(kind='2D', T=T, reff=1, jref=300, Eg=0.66, A=1, R_series=0.00236, R_shunt=1e14, n=3.5) db_junction2 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.4, A=1, R_series=0.00012, R_shunt=1e14, n=3.5) db_junction3 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.9, A=1, R_series=8.0e-5, R_shunt=1e14, n=3.5) my_solar_cell = SolarCell([db_junction3, db_junction2, db_junction], T=T, R_series=0.0, area=0.1) wl = np.linspace(350, 2000, 301) * 1e-9 light_source = LightSource(source_type='standard', version='AM1.5g', x=wl, output_units='photon_flux_per_m', concentration=1) options = {'light_iv': True, 'wavelength': wl, 'light_source': light_source} # After defining the individual solar cell, we solve the module IV characteristics adding some dispersion in the values of the short circuit currents. voltage, current, all_Isc_values, raw_data = solve_pv_module(my_solar_cell, options, jscSigma=0.02) plt.figure(1) plt.subplot(311) plt.title('Histogram of sub-cell photocurrents') plt.ylabel('InGaP')
# We solve the quantum properties of the QW, leaving the default values of all parameters QW_list = PDD.SolveQWproperties(QW, wavelengths=wl) # Materials for the BOTTOM junction window_bottom = material('GaInP')(T=T, Nd=5e24, In=0.49) n_GaAs = material('GaAs')(T=T, Nd=1e24) p_GaAs = material('GaAs')(T=T, Na=8e22) bsf_bottom = material('GaInP')(T=T, Na=5e24, In=0.49) # If you want to test the code without QWs, to make ti a bit faster, comment the line with QW_list GaAs_junction = Junction([ Layer(width=10e-9, material=window_bottom, role="Window"), Layer(width=150e-9, material=n_GaAs, role="Emitter") ] + QW_list + [ Layer(width=2000e-9, material=p_GaAs, role="Base"), Layer(width=200e-9, material=bsf_bottom, role="BSF") ], sn=1e6, sp=1e6, T=T, kind='PDD') # Materials for the TOP junction window_top = material('AlInP')(T=T, Nd=5e23, Al=0.53, electron_mobility=0.01, hole_mobility=7e-4) n_GaInP = material('GaInP')(T=T, Nd=5e23, In=0.49) p_GaInP = material('GaInP')(T=T, Na=8e22, In=0.49) bsf_top = material('AlInP')(T=T,
# Materials for the BOTTOM junction window_bottom = material("GaInP")(T=T, Nd=5e24, In=0.49) n_GaAs = material("GaAs")(T=T, Nd=1e24) p_GaAs = material("GaAs")(T=T, Na=8e22) bsf_bottom = material("GaInP")(T=T, Na=5e24, In=0.49) # If you want to test the code without QWs, to make ti a bit faster, comment the line # with QW_list GaAs_junction = Junction( [ Layer(width=10e-9, material=window_bottom, role="Window"), Layer(width=150e-9, material=n_GaAs, role="Emitter"), ] # Comment the following line to remove the QWs + QW_list + [ Layer(width=2000e-9, material=p_GaAs, role="Base"), Layer(width=200e-9, material=bsf_bottom, role="BSF"), ], sn=1e6, sp=1e6, T=T, kind="PDD", ) # Materials for the TOP junction window_top = material("AlInP")(T=T, Nd=5e23, Al=0.53, electron_mobility=0.01, hole_mobility=7e-4) n_GaInP = material("GaInP")(T=T, Nd=5e23, In=0.49)