Repository: pvlib/pvlib-python

Issue:
Error in Ixx equation in pvsystem.sapm
The SAPM function uses `Aisc` (temperature coefficient for Isc) in the equation for `Ixx`, where it should be `Aimp` (temperature coefficient for Imp). [This line](https://github.com/pvlib/pvlib-python/blob/1d854e5a83543de34337a63356efb9c8dd3d859a/pvlib/pvsystem.py#L2260).

Equation 10 of the 2004 [Sandia report](https://www.osti.gov/servlets/purl/919131) shows `Aimp` is intended.

Discussion among the Sandia staff concluded that there is a typo in PVLib for Matlab, in [this line](https://github.com/sandialabs/MATLAB_PV_LIB/blob/684553ac1d21c59752240295ef225af7ccc1ca82/pvl_sapm.m#L93).

This error was propagated when the Matlab code was ported to python by R. Andrews (see pvl_sapm.py file in the prearizona tag for pvlib).

The comment originated with W. Holmgren, who may have been looking at the Matlab code as the authoritative source.

**Expected behavior**
Correct [this line](https://github.com/pvlib/pvlib-python/blob/1d854e5a83543de34337a63356efb9c8dd3d859a/pvlib/pvsystem.py#L2260) to use `Aimp`.

**Versions:**
 - ``pvlib.__version__``:  all versions

**Additional context**
The error only affects `Ixx` from `pvsystem.sapm` and nothing else.

PVLib for Matlab issue https://github.com/sandialabs/MATLAB_PV_LIB/issues/37



Discussion:

Patch:
diff --git a/docs/sphinx/source/whatsnew/v0.10.5.rst b/docs/sphinx/source/whatsnew/v0.10.5.rst
index 41c55da8f9..7ee3be7613 100644
--- a/docs/sphinx/source/whatsnew/v0.10.5.rst
+++ b/docs/sphinx/source/whatsnew/v0.10.5.rst
@@ -15,6 +15,7 @@ Enhancements
 
 Bug fixes
 ~~~~~~~~~
+* Corrected equation for Ixx0 in :py:func:`pvlib.pvsystem.sapm` (:issue:`2016`, :pull:`2019`)
 * Fixed :py:func:`pvlib.pvsystem.retrieve_sam` silently ignoring the `path` parameter
   when `name` was provided. Now an exception is raised requesting to only provide one
   of the two parameters. (:issue:`2018`, :pull:`2020`)
diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py
index c5a0f55558..096d3896f5 100644
--- a/pvlib/pvsystem.py
+++ b/pvlib/pvsystem.py
@@ -2264,10 +2264,9 @@ def sapm(effective_irradiance, temp_cell, module):
         module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
         (1 + module['Aisc']*(temp_cell - temp_ref)))
 
-    # the Ixx calculation in King 2004 has a typo (mixes up Aisc and Aimp)
     out['i_xx'] = (
         module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
-        (1 + module['Aisc']*(temp_cell - temp_ref)))
+        (1 + module['Aimp']*(temp_cell - temp_ref)))
 
     if isinstance(out['i_sc'], pd.Series):
         out = pd.DataFrame(out)


Test patch:
diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py
index 1151432bd7..f193a16e95 100644
--- a/pvlib/tests/test_pvsystem.py
+++ b/pvlib/tests/test_pvsystem.py
@@ -166,16 +166,14 @@ def test_sapm(sapm_module_params):
     out = pvsystem.sapm(effective_irradiance, temp_cell, sapm_module_params)
 
     expected = pd.DataFrame(np.array(
-      [[  -5.0608322 ,   -4.65037767,           nan,           nan,
-                  nan,   -4.91119927,   -4.15367716],
-       [   2.545575  ,    2.28773882,   56.86182059,   47.21121608,
-         108.00693168,    2.48357383,    1.71782772],
-       [   5.65584763,    5.01709903,   54.1943277 ,   42.51861718,
-         213.32011294,    5.52987899,    3.48660728],
-       [          nan,           nan,           nan,           nan,
-                  nan,           nan,           nan],
-       [          nan,           nan,           nan,           nan,
-                  nan,           nan,           nan]]),
+        [[-5.0608322, -4.65037767, np.nan, np.nan, np.nan,
+          -4.91119927, -4.16721569],
+         [2.545575, 2.28773882, 56.86182059, 47.21121608, 108.00693168,
+          2.48357383, 1.71782772],
+         [5.65584763, 5.01709903, 54.1943277, 42.51861718, 213.32011294,
+          5.52987899, 3.46796463],
+         [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
+         [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]]),
         columns=['i_sc', 'i_mp', 'v_oc', 'v_mp', 'p_mp', 'i_x', 'i_xx'],
         index=times)
 
@@ -184,13 +182,13 @@ def test_sapm(sapm_module_params):
     out = pvsystem.sapm(1000, 25, sapm_module_params)
 
     expected = OrderedDict()
-    expected['i_sc'] = 5.09115
-    expected['i_mp'] = 4.5462909092579995
-    expected['v_oc'] = 59.260800000000003
-    expected['v_mp'] = 48.315600000000003
-    expected['p_mp'] = 219.65677305534581
-    expected['i_x'] = 4.9759899999999995
-    expected['i_xx'] = 3.1880204359100004
+    expected['i_sc'] = sapm_module_params['Isco']
+    expected['i_mp'] = sapm_module_params['Impo']
+    expected['v_oc'] = sapm_module_params['Voco']
+    expected['v_mp'] = sapm_module_params['Vmpo']
+    expected['p_mp'] = sapm_module_params['Impo'] * sapm_module_params['Vmpo']
+    expected['i_x'] = sapm_module_params['IXO']
+    expected['i_xx'] = sapm_module_params['IXXO']
 
     for k, v in expected.items():
         assert_allclose(out[k], v, atol=1e-4)