def test_series_connected_mj_cells(self): """ Test three series-connected triple-junction cells. We break them down into nine series-connected subcells and perform ```solve_series_connected_ivs()``` :return: """ sq1_cell = SQCell(eg=1.87, cell_T=300, plug_in_term=rev_diode) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq3_cell = SQCell(eg=1.0, cell_T=300, plug_in_term=rev_diode) tj_cell = MJCell([sq1_cell, sq2_cell, sq3_cell]) tj_cell.set_input_spectrum(load_astm(("AM1.5d"))) # Set up the MJCell() first. The purpose is only for calculating the transmitted spectrum # and the photocurrent of each subcell. We don't use the MJCell.get_j_from_v() to solve the I-V connected_cells = [] number_of_mjcell = 3 multi = np.array([0, 0.25, 0.5]) for i in range(number_of_mjcell): # Need copy.deepcopy to also copy the subcells c_tj_cell = copy.deepcopy(tj_cell) # multi = np.random.random() * 0.5 c_tj_cell.set_input_spectrum(load_astm("AM1.5d") * (1 + multi[i])) connected_cells.append(c_tj_cell) # Extract each subcell, make them into series-connected cells # Connect all the subcells in series iv_funcs = [] for mj_cells in connected_cells: for subcell in mj_cells.subcell: iv_funcs.append(subcell.get_j_from_v) reverse_plot = True if reverse_plot: rev_fac = -1 else: rev_fac =1 from pypvcell.fom import isc for idx, cell in enumerate(connected_cells): v, i = cell.get_iv() print(isc(v, i * rev_fac)) plt.plot(v, i * rev_fac, label="MJ cell {}".format(idx + 1)) iv_pair = solve_series_connected_ivs(iv_funcs, vmin=-1, vmax=3.5, vnum=300) plt.plot(iv_pair[0], iv_pair[1] * rev_fac, '.-', label="Connected I-V") plt.ylim(sorted([-300 * rev_fac, 0])) plt.xlim([-10, 12]) plt.xlabel("voltage (V)") plt.ylabel("current (A/m^2)") plt.legend() plt.savefig("./tests_output/Mjx3_demo.png", dpi=300) plt.show()
def test_diode_solver(self): hp1 = HighPSQCell(1.42, cell_T=300) hp1.set_input_spectrum(load_astm()) hp2 = HighPSQCell(1.42, cell_T=300) hp2.set_input_spectrum(load_astm()) hp3 = HighPSQCell(1.42, cell_T=300) hp3.set_input_spectrum(load_astm()) ref_hp = HighPSQCell(1.42, cell_T=300) ref_hp.set_input_spectrum(load_astm()) d1 = DiodeSeriesConnect([hp1, hp2, hp3]) test_v = 1.0 j1 = d1.get_j_from_v(test_v) j2 = ref_hp.get_j_from_v(test_v / 3.0) # by circuit law, j1 should equal to j2 self.assertTrue(np.isclose(j1, j2)) # extend the examination range test_v = np.linspace(-1, 1, 10) j1 = d1.get_j_from_v(test_v) j2 = ref_hp.get_j_from_v(test_v / 3.0) self.assertTrue(np.allclose(j1, j2))
def test_parallel_connected_mj_cells_2(self): """ Try connecting two strings of cells. All are Eg=1.42 SQCell. Each string has five cells. One string has a cell has only 0.5 sun. :return: """ normal_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) normal_cell.set_input_spectrum(load_astm("AM1.5d")) low_current_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) low_current_cell.set_input_spectrum(load_astm("AM1.5d") * 0.5) # A trick is used here to configure MJCell. The MJCell is not illuminated. # But each of the subcell is illuminated individually. tj_cell_1 = MJCell([copy.deepcopy(normal_cell) for i in range(4)] + [copy.deepcopy(low_current_cell)]) tj_cell_2 = MJCell([copy.deepcopy(normal_cell) for i in range(5)]) iv_funcs = [tj_cell_1.get_j_from_v, tj_cell_2.get_j_from_v] parallel_v, parallel_i = solve_parallel_connected_ivs(iv_funcs, vmin=-2, vmax=6, vnum=30) volt = np.linspace(-2, 6, num=30) curr_1 = tj_cell_1.get_j_from_v(volt) curr_2 = tj_cell_2.get_j_from_v(volt) plt.plot(volt, curr_1, '.-', label="string 1") plt.plot(volt, curr_2, '.-', label="string 2") plt.plot(parallel_v, parallel_i, '.-', label="parallel-connected string") plt.ylim([-600, 0]) plt.legend() plt.show()
def no_reverse_diode(): sq1_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=None) sq1_cell.set_input_spectrum(load_astm("AM1.5d") * 0.5) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=None) sq2_cell.set_input_spectrum(load_astm("AM1.5d")) sq3_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=None) sq3_cell.set_input_spectrum(load_astm("AM1.5d") * 1.1) iv_funcs = [ sq1_cell.get_j_from_v, sq2_cell.get_j_from_v, sq3_cell.get_j_from_v ] volt = np.linspace(-1, 2, num=300) plt.plot(volt, sq1_cell.get_j_from_v(volt), '.-', label="cell 1") plt.plot(volt, sq2_cell.get_j_from_v(volt), '.-', label="cell 2") plt.plot(volt, sq3_cell.get_j_from_v(volt), '.-', label="cell 3") plt.ylim([-350, 0]) plt.xlim([-1.5, 4]) plt.xlabel("voltage (V)") plt.ylabel("current (A/m^2)") plt.legend() plt.savefig("./figs/no_rev_diode_iv.png", dpi=300) plt.savefig("./figs/no_rev_diode_iv.pdf") plt.show() plt.close() plt.figure() current_to_solve = sq1_cell.get_j_from_v(volt) current_to_solve = np.unique(current_to_solve) # plt.plot(volt, sq1_cell.get_j_from_v(volt),'.-',label="cell 1") sum_v = np.zeros_like(current_to_solve) for idx, iv_func in enumerate(iv_funcs[0:]): v, i = solve_v_from_j_by_bracket_root_finding(iv_func, current_to_solve, -3, 5, bisect) sum_v += v plt.plot(v, i, '.-', label="solved cell {}".format(idx + 1)) # plot summed up the voltages plt.plot(sum_v, current_to_solve, '.-', label="connected cell") plt.ylim([-350, 0]) plt.xlim([-1.5, 4]) plt.xlabel("voltage (V)") plt.ylabel("current (A/m^2)") plt.legend() plt.savefig("./figs/no_rev_diode_iv_solved.png", dpi=300) plt.savefig("./figs/no_rev_diode_iv_solved.pdf") plt.show()
def test_two_connected_mj_cells(self): """ Test three series-connected triple-junction cells. We use MJCells.get_j_from_v() as the iv_func of the bracket-based root-finding solver. Warning: this is slow. :return: """ sq1_cell = SQCell(eg=1.87, cell_T=300, plug_in_term=rev_diode) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq3_cell = SQCell(eg=1.0, cell_T=300, plug_in_term=rev_diode) tj_cell = MJCell([sq1_cell, sq2_cell, sq3_cell]) tj_cell.set_input_spectrum(load_astm(("AM1.5d"))) tj_cell_1 = copy.deepcopy(tj_cell) tj_cell_2 = copy.deepcopy(tj_cell) iv_funcs = [tj_cell_1.get_j_from_v, tj_cell_2.get_j_from_v] # solved_v,solved_i=solve_series_connected_ivs(iv_funcs, vmin=-2, vmax=3, vnum=10) volt_range = np.linspace(-1, 4, num=25) curr_range = tj_cell_1.get_j_from_v(volt_range) from scipy.optimize import brentq solved_v, solved_i = solve_v_from_j_by_bracket_root_finding(iv_funcs[0], curr_range, -5, 5, brentq) plt.plot(solved_v, solved_i, '.-') plt.ylim([-300, 0]) plt.show()
def test_dbcell2(self): qe_val = 0.8 ill = load_astm("AM1.5g") gaas_qe = gen_step_qe(1.42, qe_val) gaas_db = DBCell(qe=gaas_qe, rad_eta=1, T=300) gaas_db.set_input_spectrum(ill) trans_sp = gaas_db.get_transmit_spectrum() # Compare the expected and transmitted spectrum x = np.linspace(1.5, 2, num=10) trans = trans_sp.get_interp_spectrum(x, to_x_unit='eV') orig = ill.get_interp_spectrum(x, to_x_unit='eV') * (1 - qe_val) cp = np.allclose(trans[1, :], orig[1, :]) self.assertTrue(cp)
def test_mj_j_from_v(self): """ Test MJCell.get_j_from_v() :return: """ sq1_cell = SQCell(eg=1.87, cell_T=300, plug_in_term=rev_diode) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq3_cell = SQCell(eg=1.0, cell_T=300, plug_in_term=rev_diode) tj_cell = MJCell([sq1_cell, sq2_cell, sq3_cell]) tj_cell.set_input_spectrum(load_astm(("AM1.5d"))) solved_mj_v, solved_mj_i = tj_cell.get_iv() volt = np.linspace(2.5, 5, num=300) solved_current = tj_cell.get_j_from_v(volt, max_iter=3) interped_i = np.interp(volt, solved_mj_v, solved_mj_i) print(solved_current - interped_i) plt.plot(volt, interped_i, '.-') plt.plot(solved_mj_v, solved_mj_i, '.-') plt.plot(volt, solved_current, '.-', label='get_j_from_v', alpha=0.3) plt.ylim([-200, 0]) plt.legend() plt.show()
def test_dbcell(self): gaas_qe = gen_step_qe(1.42, 1) gaas_db = DBCell(qe=gaas_qe, rad_eta=1, T=300) gaas_db.set_input_spectrum(load_astm("AM1.5g")) gaas_db_eta = gaas_db.get_eta() sq_gaas = SQCell(eg=1.42, cell_T=300) sq_gaas.set_input_spectrum(load_astm("AM1.5g")) sq_gaas_eta = sq_gaas.get_eta() self.assertTrue(np.isclose(gaas_db_eta, sq_gaas_eta, rtol=5e-3))
def test_mj_cell_iv(self): """ Test solving multi-junction cells, by breaking it down into series-connected subcells. :return: """ sq1_cell = SQCell(eg=1.87, cell_T=300, plug_in_term=rev_breakdown_diode) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_breakdown_diode) sq3_cell = SQCell(eg=1.0, cell_T=300, plug_in_term=rev_breakdown_diode) tj_cell = MJCell([sq1_cell, sq2_cell, sq3_cell]) tj_cell.set_input_spectrum(load_astm(("AM1.5d"))) solved_mj_v, solved_mj_i = tj_cell.get_iv() # plot the I-V of sq1,sq2 and sq3 volt = np.linspace(-3, 3, num=300) plt.plot(volt, sq1_cell.get_j_from_v(volt), label="top cell") plt.plot(volt, sq2_cell.get_j_from_v(volt), label="middle cell") plt.plot(volt, sq3_cell.get_j_from_v(volt), label="bottom cell") plt.plot(solved_mj_v, solved_mj_i, '.-', label="MJ cell") plt.ylim([-200, 0]) plt.xlim([-5, 6]) plt.xlabel("voltage (V)") plt.ylabel("currnet (A/m^2)") plt.legend() plt.show()
def test_parallel_connected_mj_cells(self): """ Connected two triple-junction cells in parallel :return: """ sq1_cell = SQCell(eg=1.87, cell_T=300, plug_in_term=rev_breakdown_diode) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_breakdown_diode) sq3_cell = SQCell(eg=1.0, cell_T=300, plug_in_term=rev_breakdown_diode) tj_cell = MJCell([sq1_cell, sq2_cell, sq3_cell]) tj_cell.set_input_spectrum(load_astm(("AM1.5d"))) tj_cell_1 = copy.deepcopy(tj_cell) tj_cell_2 = copy.deepcopy(tj_cell) iv_funcs = [tj_cell_1.get_j_from_v, tj_cell_2.get_j_from_v] parallel_v, parallel_i = solve_parallel_connected_ivs(iv_funcs, vmin=-2, vmax=3.5, vnum=30) volt = np.linspace(-2, 3.5, num=30) curr = tj_cell_1.get_j_from_v(volt) plt.plot(volt, curr, '.-', label="single string") plt.plot(parallel_v, parallel_i, '.-', label="strings connected in parallel") plt.ylim([-600, 0]) plt.show()
def test_multi_junction_diode(self): hp1 = HighPSQCell(1.87, cell_T=300) hp1.set_input_spectrum(load_astm()) hp2 = HighPSQCell(1.42, cell_T=300) hp2.set_input_spectrum(load_astm()) hp3 = HighPSQCell(1.0, cell_T=300) hp3.set_input_spectrum(load_astm()) d1 = DiodeSeriesConnect([hp1, hp2, hp3]) test_v = 1.0 j1 = d1.get_j_from_v(test_v) test_v = np.linspace(-2, 3.4, num=200) j1 = d1.get_j_from_v(test_v) plt.plot(test_v, j1) plt.show()
def test_solving_five_cells(self): """ Test five series-connected, non-uniform illuminated, Eg=1.42 solar cells :return: """ sq1_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq1_cell.set_input_spectrum(load_astm("AM1.5d") * 0.5) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq2_cell.set_input_spectrum(load_astm("AM1.5d")) sq3_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq3_cell.set_input_spectrum(load_astm("AM1.5d")) sq4_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq4_cell.set_input_spectrum(load_astm("AM1.5d") * 1.5) sq5_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq5_cell.set_input_spectrum(load_astm("AM1.5d") * 0.75) iv_funcs = [sq1_cell.get_j_from_v, sq2_cell.get_j_from_v, sq3_cell.get_j_from_v, sq4_cell.get_j_from_v, sq5_cell.get_j_from_v] iv_pair = solve_series_connected_ivs(iv_funcs=iv_funcs, vmin=-3, vmax=3, vnum=300) volt = np.linspace(-3, 3, num=300) plt.plot(volt, sq1_cell.get_j_from_v(volt)) plt.plot(volt, sq2_cell.get_j_from_v(volt)) plt.plot(volt, sq4_cell.get_j_from_v(volt)) plt.plot(volt, sq5_cell.get_j_from_v(volt)) plt.plot(iv_pair[0, :], iv_pair[1, :], '.-') plt.ylim([-500, 0]) plt.xlim([-5, 6]) plt.xlabel("voltage (V)") plt.ylabel("currnet (A/m^2)") plt.show()
def setUp(self): self.dark_hpc = HighPSQCell(eg=1.42, cell_T=300) self.light_hpc = HighPSQCell(eg=1.42, cell_T=300) self.light_hpc.set_input_spectrum(load_astm())
def setUp(self): self.input_ill = load_astm("AM1.5g")
def with_reverse_diode(plot_arrow=False): sq1_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq1_cell.set_input_spectrum(load_astm("AM1.5d") * 0.5) sq2_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq2_cell.set_input_spectrum(load_astm("AM1.5d")) sq3_cell = SQCell(eg=1.42, cell_T=300, plug_in_term=rev_diode) sq3_cell.set_input_spectrum(load_astm("AM1.5d") * 1.1) iv_funcs = [ sq1_cell.get_j_from_v, sq2_cell.get_j_from_v, sq3_cell.get_j_from_v ] volt = np.linspace(-3, 2, num=300) arrow_dx = volt + 1.0 arrow_dy = np.zeros_like(volt) plt.plot(volt, sq1_cell.get_j_from_v(volt), '.-', label="cell 1") prev_current = None if plot_arrow: for v in volt: current = sq1_cell.get_j_from_v(v) if (prev_current is None) or (np.isclose( current, prev_current, rtol=5e-2) == False): plt.arrow(v, sq1_cell.get_j_from_v(v), 2.0 - v, 0, color='C0', linestyle='--') prev_current = current plt.plot(volt, sq2_cell.get_j_from_v(volt), '.-', label="cell 2") prev_current = None if plot_arrow: for v in volt: current = sq2_cell.get_j_from_v(v) if (prev_current is None) or (np.isclose( current, prev_current, rtol=5e-2) == False): plt.arrow(v, sq2_cell.get_j_from_v(v), 2.0 - v, 0, color='C1', linestyle='--') prev_current = v plt.plot(volt, sq3_cell.get_j_from_v(volt), '.-', label="cell 3") prev_current = None if plot_arrow: for v in volt: current = sq3_cell.get_j_from_v(v) if (prev_current is None) or (np.isclose( current, prev_current, rtol=5e-2) == False): plt.arrow(v, sq3_cell.get_j_from_v(v), 2.0 - v, 0, color='C2', linestyle='--') prev_current = v plt.ylim([-350, 0]) plt.xlim([-1.5, 4]) plt.xlabel("voltage (V)") plt.ylabel("current (A/m^2)") plt.legend() plt.savefig("./figs/with_rev_diode_iv.png", dpi=600) plt.savefig("./figs/with_rev_diode_iv.pdf") plt.show() plt.close() plt.figure() solved_iv, subcell_ivs = solve_series_connected_ivs(iv_funcs, -2, 3, 100, return_subcell_iv=True, add_epsilon=0.0) # plot sub cell I-Vs for subcell_id in range(3): plt.plot(subcell_ivs[subcell_id, 0, :], subcell_ivs[subcell_id, 1, :], '.-', label="cell {}".format(subcell_id + 1)) # plot summed up the voltages plt.plot(solved_iv[0], solved_iv[1], '.-', label="connected cell") plt.ylim([-350, 0]) plt.xlim([-3, 4]) plt.xlabel("voltage (V)") plt.ylabel("current (A/m^2)") plt.legend() plt.savefig("./figs/with_rev_diode_iv_solved.png", dpi=600) plt.savefig("./figs/with_rev_diode_iv_solved.pdf") plt.show()
from pypvcell.solarcell import SQCell import numpy as np import matplotlib.pyplot as plt import scipy.constants as sc from pypvcell.illumination import load_astm def rev_diode(voltage): rev_j01 = 4.46e-19 rev_bd_v = 20 return -rev_j01 * np.exp(sc.e * (-voltage - rev_bd_v) / (sc.k * 300) - 1) sq1_cell = SQCell(eg=1.3, cell_T=300, plug_in_term=rev_diode) sq1_cell.set_input_spectrum(load_astm("AM1.5d")) test_v = np.linspace(-21, 1.5, num=100) test_j = sq1_cell.get_j_from_v(test_v) print(test_j) # model reverse breakdown print(sq1_cell.j01) plt.plot(test_v, test_j) plt.show() plt.close()
def test_load_astm_fail(self): spec = "AM1.5j" with self.assertRaises(ValueError): ill = load_astm(spec)
def test_something(self): spec = "AM1.5g" ill = load_astm(spec) tp = ill.rsum() print("total power of {0}:{1}".format(spec, tp)) self.assertAlmostEqual(tp, 1000.370, places=2)