diff --git a/mbtrack2/impedance/impedance_model.py b/mbtrack2/impedance/impedance_model.py
index bc3da3c0f8f7b3bb2794e580668c1efdc1783239..cf586387aea1e5dd7d78f23ee23ec373df9eab9a 100644
--- a/mbtrack2/impedance/impedance_model.py
+++ b/mbtrack2/impedance/impedance_model.py
@@ -102,8 +102,6 @@ class ImpedanceModel():
         None.
 
         """
-        self.wakefields.append(wakefield)
-        self.positions.append(positions)
         if name is None:
             name = wakefield.name
         if name is None:
@@ -112,6 +110,8 @@ class ImpedanceModel():
             self.names.append(name)
         else:
             raise ValueError("This name is already taken.")
+        self.wakefields.append(wakefield)
+        self.positions.append(positions)
 
     def add_global(self, wakefield, name=None):
         """
diff --git a/mbtrack2/impedance/wakefield.py b/mbtrack2/impedance/wakefield.py
index 5de4a8fffb9ecf70a7feb9f14a1a1347ba8d1e5a..31712518626ca947d6faedfee0219d01d1a90876 100644
--- a/mbtrack2/impedance/wakefield.py
+++ b/mbtrack2/impedance/wakefield.py
@@ -277,6 +277,8 @@ class WakeFunction(ComplexData):
         Compute a wake function from wake potential data.
     plot()
         Plot the wake function data.
+    loss_factor(sigma)
+        Compute the loss factor or the kick factor for a Gaussian bunch.
     """
 
     def __init__(self,
@@ -454,6 +456,34 @@ class WakeFunction(ComplexData):
         label = r"$W_{" + self.component_type + r"}$" + unit
         ax.set_ylabel(label)
         return ax
+    
+    def loss_factor(self, sigma):
+        """
+        Compute the loss factor or the kick factor for a Gaussian bunch. 
+        Formulas from Eq. (5.6), Eq. (5.12) and Eq. (5.17) of [1].
+        
+        Parameters
+        ----------
+        sigma : float
+            RMS bunch length in [s]
+        
+        Returns
+        -------
+        kloss: float
+            Loss factor in [V/C] or kick factor in [V/C/m] depanding on the 
+            impedance type.
+            
+        References
+        ----------
+        [1] : Zotter, Bruno W., and Semyon A. Kheifets. Impedances and wakes 
+        in high-energy particle accelerators. World Scientific, 1998.
+        
+        """
+        time = self.data.index
+        S = 1/(2*np.sqrt(np.pi)*sigma)*np.exp(-1*time**2/(4*sigma**2))
+        kloss = trapz(x = time, y = self.data["real"]*S)
+
+        return kloss
         
 class Impedance(ComplexData):
     """
diff --git a/mbtrack2/tracking/parallel.py b/mbtrack2/tracking/parallel.py
index 30f835b413adfd02aef6a9f4aeabf860f0fa0cc5..b71cf4d66d6f5661bee12c17a177f02c8cf689cb 100644
--- a/mbtrack2/tracking/parallel.py
+++ b/mbtrack2/tracking/parallel.py
@@ -48,13 +48,16 @@ class Mpi:
         Compute the bunch profiles and share it between the different bunches.
     share_means(beam)
         Compute the bunch means and share it between the different bunches.
+    share_stds(beam)
+        Compute the bunch standard deviations and share it between the 
+        different bunches.
         
     References
     ----------
     [1] L. Dalcin, P. Kler, R. Paz, and A. Cosimo, Parallel Distributed 
     Computing using Python, Advances in Water Resources, 34(9):1124-1139, 2011.
-    """
     
+    """
     def __init__(self, filling_pattern):
         from mpi4py import MPI
         self.MPI = MPI
@@ -214,4 +217,29 @@ class Mpi:
         else:
             mean = np.zeros((6,), dtype=np.float64)
         self.comm.Allgather([mean, self.MPI.DOUBLE], [self.mean_all, self.MPI.DOUBLE])
+        
+    def share_stds(self, beam):
+        """
+        Compute the bunch standard deviations and share it between the 
+        different bunches.
+
+        Parameters
+        ----------
+        beam : Beam object
+
+        """
+        if(beam.mpi_switch == False):
+            print("Error, mpi is not initialised.")
+            
+        bunch = beam[self.bunch_num]
+        
+        charge_all = self.comm.allgather(bunch.charge)
+        self.charge_all = charge_all
+        
+        self.std_all = np.empty((self.size, 6), dtype=np.float64)
+        if len(bunch) != 0:
+            std = bunch.std
+        else:
+            std = np.zeros((6,), dtype=np.float64)
+        self.comm.Allgather([std, self.MPI.DOUBLE], [self.std_all, self.MPI.DOUBLE])
                                 
\ No newline at end of file
diff --git a/mbtrack2/tracking/particles.py b/mbtrack2/tracking/particles.py
index 9dfd6910fb1baa41950d9dea10eaf7b4b3063740..e663ee0ac563c871951452098a1d4565a1226237 100644
--- a/mbtrack2/tracking/particles.py
+++ b/mbtrack2/tracking/particles.py
@@ -119,12 +119,12 @@ class Bunch:
             current = 0
         self._mp_number = int(mp_number)
         
-        self.dtype = np.dtype([('x',np.float),
-                       ('xp',np.float),
-                       ('y',np.float),
-                       ('yp',np.float),
-                       ('tau',np.float),
-                       ('delta',np.float)])
+        self.dtype = np.dtype([('x', float),
+                       ('xp', float),
+                       ('y', float),
+                       ('yp', float),
+                       ('tau', float),
+                       ('delta', float)])
         
         self.particles = np.zeros(self.mp_number, self.dtype)
         self.track_alive = track_alive
diff --git a/mbtrack2/tracking/rf.py b/mbtrack2/tracking/rf.py
index aa4eb68562a3165ba2a3e2f81d19dbcde970670d..69a1c20f28f74503f9a11ab24ccc68a187418086 100644
--- a/mbtrack2/tracking/rf.py
+++ b/mbtrack2/tracking/rf.py
@@ -200,8 +200,8 @@ class CavityResonator():
         self.detune = detune
         self.Vc = Vc
         self.theta = theta
-        self.beam_phasor = np.zeros(1, dtype=np.complex)
-        self.beam_phasor_record = np.zeros((self.ring.h), dtype=np.complex)
+        self.beam_phasor = np.zeros(1, dtype=complex)
+        self.beam_phasor_record = np.zeros((self.ring.h), dtype=complex)
         self.tracking = False
         self.Vg = 0
         self.theta_g = 0
diff --git a/mbtrack2/tracking/wakepotential.py b/mbtrack2/tracking/wakepotential.py
index 14ac15167630cda3e042d5b623fe3e9b80a3532a..19bee813701ab7a7d27299a7f271e2ad23c99f3b 100644
--- a/mbtrack2/tracking/wakepotential.py
+++ b/mbtrack2/tracking/wakepotential.py
@@ -70,7 +70,7 @@ class WakePotential(Element):
         
     """
     
-    def __init__(self, ring, wakefield, n_bin=65):
+    def __init__(self, ring, wakefield, n_bin=80):
         self.wakefield = wakefield
         self.types = self.wakefield.wake_components
         self.n_types = len(self.wakefield.wake_components)
@@ -793,7 +793,7 @@ class LongRangeResistiveWall(Element):
         for wake_type in self.types:
             kick = self.get_kick(rank, wake_type)
             if wake_type == "Wlong":
-                bunch["delta"] += kick / self.ring.E0
+                bunch["delta"] -= kick / self.ring.E0
             elif wake_type == "Wxdip":
                 bunch["xp"] += kick / self.ring.E0
             elif wake_type == "Wydip":
diff --git a/mbtrack2/utilities/misc.py b/mbtrack2/utilities/misc.py
index 93332b83e708819e13fa424c3da624997bc90542..2a2bd27b36860ef39f1a6d6bd3c485741ecf13fc 100644
--- a/mbtrack2/utilities/misc.py
+++ b/mbtrack2/utilities/misc.py
@@ -9,13 +9,14 @@ from pathlib import Path
 from scipy.interpolate import interp1d
 from mbtrack2.impedance.wakefield import Impedance
 from mbtrack2.utilities.spectrum import spectral_density
-    
-def effective_impedance(ring, imp, m, mu, sigma, M, tuneS, xi=None, 
+
+
+def effective_impedance(ring, imp, m, mu, sigma, M, tuneS, xi=None,
                         mode="Hermite"):
     """
     Compute the effective (longitudinal or transverse) impedance. 
     Formulas from Eq. (1) and (2) p238 of [1].
-    
+
     Parameters
     ----------
     ring : Synchrotron object
@@ -42,61 +43,112 @@ def effective_impedance(ring, imp, m, mu, sigma, M, tuneS, xi=None,
     Zeff : float 
         effective impedance in [ohm] or in [ohm/m] depanding on the impedance
         type.
-        
+
     References
     ----------
     [1] : Handbook of accelerator physics and engineering, 3rd printing.
     """
-    
+
     if not isinstance(imp, Impedance):
         raise TypeError("{} should be an Impedance object.".format(imp))
-        
+
     fmin = imp.data.index.min()
     fmax = imp.data.index.max()
     if fmin > 0:
         double_sided_impedance(imp)
-        
-    if mode == "Hermite":
+
+    if mode in ["Hermite", "Legendre", "Sinusoidal", "Sacherer", "Chebyshev"]:
         def h(f):
             return spectral_density(frequency=f, sigma=sigma, m=m,
-                                    mode="Hermite")
+                                    mode=mode)
     else:
         raise NotImplementedError("Not implemanted yet.")
-    
-    pmax = fmax/(ring.f0 * M) - 1
-    pmin = fmin/(ring.f0 * M) + 1
-    
-    p = np.arange(pmin,pmax+1)
-    
+
     if imp.component_type == "long":
+        pmax = fmax/(ring.f0 * M) - 1
+        pmin = fmin/(ring.f0 * M) + 1
+        p = np.arange(pmin, pmax+1)
+
         fp = ring.f0*(p*M + mu + m*tuneS)
-        fp = fp[np.nonzero(fp)] # Avoid division by 0
-        num = np.sum( imp(fp) * h(fp) / (fp*2*np.pi) )
-        den = np.sum( h(fp) )
+        fp = fp[np.nonzero(fp)]  # Avoid division by 0
+        num = np.sum(imp(fp) * h(fp) / (fp*2*np.pi))
+        den = np.sum(h(fp))
         Zeff = num/den
-        
+
     elif imp.component_type == "xdip" or imp.component_type == "ydip":
         if imp.component_type == "xdip":
-            tuneXY = ring.tune[0]
-            if xi is None :
+            tuneXY = ring.tune[0]-np.floor(ring.tune[0])
+            if xi is None:
                 xi = ring.chro[0]
         elif imp.component_type == "ydip":
-            tuneXY = ring.tune[1]
+            tuneXY = ring.tune[1]-np.floor(ring.tune[1])
             if xi is None:
                 xi = ring.chro[1]
+        pmax = fmax/(ring.f0 * M) - 1
+        pmin = fmin/(ring.f0 * M) + 1
+        p = np.arange(pmin, pmax+1)
         fp = ring.f0*(p*M + mu + tuneXY + m*tuneS)
         f_xi = xi/ring.eta*ring.f0
-        num = np.sum( imp(fp) * h(fp - f_xi) )
-        den = np.sum( h(fp - f_xi) )
+        num = np.sum(imp(fp) * h(fp - f_xi))
+        den = np.sum(h(fp - f_xi))
         Zeff = num/den
     else:
         raise TypeError("Effective impedance is only defined for long, xdip"
                         " and ydip impedance type.")
-        
+
     return Zeff
 
 
-def yokoya_elliptic(x_radius , y_radius):
+def head_tail_form_factor(ring, imp, m, sigma, tuneS, xi=None, mode="Hermite", mu=0):
+    M = 1
+    if not isinstance(imp, Impedance):
+        raise TypeError("{} should be an Impedance object.".format(imp))
+
+    fmin = imp.data.index.min()
+    fmax = imp.data.index.max()
+    if fmin > 0:
+        double_sided_impedance(imp)
+
+    if mode in ["Hermite", "Legendre", "Sinusoidal", "Sacherer", "Chebyshev"]:
+        def h(f):
+            return spectral_density(frequency=f, sigma=sigma, m=m,
+                                    mode=mode)
+    else:
+        raise NotImplementedError("Not implemanted yet.")
+
+    pmax = np.floor(fmax/(ring.f0 * M))
+    pmin = np.ceil(fmin/(ring.f0 * M))
+
+    p = np.arange(pmin, pmax+1)
+
+    if imp.component_type == "long":
+        fp = ring.f0*(p*M + mu + m*tuneS)
+        fp = fp[np.nonzero(fp)]  # Avoid division by 0
+        den = np.sum(h(fp))
+
+    elif imp.component_type == "xdip" or imp.component_type == "ydip":
+        if imp.component_type == "xdip":
+            tuneXY = ring.tune[0]-np.floor(ring.tune[0])
+            if xi is None:
+                xi = ring.chro[0]
+        elif imp.component_type == "ydip":
+            tuneXY = ring.tune[1]-np.floor(ring.tune[0])
+            if xi is None:
+                xi = ring.chro[1]
+        fp = ring.f0*(p*M + mu + tuneXY + m*tuneS)
+        f_xi = xi/ring.eta*ring.f0
+        den = np.sum(h(fp - f_xi))
+    else:
+        raise TypeError("Effective impedance is only defined for long, xdip"
+                        " and ydip impedance type.")
+
+    return den
+
+
+def tune_shift_from_effective_impedance(Zeff):
+    pass
+
+def yokoya_elliptic(x_radius, y_radius):
     """
     Compute Yokoya factors for an elliptic beam pipe.
     Function adapted from N. Mounet IW2D.
@@ -127,7 +179,7 @@ def yokoya_elliptic(x_radius , y_radius):
     else:
         small_semiaxis = x_radius
         large_semiaxis = y_radius
-        
+
     path_to_file = Path(__file__).parent
     file = path_to_file / "data" / "Yokoya_elliptic_from_Elias_USPAS.csv"
 
@@ -140,7 +192,7 @@ def yokoya_elliptic(x_radius , y_radius):
 
     # interpolate Yokoya file at the correct ratio
     yoklong = 1
-    
+
     if y_radius < x_radius:
         yokydip = np.interp(ratio, ratio_col, yokoya_file["dipy"])
         yokxdip = np.interp(ratio, ratio_col, yokoya_file["dipx"])
@@ -150,10 +202,11 @@ def yokoya_elliptic(x_radius , y_radius):
         yokxdip = np.interp(ratio, ratio_col, yokoya_file["dipy"])
         yokydip = np.interp(ratio, ratio_col, yokoya_file["dipx"])
         yokxquad = np.interp(ratio, ratio_col, yokoya_file["quady"])
-        yokyquad = np.interp(ratio, ratio_col, yokoya_file["quadx"])        
+        yokyquad = np.interp(ratio, ratio_col, yokoya_file["quadx"])
 
     return (yoklong, yokxdip, yokydip, yokxquad, yokyquad)
 
+
 def beam_loss_factor(impedance, frequency, spectrum, ring):
     """
     Compute "beam" loss factor using the beam spectrum, uses a sum instead of 
@@ -172,7 +225,7 @@ def beam_loss_factor(impedance, frequency, spectrum, ring):
     -------
     kloss_beam : float
         Beam loss factor in [V/C].
-        
+
     References
     ----------
     [1] : Handbook of accelerator physics and engineering, 3rd printing. 
@@ -180,24 +233,25 @@ def beam_loss_factor(impedance, frequency, spectrum, ring):
     """
     pmax = np.floor(impedance.data.index.max()/ring.f0)
     pmin = np.floor(impedance.data.index.min()/ring.f0)
-    
+
     if pmin >= 0:
         double_sided_impedance(impedance)
         pmin = -1*pmax
-    
-    p = np.arange(pmin+1,pmax)    
+
+    p = np.arange(pmin+1, pmax)
     pf0 = p*ring.f0
     ReZ = np.real(impedance(pf0))
     spectral_density = np.abs(spectrum)**2
-    # interpolation of the spectrum is needed to avoid problems liked to 
+    # interpolation of the spectrum is needed to avoid problems liked to
     # division by 0
     # computing the spectrum directly to the frequency points gives
     # wrong results
     spect = interp1d(frequency, spectral_density)
     kloss_beam = ring.f0 * np.sum(ReZ*spect(pf0))
-    
+
     return kloss_beam
 
+
 def double_sided_impedance(impedance):
     """
     Add negative frequency points to single sided impedance spectrum following
@@ -209,31 +263,30 @@ def double_sided_impedance(impedance):
         Single sided impedance.
     """
     fmin = impedance.data.index.min()
-    
+
     if fmin >= 0:
         negative_index = impedance.data.index*-1
         negative_data = impedance.data.set_index(negative_index)
-        
+
         imp_type = impedance.component_type
-        
+
         if imp_type == "long":
             negative_data["imag"] = -1*negative_data["imag"]
-            
+
         elif (imp_type == "xdip") or (imp_type == "ydip"):
             negative_data["real"] = -1*negative_data["real"]
-        
+
         elif (imp_type == "xquad") or (imp_type == "yquad"):
             negative_data["real"] = -1*negative_data["real"]
-            
+
         else:
             raise ValueError("Wrong impedance type")
-            
+
         try:
             negative_data = negative_data.drop(0)
         except KeyError:
             pass
-            
+
         all_data = impedance.data.append(negative_data)
         all_data = all_data.sort_index()
         impedance.data = all_data
-        
diff --git a/mbtrack2/utilities/read_impedance.py b/mbtrack2/utilities/read_impedance.py
index 195f0118c376b845cad4cfd363e8b0eab1de2e93..a0550fee0c07f8e4c9e5b07fe27812afde017b2d 100644
--- a/mbtrack2/utilities/read_impedance.py
+++ b/mbtrack2/utilities/read_impedance.py
@@ -66,7 +66,7 @@ def read_CST(file, component_type='long', divide_by=None, imp=True):
     return result
 
 
-def read_IW2D(file, file_type='Zlong'):
+def read_IW2D(file, file_type='Zlong', output=False):
     """
     Read IW2D file format into an Impedance object or a WakeField object.
 
@@ -76,6 +76,9 @@ def read_IW2D(file, file_type='Zlong'):
         Path to the file to read.
     file_type : str, optional
         Type of the Impedance or WakeField object.
+    output : bool, optional
+        If True, print out the interpolated values.
+        Default is False.
 
     Returns
     -------
@@ -99,8 +102,9 @@ def read_IW2D(file, file_type='Zlong'):
         if np.any(df.isna()):
             index = df.isna().values
             df = df.interpolate()
-            print("Nan values have been interpolated to:")
-            print(df[index])
+            if output:
+                print("Nan values have been interpolated to:")
+                print(df[index])
         result = WakeFunction(variable=df.index,
                               function=df["Wake"],
                               component_type=file_type[1:])
@@ -109,7 +113,7 @@ def read_IW2D(file, file_type='Zlong'):
     return result
 
 
-def read_IW2D_folder(folder, suffix, select="WZ"):
+def read_IW2D_folder(folder, suffix, select="WZ", output=False):
     """
     Read IW2D results into a WakeField object.
 
@@ -123,6 +127,9 @@ def read_IW2D_folder(folder, suffix, select="WZ"):
     select : str, optional
         Select which object to load. "W" for WakeFunction, "Z" for Impedance
         and "WZ" or "ZW" for both.
+    output : bool, optional
+        If True, print out the interpolated values.
+        Default is False.
 
     Returns
     -------
@@ -148,7 +155,7 @@ def read_IW2D_folder(folder, suffix, select="WZ"):
     for key, item in types.items():
         for component in components:
             name = data_folder / (key + component + suffix)
-            res = read_IW2D(file=name, file_type=key + component)
+            res = read_IW2D(file=name, file_type=key + component, output=output)
             list_for_wakefield.append(res)
 
     wake = WakeField(list_for_wakefield)
@@ -156,7 +163,7 @@ def read_IW2D_folder(folder, suffix, select="WZ"):
     return wake
 
 
-def read_ABCI(file, azimuthal=False):
+def read_ABCI(file, azimuthal=False, output=False):
     """
     Read ABCI output files [1].
 
@@ -170,6 +177,9 @@ def read_ABCI(file, azimuthal=False):
         If False, it is loaded from the "TRANSVERSE" data. In that case, a -1
         factor is applied on the wake to agree with mbtrack2 sign convention.
         The default is False.
+    output : bool, optional
+        If True, print out the loaded components header.
+        Default is False.
 
     Returns
     -------
@@ -221,8 +231,7 @@ def read_ABCI(file, azimuthal=False):
                  f'  TITLE: {source} WAKE POTENTIAL               \n': 'Wxdip',
                  f'  TITLE: REAL PART OF {source} IMPEDANCE                        \n': 'Zxdip_re',
                  f'  TITLE: IMAGINARY PART OF {source} IMPEDANCE                   \n': 'Zxdip_im'}
-    impedance_type_specification_line = {
-        '   DATE:     TIME:      MROT:     NO. OF POINTS:\n'}
+
     wake_list = []
     start = True
     with open(file) as f:
@@ -238,7 +247,8 @@ def read_ABCI(file, azimuthal=False):
                 # read the header
                 header = [next(f) for _ in range(4)]
                 header.insert(0, line)
-            print(header)
+            if output:
+                print(header)
             # read the body until next TITLE field or end of file
             body = []
             while True:
@@ -263,8 +273,10 @@ def read_ABCI(file, azimuthal=False):
                         comp = _read_temp(tmp.name, abci_dict[header[0]])
                         wake_list.append(comp)
                     elif abci_dict[header[0]][1:] == "long" and impedance_type == 1:
-                        comp = _read_temp(tmp.name, abci_dict[header[0]]+'dip')
-                        wake_list.append(comp)
+                        pass
+                        # Wlongxdip & Wlongydip not implemented yet
+                        # comp = _read_temp(tmp.name, abci_dict[header[0]]+'dip')
+                        # wake_list.append(comp)
                     else:
                         comp_x = _read_temp(tmp.name, "Wxdip")
                         comp_y = _read_temp(tmp.name, "Wydip")
@@ -285,8 +297,10 @@ def read_ABCI(file, azimuthal=False):
                         comp = _read_temp(tmp1.name, "Zlong", tmp2.name)
                         wake_list.append(comp)
                     elif abci_dict[header[0]][1:-3] == "long" and impedance_type == 1:
-                        comp = _read_temp(tmp1.name, "Zlongdip", tmp2.name)
-                        wake_list.append(comp)
+                        pass
+                        # Zlongxdip & Zlongydip not implemented yet
+                        # comp = _read_temp(tmp1.name, "Zlongdip", tmp2.name)
+                        # wake_list.append(comp)
                     else:
                         comp_x = _read_temp(tmp1.name, "Zxdip", tmp2.name)
                         comp_y = _read_temp(tmp1.name, "Zydip", tmp2.name)
diff --git a/mbtrack2/utilities/spectrum.py b/mbtrack2/utilities/spectrum.py
index 91fba8d805e4ad9dce16ca12fd6d4770c9cededa..df78d64110cf84b337ef9b29bb6d043e835512d5 100644
--- a/mbtrack2/utilities/spectrum.py
+++ b/mbtrack2/utilities/spectrum.py
@@ -4,12 +4,14 @@ Module where bunch and beam spectrums and profile are defined.
 """
 
 import numpy as np
+from scipy.special import jv, spherical_jn
 
-def spectral_density(frequency, sigma, m = 1, mode="Hermite"):
+
+def spectral_density(frequency, sigma, m=1, k=0, mode="Hermite"):
     """
     Compute the spectral density of different modes for various values of the
     head-tail mode number, based on Table 1 p238 of [1].
-    
+
     Parameters
     ----------
     frequency : list or numpy array
@@ -18,26 +20,43 @@ def spectral_density(frequency, sigma, m = 1, mode="Hermite"):
         RMS bunch length in [s]
     m : int, optional
         head-tail (or azimutal/synchrotron) mode number
+    k : int, optional
+        radial mode number (such that |q|=m+2k, where |q| is the head-tail mode number)
     mode: str, optional
         type of the mode taken into account for the computation:
-        -"Hermite" modes for Gaussian bunches
+        -"Hermite" modes for Gaussian bunches (typical for electrons)
+        -"Chebyshev" for airbag bunches
+        -"Legendre" for parabolic bunches (typical for protons)
+        -"Sacherer" or "Sinusoidal" simplifying approximation of Legendre modes from [3]
 
     Returns
     -------
     numpy array
-    
+
     References
     ----------
     [1] : Handbook of accelerator physics and engineering, 3rd printing.
+    [2] : Ng, K. Y. (2005). Physics of intensity dependent beam instabilities. WORLD SCIENTIFIC. https://doi.org/10.1142/5835
+    [3] : Sacherer, F. J. (1972). Methods for computing bunched beam instabilities. CERN Tech. rep. CERN/SI-BR/72-5 https://cds.cern.ch/record/2291670?ln=en
     """
-    
+
     if mode == "Hermite":
-        return (2*np.pi*frequency*sigma)**(2*m)*np.exp(
-                -1*(2*np.pi*frequency*sigma)**2)
+        return 1/(np.math.factorial(m)*2**m)*(2*np.pi*frequency*sigma)**(2*m)*np.exp(
+            -(2*np.pi*frequency*sigma)**2)
+    elif mode == "Chebyshev":
+        tau_l = 4*sigma
+        return (jv(m, 2*np.pi*frequency*tau_l))**2
+    elif mode == "Legendre":
+        tau_l = 4*sigma
+        return (spherical_jn(m,  np.abs(2*np.pi*frequency*tau_l)))**2
+    elif mode == "Sacherer" or mode == "Sinusoidal":
+        y = 4*2*np.pi*frequency*sigma/np.pi
+        return (2*(m+1)/np.pi*1/np.abs(y**2-(m+1)**2)*np.sqrt(1+(-1)**m*np.cos(np.pi*y)))**2
     else:
         raise NotImplementedError("Not implemanted yet.")
-        
-def gaussian_bunch_spectrum(frequency, sigma): 
+
+
+def gaussian_bunch_spectrum(frequency, sigma):
     """
     Compute a Gaussian bunch spectrum [1].
 
@@ -52,7 +71,7 @@ def gaussian_bunch_spectrum(frequency, sigma):
     -------
     bunch_spectrum : array
         Bunch spectrum sampled at points given in frequency.
-        
+
     References
     ----------
     [1] : Gamelin, A. (2018). Collective effects in a transient microbunching 
@@ -60,7 +79,8 @@ def gaussian_bunch_spectrum(frequency, sigma):
     """
     return np.exp(-1/2*(2*np.pi*frequency)**2*sigma**2)
 
-def gaussian_bunch(time, sigma): 
+
+def gaussian_bunch(time, sigma):
     """
     Compute a Gaussian bunch profile.
 
@@ -77,10 +97,10 @@ def gaussian_bunch(time, sigma):
         Bunch profile in [s**-1] sampled at points given in time.
     """
     return np.exp(-1/2*(time**2/sigma**2))/(sigma*np.sqrt(2*np.pi))
-        
-        
-def beam_spectrum(frequency, M, bunch_spacing, sigma=None, 
-                  bunch_spectrum=None): 
+
+
+def beam_spectrum(frequency, M, bunch_spacing, sigma=None,
+                  bunch_spectrum=None):
     """
     Compute the beam spectrum assuming constant spacing between bunches [1].
 
@@ -107,13 +127,13 @@ def beam_spectrum(frequency, M, bunch_spacing, sigma=None,
     [1] Rumolo, G - Beam Instabilities - CAS - CERN Accelerator School: 
         Advanced Accelerator Physics Course - 2014, Eq. 9
     """
-    
+
     if bunch_spectrum is None:
         bunch_spectrum = gaussian_bunch_spectrum(frequency, sigma)
-        
-    beam_spectrum = (bunch_spectrum * np.exp(1j*np.pi*frequency * 
-                                             bunch_spacing*(M-1)) * 
-                     np.sin(M*np.pi*frequency*bunch_spacing) / 
+
+    beam_spectrum = (bunch_spectrum * np.exp(1j*np.pi*frequency *
+                                             bunch_spacing*(M-1)) *
+                     np.sin(M*np.pi*frequency*bunch_spacing) /
                      np.sin(np.pi*frequency*bunch_spacing))
-    
-    return beam_spectrum
\ No newline at end of file
+
+    return beam_spectrum