diff --git a/bilby/gw/likelihood.py b/bilby/gw/likelihood.py
index ad1a4063a6aeb0d10486da7c8c79d5c86263ed26..37d711114cf04dd6442b489519d0a38194cb285f 100644
--- a/bilby/gw/likelihood.py
+++ b/bilby/gw/likelihood.py
@@ -6,7 +6,7 @@ import copy
 import numpy as np
 import pandas as pd
 from scipy.interpolate import interp1d
-from scipy.special import logsumexp, i0e
+from scipy.special import logsumexp
 
 from ..core.likelihood import Likelihood
 from ..core.utils import BilbyJsonEncoder, decode_bilby_json
@@ -18,7 +18,9 @@ from .detector import InterferometerList, get_empty_interferometer, calibration
 from .prior import BBHPriorDict, CBCPriorDict, Cosmological
 from .source import lal_binary_black_hole
 from .utils import (
-    noise_weighted_inner_product, build_roq_weights, zenith_azimuth_to_ra_dec)
+    noise_weighted_inner_product, build_roq_weights, zenith_azimuth_to_ra_dec,
+    ln_i0
+)
 from .waveform_generator import WaveformGenerator
 from collections import namedtuple
 
@@ -173,8 +175,6 @@ class GravitationalWaveTransient(Likelihood):
 
         if self.phase_marginalization:
             self._check_marginalized_prior_is_set(key='phase')
-            self._bessel_function_interped = None
-            self._setup_phase_marginalization()
             priors['phase'] = float(0)
             self._marginalized_parameters.append('phase')
 
@@ -574,8 +574,7 @@ class GravitationalWaveTransient(Likelihood):
             time_log_like = self.distance_marginalized_likelihood(
                 d_inner_h, h_inner_h)
         elif self.phase_marginalization:
-            time_log_like = (self._bessel_function_interped(abs(d_inner_h)) -
-                             h_inner_h.real / 2)
+            time_log_like = ln_i0(abs(d_inner_h)) - h_inner_h.real / 2
         else:
             time_log_like = (d_inner_h.real - h_inner_h.real / 2)
 
@@ -630,8 +629,9 @@ class GravitationalWaveTransient(Likelihood):
 
         if self.phase_marginalization:
             distance_log_like = (
-                self._bessel_function_interped(abs(d_inner_h_dist)) -
-                h_inner_h_dist.real / 2)
+                ln_i0(abs(d_inner_h_dist)) -
+                h_inner_h_dist.real / 2
+            )
         else:
             distance_log_like = (d_inner_h_dist.real - h_inner_h_dist.real / 2)
 
@@ -702,7 +702,7 @@ class GravitationalWaveTransient(Likelihood):
             d_inner_h_ref, h_inner_h_ref)
 
     def phase_marginalized_likelihood(self, d_inner_h, h_inner_h):
-        d_inner_h = self._bessel_function_interped(abs(d_inner_h))
+        d_inner_h = ln_i0(abs(d_inner_h))
 
         if self.calibration_marginalization and self.time_marginalization:
             return d_inner_h - np.outer(h_inner_h, np.ones(np.shape(d_inner_h)[1])) / 2
@@ -921,9 +921,7 @@ class GravitationalWaveTransient(Likelihood):
         d_inner_h_array_full = np.outer(self._d_inner_h_ref_array, scaling)
         h_inner_h_array_full = np.outer(self._optimal_snr_squared_ref_array, scaling ** 2)
         if self.phase_marginalization:
-            d_inner_h_array_full = self._bessel_function_interped(abs(
-                d_inner_h_array_full
-            ))
+            d_inner_h_array_full = ln_i0(abs(d_inner_h_array_full))
         prior_term = self.distance_prior_array * self._delta_distance
         for ii, optimal_snr_squared_array in tqdm(
             enumerate(h_inner_h_array_full), total=len(self._optimal_snr_squared_ref_array)
@@ -940,11 +938,20 @@ class GravitationalWaveTransient(Likelihood):
         self.cache_lookup_table()
 
     def _setup_phase_marginalization(self, min_bound=-5, max_bound=10):
-        x_values = np.logspace(min_bound, max_bound, int(1e6))
-        self._bessel_function_interped = interp1d(
-            x_values, x_values + np.log([i0e(snr) for snr in x_values]),
-            bounds_error=False, fill_value=(0, np.nan)
+        logger.warning(
+            "The _setup_phase_marginalization method is deprecated and will be removed, "
+            "please update the implementation of phase marginalization "
+            "to use bilby.gw.utils.ln_i0"
+        )
+
+    @staticmethod
+    def _bessel_function_interped(xx):
+        logger.warning(
+            "The _bessel_function_interped method is deprecated and will be removed, "
+            "please update the implementation of phase marginalization "
+            "to use bilby.gw.utils.ln_i0"
         )
+        return ln_i0(xx) + xx
 
     def _setup_time_marginalization(self):
         self._delta_tc = 2 / self.waveform_generator.sampling_frequency
diff --git a/bilby/gw/utils.py b/bilby/gw/utils.py
index ab8c69ee8166c5f66a9dc1c05d32a972ea80b160..9fb3661c06bda4d81def0f7db508b8d43b8c017f 100644
--- a/bilby/gw/utils.py
+++ b/bilby/gw/utils.py
@@ -4,6 +4,7 @@ from math import fmod
 
 import numpy as np
 from scipy.interpolate import interp1d
+from scipy.special import i0e
 
 from ..core.utils import (ra_dec_to_theta_phi,
                           speed_of_light, logger, run_commandline,
@@ -987,3 +988,21 @@ def greenwich_mean_sidereal_time(time):
     from lal import GreenwichMeanSiderealTime
     time = float(time)
     return GreenwichMeanSiderealTime(time)
+
+
+def ln_i0(value):
+    """
+    A numerically stable method to evaluate ln(I_0) a modified Bessel function
+    of order 0 used in the phase-marginalized likelihood.
+
+    Parameters
+    ==========
+    value: array-like
+        Value(s) at which to evaluate the function
+
+    Returns
+    =======
+    array-like:
+        The natural logarithm of the bessel function
+    """
+    return np.log(i0e(value)) + value