Explicit vs. Implicit Methods of IV Curve Generation - SunPower/PVMismatch GitHub Wiki

Execution Time

Let's compare the execution time between the explicit method derived by J.W. Bishop in 1988 (Solar Cells, Vol 25, pp73-89) and a general implicit method for generating an I-V curve.

Discussion

  • Explicit is 2 to 3 orders of magnitude faster than implicit
  • Speedup factor increases as the number of calculation points increases assuming that explicit method uses SIMD via SSE
  • Implicit introduces errors, since it quits iterating when it’s either the Newton step or the norm of residuals reaches TOL. The errors ...
    • ... are smallest near Vcell = 0, the
    • ... are very small, on the order of 0.1 micro-amps in forward bias (I)
    • ... explode in reverse bias (II) and for negative current (IV)

Results

trial Num. pts Explicit method Implicit method Speedup factor
1 202 95.2 µs ± 466 ns per loop 26.7 ms ± 229 µs per loop 280x
2 202 96 µs ± 844 ns per loop 26.4 ms ± 157 µs per loop 275x
3 2002 211 µs ± 1.32 µs per loop 265 ms ± 3.09 ms per loop 1256x
4 2002 213 µs ± 1.45 µs per loop 261 ms ± 618 µs per loop 1225x

Errors from implicit method in forward bias

Imgur forward bias implicit errors

Errors from implicit method in reverse bias

Imgur reverse bias implicit errors

Notes

  • Probably won’t big differences between difference BLAS’s, ie: OpenBLAS will perform as well as Intel MKL. BLAS is used to vectorize calculations and also for the hybrd non-linear solver in minpack.
  • Python NumPy automatically uses BLAS with some sort of SIMD depending on BLAS and chipset, but there will still be an improvement in speed even without SIMD, because the explicit method doesn’t have do repeat iterations at each calculation point, and it doesn’t ever have to calculate any Jacobians (read: derivatives), so the total number of flops per calculation point are many times smaller.

Test Code

>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>> from pvmismatch import *

>>> pvc = pvcell.PVcell(pvconst=pvconstants.PVconstants(npts=1001))
>>> pvc._calc_now = False
>>> pvc.Ee = 0.888
>>> pvc.Tcell = 323

>>> %timeit pvc.calcCell()
>>> %timeit pvc.calcCell()

>>> Icells, Vcells, Pcells = pvc.calcCell()

>>> %timeit [pvc.calcIcell(Vc) for Vc in Vcells]
>>> %timeit [pvc.calcIcell(Vc) for Vc in Vcells]

>>> Itest = np.asarray([pvc.calcIcell(Vc) for Vc in Vcells])

>>> plt.ion()

>>> pos_idx = Vcells>0
>>> plt.plot(Vcells[pos_idx], Icells[pos_idx] - Itest[pos_idx])
>>> plt.xlabel('cell voltage, $V_{cell} [V]$')
>>> plt.ylabel('current difference [A]')
>>> plt.title('current error versus test voltage between implicit and explicit\n')
>>> plt.tight_layout()
>>> plt.grid()

>>> plt.figure()

>>> neg_idx = np.logical_and(-4.5<Vcells, Vcells<0)
>>> plt.plot(Vcells[neg_idx], Icells[neg_idx] - Itest[neg_idx])
>>> plt.title('current error versus test voltage between implicit and explicit\n')
>>> plt.grid()
>>> plt.ylabel('current difference [A]')
>>> plt.xlabel('cell voltage, $V_{cell} [V]$')
>>> plt.tight_layout()