diff --git a/docs/sphinx/source/reference/pv_modeling/parameters.rst b/docs/sphinx/source/reference/pv_modeling/parameters.rst
index 9b1817bd01..6b54cfedfd 100644
--- a/docs/sphinx/source/reference/pv_modeling/parameters.rst
+++ b/docs/sphinx/source/reference/pv_modeling/parameters.rst
@@ -21,6 +21,14 @@ Functions for fitting the single diode equation
 
     ivtools.sde.fit_sandia_simple
 
+Functions for converting between single diode models
+
+.. autosummary::
+   :toctree: ../generated/
+
+    ivtools.sdm.convert_cec_pvsyst
+    ivtools.sdm.convert_pvsyst_cec
+
 Utilities for working with IV curve data
 
 .. autosummary::
diff --git a/pvlib/ivtools/sdm.py b/pvlib/ivtools/sdm.py
index 07bd6e2396..2e85e6b2c2 100644
--- a/pvlib/ivtools/sdm.py
+++ b/pvlib/ivtools/sdm.py
@@ -7,12 +7,14 @@
 """
 
 import numpy as np
+import pandas as pd
 
 from scipy import constants
 from scipy import optimize
 from scipy.special import lambertw
 
-from pvlib.pvsystem import calcparams_pvsyst, singlediode, v_from_i
+from pvlib.pvsystem import (calcparams_pvsyst, calcparams_cec, singlediode,
+                            v_from_i)
 from pvlib.singlediode import bishop88_mpp
 
 from pvlib.ivtools.utils import rectify_iv_curve, _numdiff
@@ -24,6 +26,17 @@
 CONSTANTS = {'E0': 1000.0, 'T0': 25.0, 'k': constants.k, 'q': constants.e}
 
 
+IEC61853 = pd.DataFrame(
+    columns=['effective_irradiance', 'temp_cell'],
+    data=np.array(
+        [[100, 100, 100, 100, 200, 200, 200, 200, 400, 400, 400, 400,
+          600, 600, 600, 600, 800, 800, 800, 800, 1000, 1000, 1000, 1000,
+          1100, 1100, 1100, 1100],
+         [15, 25, 50, 75, 15, 25, 50, 75, 15, 25, 50, 75, 15, 25, 50, 75,
+          15, 25, 50, 75, 15, 25, 50, 75, 15, 25, 50, 75]]).T,
+    dtype=np.float64)
+
+
 def fit_cec_sam(celltype, v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc,
                 gamma_pmp, cells_in_series, temp_ref=25):
     """
@@ -1354,3 +1367,309 @@ def maxp(temp_cell, irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
     gamma_pdc = _first_order_centered_difference(maxp, x0=temp_ref, args=args)
 
     return gamma_pdc / pmp
+
+
+def _pvsyst_objfun(pvs_mod, cec_ivs, ee, tc, cs):
+
+    # translate the guess into named args that are used in the functions
+    # order : [alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref,
+    # R_sh_mult, R_sh_ref, R_s]
+    # cec_ivs : DataFrame with columns i_sc, v_oc, i_mp, v_mp, p_mp
+    # ee : effective irradiance
+    # tc : cell temperature
+    # cs : cells in series
+    alpha_sc = pvs_mod[0]
+    gamma_ref = pvs_mod[1]
+    mu_gamma = pvs_mod[2]
+    I_L_ref = pvs_mod[3]
+    I_o_ref = pvs_mod[4]
+    R_sh_mult = pvs_mod[5]
+    R_sh_ref = pvs_mod[6]
+    R_s = pvs_mod[7]
+
+    R_sh_0 = R_sh_ref * R_sh_mult
+
+    pvs_params = calcparams_pvsyst(
+        ee, tc, alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref, R_sh_ref,
+        R_sh_0, R_s, cs)
+
+    pvsyst_ivs = singlediode(*pvs_params)
+
+    isc_diff = np.abs((pvsyst_ivs['i_sc'] - cec_ivs['i_sc']) /
+                      cec_ivs['i_sc']).mean()
+    imp_diff = np.abs((pvsyst_ivs['i_mp'] - cec_ivs['i_mp']) /
+                      cec_ivs['i_mp']).mean()
+    voc_diff = np.abs((pvsyst_ivs['v_oc'] - cec_ivs['v_oc']) /
+                      cec_ivs['v_oc']).mean()
+    vmp_diff = np.abs((pvsyst_ivs['v_mp'] - cec_ivs['v_mp']) /
+                      cec_ivs['v_mp']).mean()
+    pmp_diff = np.abs((pvsyst_ivs['p_mp'] - cec_ivs['p_mp']) /
+                      cec_ivs['p_mp']).mean()
+
+    mean_abs_diff = (isc_diff + imp_diff + voc_diff + vmp_diff + pmp_diff) / 5
+
+    return mean_abs_diff
+
+
+def convert_cec_pvsyst(cec_model, cells_in_series, method='Nelder-Mead',
+                       options=None):
+    r"""
+    Convert a set of CEC model parameters to an equivalent set of PVsyst model
+    parameters.
+
+    Parameter conversion uses optimization as described in [1]_ to fit the
+    PVsyst model to :math:`I_{sc}`, :math:`V_{oc}`, :math:`V_{mp}`,
+    :math:`I_{mp}`, and :math:`P_{mp}`, calculated using the input CEC model
+    at the IEC 61853-3 conditions [2]_.
+
+    Parameters
+    ----------
+    cec_model : dict or DataFrame
+        Must include keys: 'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
+        'R_sh_ref', 'R_s', 'Adjust'
+    cell_in_series : int
+        Number of cells in series.
+    method : str, default 'Nelder-Mead'
+        Method for scipy.optimize.minimize.
+    options : dict, optional
+        Solver options passed to scipy.optimize.minimize.
+
+    Returns
+    -------
+    dict with the following elements:
+        alpha_sc : float
+            Short-circuit current temperature coefficient [A/C] .
+        I_L_ref : float
+            The light-generated current (or photocurrent) at reference
+            conditions [A].
+        I_o_ref : float
+            The dark or diode reverse saturation current at reference
+            conditions [A].
+        EgRef : float
+            The energy bandgap at reference temperature [eV].
+        R_s : float
+            The series resistance at reference conditions [ohm].
+        R_sh_ref : float
+            The shunt resistance at reference conditions [ohm].
+        R_sh_0 : float
+            Shunt resistance at zero irradiance [ohm].
+        R_sh_exp : float
+            Exponential factor defining decrease in shunt resistance with
+            increasing effective irradiance [unitless].
+        gamma_ref : float
+            Diode (ideality) factor at reference conditions [unitless].
+        mu_gamma : float
+            Temperature coefficient for diode (ideality) factor at reference
+            conditions [1/K].
+        cells_in_series : int
+            Number of cells in series.
+
+    Notes
+    -----
+    Reference conditions are irradiance of 1000 W/m⁻² and cell temperature of
+    25 °C.
+
+    See Also
+    --------
+    pvlib.ivtools.sdm.convert_pvsyst_cec
+
+    References
+    ----------
+    .. [1] L. Deville et al., "Parameter Translation for Photovoltaic Single
+       Diode Models", submitted. 2024
+
+    .. [2] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy
+       rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018.
+    """
+    if options is None:
+        options = {'maxiter': 5000, 'maxfev': 5000, 'xatol': 0.001}
+
+    # calculate target IV curve values
+    cec_params = calcparams_cec(
+        IEC61853['effective_irradiance'],
+        IEC61853['temp_cell'],
+        **cec_model)
+    cec_ivs = singlediode(*cec_params)
+
+    # initial guess at PVsyst parameters
+    # Order in list is alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref,
+    # Rsh_mult = R_sh_0 / R_sh_ref, R_sh_ref, R_s
+    initial = [0, 1.2, 0.001, cec_model['I_L_ref'], cec_model['I_o_ref'],
+               12, 1000, cec_model['R_s']]
+
+    # bounds for PVsyst parameters
+    b_alpha = (-1, 1)
+    b_gamma = (1, 2)
+    b_mu = (-1, 1)
+    b_IL = (1e-12, 100)
+    b_Io = (1e-24, 0.1)
+    b_Rmult = (1, 20)
+    b_Rsh = (100, 1e6)
+    b_Rs = (1e-12, 10)
+    bounds = [b_alpha, b_gamma, b_mu, b_IL, b_Io, b_Rmult, b_Rsh, b_Rs]
+
+    # optimization to find PVsyst parameters
+    result = optimize.minimize(
+        _pvsyst_objfun, initial,
+        args=(cec_ivs, IEC61853['effective_irradiance'],
+              IEC61853['temp_cell'], cells_in_series),
+        method='Nelder-Mead',
+        bounds=bounds,
+        options=options)
+
+    alpha_sc, gamma, mu_gamma, I_L_ref, I_o_ref, Rsh_mult, R_sh_ref, R_s = \
+        result.x
+
+    R_sh_0 = Rsh_mult * R_sh_ref
+    R_sh_exp = 5.5
+    EgRef = 1.121  # default for all modules in the CEC model
+    return {'alpha_sc': alpha_sc,
+            'I_L_ref': I_L_ref, 'I_o_ref': I_o_ref, 'EgRef': EgRef, 'R_s': R_s,
+            'R_sh_ref': R_sh_ref, 'R_sh_0': R_sh_0, 'R_sh_exp': R_sh_exp,
+            'gamma_ref': gamma, 'mu_gamma': mu_gamma,
+            'cells_in_series': cells_in_series,
+            }
+
+
+def _cec_objfun(cec_mod, pvs_ivs, ee, tc, alpha_sc):
+    # translate the guess into named args that are used in the functions
+    # order : [I_L_ref, I_o_ref, a_ref, R_sh_ref, R_s, alpha_sc, Adjust]
+    # pvs_ivs : DataFrame with columns i_sc, v_oc, i_mp, v_mp, p_mp
+    # ee : effective irradiance
+    # tc : cell temperature
+    # alpha_sc : temperature coefficient for Isc
+    I_L_ref = cec_mod[0]
+    I_o_ref = cec_mod[1]
+    a_ref = cec_mod[2]
+    R_sh_ref = cec_mod[3]
+    R_s = cec_mod[4]
+    Adjust = cec_mod[5]
+    alpha_sc = alpha_sc
+
+    cec_params = calcparams_cec(
+        ee, tc, alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, Adjust)
+    cec_ivs = singlediode(*cec_params)
+
+    isc_rss = np.sqrt(sum((cec_ivs['i_sc'] - pvs_ivs['i_sc'])**2))
+    imp_rss = np.sqrt(sum((cec_ivs['i_mp'] - pvs_ivs['i_mp'])**2))
+    voc_rss = np.sqrt(sum((cec_ivs['v_oc'] - pvs_ivs['v_oc'])**2))
+    vmp_rss = np.sqrt(sum((cec_ivs['v_mp'] - pvs_ivs['v_mp'])**2))
+    pmp_rss = np.sqrt(sum((cec_ivs['p_mp'] - pvs_ivs['p_mp'])**2))
+
+    mean_diff = (isc_rss+imp_rss+voc_rss+vmp_rss+pmp_rss) / 5
+
+    return mean_diff
+
+
+def convert_pvsyst_cec(pvsyst_model, method='Nelder-Mead', options=None):
+    r"""
+    Convert a set of PVsyst model parameters to an equivalent set of CEC model
+    parameters.
+
+    Parameter conversion uses optimization as described in [1]_ to fit the
+    CEC model to :math:`I_{sc}`, :math:`V_{oc}`, :math:`V_{mp}`,
+    :math:`I_{mp}`, and :math:`P_{mp}`, calculated using the input PVsyst model
+    at the IEC 61853-3 conditions [2]_.
+
+    Parameters
+    ----------
+    pvsyst_model : dict or DataFrame
+        Must include keys: 'alpha_sc', 'I_L_ref', 'I_o_ref', 'EgRef', 'R_s',
+        'R_sh_ref', 'R_sh_0', 'R_sh_exp', 'gamma_ref', 'mu_gamma',
+        'cells_in_series'
+    method : str, default 'Nelder-Mead'
+        Method for scipy.optimize.minimize.
+    options : dict, optional
+        Solver options passed to scipy.optimize.minimize.
+
+    Returns
+    -------
+    dict with the following elements:
+        I_L_ref : float
+            The light-generated current (or photocurrent) at reference
+            conditions [A].
+        I_o_ref : float
+            The dark or diode reverse saturation current at reference
+            conditions [A].
+        R_s : float
+            The series resistance at reference conditions [ohm].
+        R_sh_ref : float
+            The shunt resistance at reference conditions [ohm].
+        a_ref : float
+            The product of the usual diode ideality factor ``n`` (unitless),
+            number of cells in series ``Ns``, and cell thermal voltage at
+            reference conditions [V].
+        Adjust : float
+            The adjustment to the temperature coefficient for short circuit
+            current, in percent.
+        EgRef : float
+            The energy bandgap at reference temperature [eV].
+        dEgdT : float
+            The temperature dependence of the energy bandgap at reference
+            conditions [1/K].
+
+    Notes
+    -----
+    Reference conditions are irradiance of 1000 W/m⁻² and cell temperature of
+    25 °C.
+
+    See Also
+    --------
+    pvlib.ivtools.sdm.convert_cec_pvsyst
+
+    References
+    ----------
+    .. [1] L. Deville et al., "Parameter Translation for Photovoltaic Single
+       Diode Models", submitted. 2024.
+
+    .. [2] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy
+       rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018.
+    """
+
+    if options is None:
+        options = {'maxiter': 5000, 'maxfev': 5000, 'xatol': 0.001}
+
+    # calculate target IV curve values
+    pvs_params = calcparams_pvsyst(
+        IEC61853['effective_irradiance'],
+        IEC61853['temp_cell'],
+        **pvsyst_model)
+    pvsyst_ivs = singlediode(*pvs_params)
+
+    # set EgRef and dEgdT to CEC defaults
+    EgRef = 1.121
+    dEgdT = -0.0002677
+
+    # initial guess
+    # order must match _pvsyst_objfun
+    # order : [I_L_ref, I_o_ref, a_ref, R_sh_ref, R_s, alpha_sc, Adjust]
+    nNsVth = pvsyst_model['gamma_ref'] * pvsyst_model['cells_in_series'] \
+        * 0.025
+    initial = [pvsyst_model['I_L_ref'], pvsyst_model['I_o_ref'],
+               nNsVth, pvsyst_model['R_sh_ref'], pvsyst_model['R_s'],
+               0]
+
+    # bounds for PVsyst parameters
+    b_IL = (1e-12, 100)
+    b_Io = (1e-24, 0.1)
+    b_aref = (1e-12, 1000)
+    b_Rsh = (100, 1e6)
+    b_Rs = (1e-12, 10)
+    b_Adjust = (-100, 100)
+    bounds = [b_IL, b_Io, b_aref, b_Rsh, b_Rs, b_Adjust]
+
+    result = optimize.minimize(
+        _cec_objfun, initial,
+        args=(pvsyst_ivs, IEC61853['effective_irradiance'],
+              IEC61853['temp_cell'], pvsyst_model['alpha_sc']),
+        method='Nelder-Mead',
+        bounds=bounds,
+        options=options)
+
+    I_L_ref, I_o_ref, a_ref, R_sh_ref, R_s, Adjust = result.x
+
+    return {'alpha_sc': pvsyst_model['alpha_sc'],
+            'a_ref': a_ref, 'I_L_ref': I_L_ref, 'I_o_ref': I_o_ref,
+            'R_sh_ref': R_sh_ref, 'R_s': R_s, 'Adjust': Adjust,
+            'EgRef': EgRef, 'dEgdT': dEgdT
+            }
diff --git a/pvlib/tests/ivtools/test_sdm.py b/pvlib/tests/ivtools/test_sdm.py
index d4cc7db141..5c0b4091d8 100644
--- a/pvlib/tests/ivtools/test_sdm.py
+++ b/pvlib/tests/ivtools/test_sdm.py
@@ -6,7 +6,6 @@
 
 from pvlib.ivtools import sdm
 from pvlib import pvsystem
-from pvlib._deprecation import pvlibDeprecationWarning
 
 from pvlib.tests.conftest import requires_pysam, requires_statsmodels
 
@@ -405,3 +404,49 @@ def test_pvsyst_temperature_coeff():
         params['I_L_ref'], params['I_o_ref'], params['R_sh_ref'],
         params['R_sh_0'], params['R_s'], params['cells_in_series'])
     assert_allclose(gamma_pdc, expected, rtol=0.0005)
+
+
+def test_convert_cec_pvsyst():
+    cells_in_series = 66
+    trina660_cec = {'I_L_ref': 18.4759, 'I_o_ref': 5.31e-12,
+                    'EgRef': 1.121, 'dEgdT': -0.0002677,
+                    'R_s': 0.159916, 'R_sh_ref': 113.991, 'a_ref': 1.59068,
+                    'Adjust': 6.42247, 'alpha_sc': 0.00629}
+    trina660_pvsyst_est = sdm.convert_cec_pvsyst(trina660_cec,
+                                                 cells_in_series)
+    pvsyst_expected = {'alpha_sc': 0.007478218748188788,
+                       'I_L_ref': 18.227679597516214,
+                       'I_o_ref': 2.7418999402908e-11,
+                       'EgRef': 1.121,
+                       'R_s': 0.16331908293164496,
+                       'R_sh_ref': 5267.928954454954,
+                       'R_sh_0': 60171.206687871425,
+                       'R_sh_exp': 5.5,
+                       'gamma_ref': 1.0,
+                       'mu_gamma': -6.349173477135307e-05,
+                       'cells_in_series': 66}
+
+    assert np.all([np.isclose(trina660_pvsyst_est[k], pvsyst_expected[k],
+                              rtol=1e-3)
+                   for k in pvsyst_expected])
+
+
+def test_convert_pvsyst_cec():
+    trina660_pvsyst = {'alpha_sc': 0.0074, 'I_L_ref': 18.464391,
+                       'I_o_ref': 3.3e-11, 'EgRef': 1.121,
+                       'R_s': 0.156, 'R_sh_ref': 200, 'R_sh_0': 800,
+                       'R_sh_exp': 5.5, 'gamma_ref': 1.002, 'mu_gamma': 1e-3,
+                       'cells_in_series': 66}
+    trina660_cec_est = sdm.convert_pvsyst_cec(trina660_pvsyst)
+    cec_expected = {'alpha_sc': 0.0074,
+                    'I_L_ref': 18.05154226834071,
+                    'I_o_ref': 2.6863417875143392e-14,
+                    'EgRef': 1.121,
+                    'dEgdT': -0.0002677,
+                    'R_s': 0.09436341848926795,
+                    'a_ref': 1.2954800250731866,
+                    'Adjust': 0.0011675969492410047}
+
+    assert np.all([np.isclose(trina660_cec_est[k], cec_expected[k],
+                              rtol=1e-3)
+                   for k in cec_expected])