def test_fish(): """ test shunt current. """ # make sympy symbols ish, vd, rsh = sympy.symbols(['ish', 'vd', 'rsh']) # shunt current ish = vd / rsh d_vd = sympy.diff(ish, vd) d_rsh = sympy.diff(ish, rsh) # evaluate test_data = {'vd': VD_1, 'rsh': RSH_1} fish_test, jish_test = diode.fish(**test_data) fish_expected = np.float(ish.evalf(subs=test_data)) jish_expected = np.array( [d_vd.evalf(subs=test_data), d_rsh.evalf(subs=test_data)], dtype=np.float) LOGGER.debug('test: %g = expected: %g', fish_test, fish_expected) assert np.isclose(fish_test, fish_expected) assert np.allclose(jish_test, jish_expected.reshape(-1, 1))
def residual_two_diode(x, isc, voc, imp, vmp, tc): """ Objective function to solve 2-diode model. :param x: parameters isat1, isat2, rs and rsh :param isc: short circuit current [A] at tc [C] :param voc: open circuit voltage [V] at tc [C] :param imp: max power current [A] at tc [C] :param vmp: max power voltage [V] at tc [C] :param tc: cell temperature [C] :return: norm of the residuals its sensitivity """ # Constants q = diode.QE # [C/electron] elementary electric charge # (n.b. 1 Coulomb = 1 A * s) kb = diode.KB # [J/K/molecule] Boltzmann's constant tck = tc + 273.15 # [K] reference temperature # Governing Equation vt = kb * tck / q # [V] thermal voltage # Rescale Variables isat1_t0 = np.exp(x[0]) isat2 = np.exp(x[1]) rs = x[2]**2.0 rsh = x[3]**2.0 # first diode saturation current isat1 = diode.isat_t(tc, isat1_t0) # Short Circuit vd_isc, _ = diode.fvd(vc=0.0, ic=isc, rs=rs) id1_isc, _ = diode.fid(isat=isat1, vd=vd_isc, m=1.0, vt=vt) id2_isc, _ = diode.fid(isat=isat2, vd=vd_isc, m=2.0, vt=vt) ish_isc, _ = diode.fish(vd=vd_isc, rsh=rsh) # Photo-generated Current iph = isc + id1_isc + id2_isc + ish_isc # [A] # Open Circuit vd_voc, jvd_voc = diode.fvd(vc=voc, ic=0.0, rs=rs) id1_voc, jid1_voc = diode.fid(isat=isat1, vd=vd_voc, m=1.0, vt=vt) id2_voc, jid2_voc = diode.fid(isat=isat2, vd=vd_voc, m=2.0, vt=vt) ish_voc, jish_voc = diode.fish(vd=vd_voc, rsh=rsh) # Max Power Point vd_mpp, jvd_mpp = diode.fvd(vc=vmp, ic=imp, rs=rs) id1_mpp, jid1_mpp = diode.fid(isat=isat1, vd=vd_mpp, m=1.0, vt=vt) id2_mpp, jid2_mpp = diode.fid(isat=isat2, vd=vd_mpp, m=2.0, vt=vt) ish_mpp, jish_mpp = diode.fish(vd=vd_mpp, rsh=rsh) # Slope at Max Power Point dpdv, jdpdv = two_diode.fdpdv(isat1=isat1, isat2=isat2, rs=rs, rsh=rsh, ic=imp, vc=vmp, vt=vt) # Shunt Resistance frsh, jrsh = two_diode.fjrsh(isat1=isat1, isat2=isat2, rs=rs, rsh=rsh, vt=vt, isc=isc) # Residual # should be (M, ) array with M residual equations (constraints) f2 = np.stack( [ (iph - id1_voc - id2_voc - ish_voc).T, # Open Circuit (iph - id1_mpp - id2_mpp - ish_mpp - imp).T, # Max Power Point dpdv.T, # Slope at Max Power Point frsh.T # Shunt Resistance ], axis=0).flatten() # Jacobian # should be (M, N) array with M residuals and N variables # [[df1/dx1, df1/dx2, ...], [df2/dx1, df2/dx2, ...]] jvoc = np.stack( ( -jid1_voc[0], # d/disat1 -jid2_voc[0], # d/disat2 -jvd_voc[2] * (jid1_voc[1] + jid2_voc[1] + jish_voc[0]), # d/drs -jish_voc[1] # d/drsh ), axis=0).T.reshape(-1, 4) jmpp = np.stack( ( -jid1_mpp[0], # d/disat1 -jid2_mpp[0], # d/disat2 -jvd_mpp[2] * (jid1_mpp[1] + jid2_mpp[1] + jish_mpp[0]), # d/drs -jish_mpp[1] # d.drsh ), axis=0).T.reshape(-1, 4) # Scaling Factors scale_fx = np.array([np.exp(x[0]), np.exp(x[1]), 2 * x[2], 2 * x[3]]) # scales each column by the corresponding element j2 = np.concatenate( (jvoc, jmpp, jdpdv[:4].T.reshape(-1, 4), jrsh[:4].T.reshape(-1, 4)), axis=0) * scale_fx return f2, j2