From b8dfb6ad54c78bf33544ceaf80c58cab6cea1959 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Sat, 23 Jul 2016 23:16:39 -0700 Subject: [PATCH 1/7] implement log lambertw calculation in v_from_i --- pvlib/pvsystem.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 989748f072..02bb451a2b 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -1827,11 +1827,26 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current, IL = photocurrent I = current - argW = I0 * Rsh / nNsVth * np.exp(Rsh *(-I + IL + I0) / nNsVth) + argW = I0 * Rsh / nNsVth * np.exp(Rsh * (-I + IL + I0) / nNsVth) lambertwterm = lambertw(argW) - # Eqn. 3 in Jain and Kapoor, 2004 + # Calculate using log(argW) in case argW is really big + logargW = (np.log(I0) + np.log(Rsh) - np.log(nNsVth) + + Rsh * (-I + IL + I0) / nNsVth) + + # Three iterations of Newton-Raphson method to solve + # w+log(w)=logargW. The initial guess is w=logargW. Where direct + # evaluation (above) results in NaN from overflow, 3 iterations + # of Newton's method gives approximately 8 digits of precision. + w = logargW + for i in range(0, 3): + w = w * (1 - np.log(w) + logargW) / (1 + w) + lambertwterm_log = w + lambertwterm = np.where(np.isinf(lambertwterm), lambertwterm_log, + lambertwterm) + + # Eqn. 3 in Jain and Kapoor, 2004 V = -I*(Rs + Rsh) + IL*Rsh - nNsVth*lambertwterm + I0*Rsh return V.real From 01f72da1911be4454ba0431e30eecd54e6a6f184 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Sat, 23 Jul 2016 23:24:57 -0700 Subject: [PATCH 2/7] add test --- pvlib/test/test_pvsystem.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index 3d8607db43..6790420730 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -355,26 +355,32 @@ def test_PVSystem_calcparams_desoto(cec_module_params): @requires_scipy def test_v_from_i(): output = pvsystem.v_from_i(20, .1, .5, 3, 6e-7, 7) - assert_allclose(7.5049875193450521, output, 5) + assert_allclose(7.5049875193450521, output, atol=1e-5) @requires_scipy def test_v_from_i_big(): output = pvsystem.v_from_i(500, 10, 4.06, 0, 6e-10, 1.2) - assert_allclose(86.320000493521079, output, 5) + assert_allclose(86.320000493521079, output, atol=1e-5) + + +@requires_scipy +def test_v_from_i_bigger(): + output = pvsystem.v_from_i(380, 1.065, 2.76, 0, 9e-9, 5.2) + assert_allclose(55.603393370545305, output, atol=1e-5) @requires_scipy def test_i_from_v(): output = pvsystem.i_from_v(20, .1, .5, 40, 6e-7, 7) - assert_allclose(-299.746389916, output, 5) + assert_allclose(-299.746389916, output, atol=1e-5) @requires_scipy def test_PVSystem_i_from_v(): system = pvsystem.PVSystem() output = system.i_from_v(20, .1, .5, 40, 6e-7, 7) - assert_allclose(-299.746389916, output, 5) + assert_allclose(-299.746389916, output, atol=1e-5) @requires_scipy From 61246345ba07ea657beadf06a965c737eb1f9117 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Sat, 23 Jul 2016 23:41:38 -0700 Subject: [PATCH 3/7] more robust --- pvlib/pvsystem.py | 4 ++-- pvlib/test/test_pvsystem.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 02bb451a2b..95146462fd 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -1843,8 +1843,8 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current, w = w * (1 - np.log(w) + logargW) / (1 + w) lambertwterm_log = w - lambertwterm = np.where(np.isinf(lambertwterm), lambertwterm_log, - lambertwterm) + lambertwterm = np.where(np.isfinite(lambertwterm), lambertwterm, + lambertwterm_log) # Eqn. 3 in Jain and Kapoor, 2004 V = -I*(Rs + Rsh) + IL*Rsh - nNsVth*lambertwterm + I0*Rsh diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index 6790420730..9148a7a24d 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -366,8 +366,9 @@ def test_v_from_i_big(): @requires_scipy def test_v_from_i_bigger(): - output = pvsystem.v_from_i(380, 1.065, 2.76, 0, 9e-9, 5.2) - assert_allclose(55.603393370545305, output, atol=1e-5) + # 1000 W/m^2 on a Canadian Solar 220M with 20 C ambient temp + output = pvsystem.v_from_i(190, 1.065, 2.89, 0, 7.05196029e-08, 10.491262) + assert_allclose(54.303958833791455, output, atol=1e-5) @requires_scipy From 0e245bdf71c60b40564a283f7ec776733b5e1ca9 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Sun, 24 Jul 2016 09:08:00 -0700 Subject: [PATCH 4/7] add note to whatsnew --- docs/sphinx/source/whatsnew/v0.4.0.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.4.0.txt b/docs/sphinx/source/whatsnew/v0.4.0.txt index ec00fe5b81..4ad28b1d94 100644 --- a/docs/sphinx/source/whatsnew/v0.4.0.txt +++ b/docs/sphinx/source/whatsnew/v0.4.0.txt @@ -65,6 +65,8 @@ Bug fixes rather than requiring that the solution for all points be within the error tolerance. Results in test scenarios changed by 1-10%. (:issue:`221`) +* Fixed a numerical overflow error in pvsystem.singlediode's v_oc + determination for some combinations of parameters. (:issue:`225`) * dirint function yielded the wrong results for non-sea-level pressures. Fixed. (:issue:`212`) * Fixed a bug in the day angle calculation used by the 'spencer' and 'asce' From 717c6e8abe23c71365fb3d555ed3d69b0831a52b Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Sun, 24 Jul 2016 09:10:08 -0700 Subject: [PATCH 5/7] add issue note to test --- pvlib/test/test_pvsystem.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py index 9148a7a24d..ecd7ec3aca 100644 --- a/pvlib/test/test_pvsystem.py +++ b/pvlib/test/test_pvsystem.py @@ -367,6 +367,7 @@ def test_v_from_i_big(): @requires_scipy def test_v_from_i_bigger(): # 1000 W/m^2 on a Canadian Solar 220M with 20 C ambient temp + # github issue 225 output = pvsystem.v_from_i(190, 1.065, 2.89, 0, 7.05196029e-08, 10.491262) assert_allclose(54.303958833791455, output, atol=1e-5) From 10cc56b0de9e294e63a980faa188090bb7365d17 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Tue, 26 Jul 2016 15:36:21 -0700 Subject: [PATCH 6/7] move the .real --- pvlib/pvsystem.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py index 95146462fd..6ea3622a12 100644 --- a/pvlib/pvsystem.py +++ b/pvlib/pvsystem.py @@ -1828,7 +1828,7 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current, I = current argW = I0 * Rsh / nNsVth * np.exp(Rsh * (-I + IL + I0) / nNsVth) - lambertwterm = lambertw(argW) + lambertwterm = lambertw(argW).real # Calculate using log(argW) in case argW is really big logargW = (np.log(I0) + np.log(Rsh) - np.log(nNsVth) + @@ -1849,7 +1849,7 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current, # Eqn. 3 in Jain and Kapoor, 2004 V = -I*(Rs + Rsh) + IL*Rsh - nNsVth*lambertwterm + I0*Rsh - return V.real + return V def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, @@ -1913,12 +1913,12 @@ def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, argW = (Rs*I0*Rsh * np.exp(Rsh*(Rs*(IL+I0)+V) / (nNsVth*(Rs+Rsh))) / (nNsVth*(Rs + Rsh))) - lambertwterm = lambertw(argW) + lambertwterm = lambertw(argW).real # Eqn. 4 in Jain and Kapoor, 2004 I = -V/(Rs + Rsh) - (nNsVth/Rs)*lambertwterm + Rsh*(IL + I0)/(Rs + Rsh) - return I.real + return I def snlinverter(v_dc, p_dc, inverter): From dd5cfc011ac9d3bb513e2f735def314715b5bd83 Mon Sep 17 00:00:00 2001 From: Will Holmgren Date: Wed, 27 Jul 2016 08:34:16 -0700 Subject: [PATCH 7/7] remove scipy version in appveyor config --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 08c939e5f3..0055415380 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,7 @@ install: - cmd: conda info -a # install depenencies - - cmd: conda create -n test_env --yes --quiet python=%PYTHON_VERSION% pip numpy scipy=0.16.0 pandas nose pytest pytz ephem numba + - cmd: conda create -n test_env --yes --quiet python=%PYTHON_VERSION% pip numpy scipy pandas nose pytest pytz ephem numba - cmd: activate test_env - cmd: python --version - cmd: conda list