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
Errors from implicit method in reverse bias
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()