Example #1
0
def fdidv(isat1, isat2, rs, rsh, ic, vc, vt):
    """
    Derivative of IV curve and its derivatives w.r.t. Isat1, Isat2, Rs, Rsh, Ic,
    Vc and Vt.

    :param isat1: diode 1 saturation current [A]
    :param isat2: diode 2 saturation current [A]
    :param rs: series resistance [ohms]
    :param rsh: shunt resistance [ohms]
    :param ic: cell current [A]
    :param vc: cell voltage [V]
    :param vt: thermal voltage (kB * Tc / qe = 26[mV] at Tc=298K) [V]
    :return: derivative of IV curve and its derivatives
    """
    vd, _ = diode.fvd(vc, ic, rs)  # vd = vc + ic * rs
    vstar = vd / vt
    rstar = rsh / rs
    exp_vstar, exp_vstar_2 = np.exp(vstar), np.exp(0.5 * vstar)
    v_sat1_sh, v_sat2_sh = isat1 * rsh, isat2 * rsh
    v_sat1_sh_exp_vstar = v_sat1_sh * exp_vstar
    v_sat2_sh_exp_vstar_2 = 0.5 * v_sat2_sh * exp_vstar_2
    vsum = v_sat1_sh_exp_vstar + v_sat2_sh_exp_vstar_2 + vt
    vsum_rstar = vsum + vt * rstar
    combiterm1 = v_sat1_sh_exp_vstar + 0.5*v_sat2_sh_exp_vstar_2
    combiterm2 = isat1*exp_vstar + 0.5*isat2*exp_vstar_2
    combiterm3 = vsum / vsum_rstar - 1.0
    combiterm4 = vsum_rstar * rs
    combiterm5 = rstar * combiterm3 / vsum_rstar
    combiterm6 = combiterm1 * combiterm3 / vt
    combiterm7 = 1.0 / combiterm4
    # dI/dV = derivative of IV curve
    didv = -vsum / combiterm4
    # jacobian
    didv_isat1 = exp_vstar * combiterm5
    didv_isat2 = 0.5 * exp_vstar_2 * combiterm5
    didv__r_s = combiterm7 * (combiterm6 * ic + vsum**2.0 / combiterm4)
    didv_rsh = combiterm7 * (combiterm2 * combiterm3 + vt * vsum / combiterm4)
    didv_ic = combiterm6 / vsum_rstar
    didv_vc = (didv + 1.0 / rs) * didv_ic
    jac = np.array([
        didv_isat1, didv_isat2, didv__r_s, didv_rsh, didv_ic, didv_vc
    ])
    return didv, jac
Example #2
0
def test_fvd():
    """
    Test diode voltage.
    """
    # make sympy symbols
    vd, vc, ic, rs = sympy.symbols(['vd', 'vc', 'ic', 'rs'])
    # diode voltage
    vd = vc + ic * rs
    d_vc = sympy.diff(vd, vc)
    d_ic = sympy.diff(vd, ic)
    d_rs = sympy.diff(vd, rs)
    # evaluate
    test_data = {'vc': VC, 'ic': IC, 'rs': RS_1}
    fvd_test, jvd_test = diode.fvd(**test_data)
    fvd_expected = np.float(vd.evalf(subs=test_data))
    jvd_expected = np.array([
        d_vc.evalf(subs=test_data),
        d_ic.evalf(subs=test_data),
        d_rs.evalf(subs=test_data)
    ],
                            dtype=np.float)
    LOGGER.debug('test: %g = expected: %g', fvd_test, fvd_expected)
    assert np.isclose(fvd_test, fvd_expected)
    assert np.allclose(jvd_test, jvd_expected.reshape(-1, 1))
Example #3
0
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
Example #4
0
def fdpdv(isat1, isat2, rs, rsh, ic, vc, vt):
    """
    Derivative of PV curve and its derivatives w.r.t. Isat1, Isat2, Rs, Rsh, Ic,
    Vc and Vt.

    :param isat1: diode 1 saturation current [A]
    :param isat2: diode 2 saturation current [A]
    :param rs: series resistance [ohms]
    :param rsh: shunt resistance [ohms]
    :param ic: cell current [A]
    :param vc: cell voltage [V]
    :param vt: thermal voltage (kB * Tc / qe = 26[mV] at Tc=298K) [V]
    :return: derivative of PV curve and its derivatives
    """
    didv, _ = fdidv(isat1, isat2, rs, rsh, ic, vc, vt)
    vd, _ = diode.fvd(vc, ic, rs)  # vd = vc + ic * rs
    dpdv = didv * vc + ic
    dpdv_isat1 = 2.0*rs*rsh*vc*(
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )*np.exp(vd/vt)/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )**2 - 2.0*rsh*vc*np.exp(vd/vt)/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )
    dpdv_isat2 = rs*rsh*vc*(
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )*np.exp(0.5*vd/vt)/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )**2 - rsh*vc*np.exp(0.5*vd/vt)/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )
    dpdv_rs = -vc*(
        2.0*isat1*rsh*ic*np.exp(vd/vt)/vt
        + 0.5*isat2*rsh*ic*np.exp(0.5*vd/vt)/vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    ) - vc*(
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )*(
        -2.0*isat1*rs*rsh*ic*np.exp(vd/vt)/vt
        - 2.0*isat1*rsh*np.exp(vd/vt)
        - 0.5*isat2*rs*rsh*ic*np.exp(0.5*vd/vt)/vt
        - isat2*rsh*np.exp(0.5*vd/vt) - 2.0*vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )**2
    dpdv_rsh = -vc*(
        2.0*isat1*np.exp(vd/vt) + isat2*np.exp(0.5*vd/vt)
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    ) - vc*(
        -2.0*isat1*rs*np.exp(vd/vt) - isat2*rs*np.exp(0.5*vd/vt) - 2.0*vt
    )*(
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )**2
    dpdv_ic = -vc*(
        2.0*isat1*rs*rsh*np.exp(vd/vt)/vt
        + 0.5*isat2*rs*rsh*np.exp(0.5*vd/vt)/vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    ) - vc*(
        -2.0*isat1*rs**2*rsh*np.exp(vd/vt)/vt
        - 0.5*isat2*rs**2*rsh*np.exp(0.5*vd/vt)/vt
    )*(
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )**2 + 1.0
    dpdv_vc = -vc*(
        2.0*isat1*rsh*(rs*didv + 1)*np.exp(vd/vt)/vt
        + 0.5*isat2*rsh*(rs*didv + 1)*np.exp(0.5*vd/vt)/vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    ) - vc*(
        -2.0*isat1*rs*rsh*(rs*didv + 1)*np.exp(vd/vt)/vt
        - 0.5*isat2*rs*rsh*(rs*didv + 1)*np.exp(0.5*vd/vt)/vt
    )*(
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    )**2 - (
        2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
    )/(
        2.0*isat1*rs*rsh*np.exp(vd/vt)
        + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
    ) + didv
    jac = np.array([
        dpdv_isat1, dpdv_isat2, dpdv_rs, dpdv_rsh, dpdv_ic, dpdv_vc
        ])
    return dpdv, jac
Example #5
0
def fjrsh(isat1, isat2, rs, rsh, vt, isc):
    """
    Shunt resistance residual and its derivatives w.r.t. Isat1, Isat2, Rs and
    Rsh.

    :param isat1: diode 1 saturation current [A]
    :param isat2: diode 2 saturation current [A]
    :param rs: series resistance [ohms]
    :param rsh: shunt resistance [ohms]
    :param vt: thermal voltage (kB * Tc / qe = 26[mV] at Tc=298K) [V]
    :param isc: short circuit current [A]
    :return: Rsh residual and its derivatives

    Shunt resistance is assumed to be equal to the inverse of the slope of the
    IV curve at short circuit.

    .. math::
        Rsh = \\frac{ -1 }{ \\left. \\frac{dI}{dV} \\right|_{V=0} }

    This assumption is valid when [put condition here].
    """
    didv, _ = fdidv(isat1, isat2, rs, rsh, ic=isc, vc=0, vt=vt)
    vd, _ = diode.fvd(0.0, isc, rs)  # vd = vc + ic * rs = 0.0 + isc * rs
    # frsh = rsh + 1/didv
    frsh = vd * (1.0/rsh + didv)
    dfrsh_isat1 = vd*(
        2.0*rs*rsh*(
            2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
        )*np.exp(vd/vt)/(
            2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt)
            + 2.0*rs*vt + 2.0*rsh*vt
        )**2 - 2.0*rsh*np.exp(vd/vt)/(
            2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt)
            + 2.0*rs*vt + 2.0*rsh*vt
        )
    )
    dfrsh_isat2 = vd*(
        rs*rsh*(
            2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
        )*np.exp(0.5*vd/vt)/(
            2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt)
            + 2.0*rs*vt + 2.0*rsh*vt
        )**2 - rsh*np.exp(0.5*vd/vt)/(
            2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt)
            + 2.0*rs*vt + 2.0*rsh*vt
        )
    )
    dfrsh_rs = (
        vd*(
            -(
                2.0*isat1*rsh*isc*np.exp(vd/vt)/vt + 0.5*isat2*rsh*isc*np.exp(0.5*vd/vt)/vt
            )/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            ) - (
                2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
            )*(
                -2.0*isat1*rs*rsh*isc*np.exp(vd/vt)/vt
                - 2.0*isat1*rsh*np.exp(vd/vt)
                - 0.5*isat2*rs*rsh*isc*np.exp(0.5*vd/vt)/vt
                - isat2*rsh*np.exp(0.5*vd/vt) - 2.0*vt
            )/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            )**2
        ) + (
            -(2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt)/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            ) + 1.0/rsh
        )*isc
    )
    dfrsh_rsh = (
        vd*(
            -(2.0*isat1*np.exp(vd/vt) + isat2*np.exp(0.5*vd/vt))/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            ) - (
                -2.0*isat1*rs*np.exp(vd/vt) - isat2*rs*np.exp(0.5*vd/vt) - 2.0*vt
            )*(2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt)/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            )**2 - 1.0/rsh**2
        )
    )
    dfrsh_ic = (
        rs*(
            -(2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt)/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            ) + 1.0/rsh
        ) + vd*(
            -(
                2.0*isat1*rs*rsh*np.exp(vd/vt)/vt + 0.5*isat2*rs*rsh*np.exp(0.5*vd/vt)/vt
            )/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            ) - (
                -2.0*isat1*rs**2*rsh*np.exp(vd/vt)/vt - 0.5*isat2*rs**2*rsh*np.exp(0.5*vd/vt)/vt
            )*(
                2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt
            )/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            )**2
        )
    )
    dfrsh_vc = (
        vd*(-(
            2.0*isat1*rsh*(rs*didv + 1)*np.exp(vd/vt)/vt
            + 0.5*isat2*rsh*(rs*didv + 1)*np.exp(0.5*vd/vt)/vt
        )/(
            2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
        ) - (
            -2.0*isat1*rs*rsh*(rs*didv + 1)*np.exp(vd/vt)/vt
            - 0.5*isat2*rs*rsh*(rs*didv + 1)*np.exp(0.5*vd/vt)/vt
        )*(2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt)/(
            2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
        )**2) + (rs*didv + 1)*(
            -(2.0*isat1*rsh*np.exp(vd/vt) + isat2*rsh*np.exp(0.5*vd/vt) + 2.0*vt)/(
                2.0*isat1*rs*rsh*np.exp(vd/vt) + isat2*rs*rsh*np.exp(0.5*vd/vt) + 2.0*rs*vt + 2.0*rsh*vt
            ) + 1.0/rsh
        )
    )
    jac = np.array([
        dfrsh_isat1, dfrsh_isat2, dfrsh_rs, dfrsh_rsh, dfrsh_ic, dfrsh_vc
    ])
    return frsh, jac