diff --git a/.gitattributes b/.gitattributes
index 18fb6d753473771466372e2c90722cd81ab85532..df50dbe029123b8b20367822981428f91dd3ae34 100755
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,3 +4,5 @@ tests/keplerian-orbits-2-0.h5 filter=lfs diff=lfs merge=lfs -text
 tests/esa-trailing-orbits-2-0.h5 filter=lfs diff=lfs merge=lfs -text
 tests/keplerian-fplan-1-1.h5 filter=lfs diff=lfs merge=lfs -text
 tests/esa-trailing-fplan-1-1.h5 filter=lfs diff=lfs merge=lfs -text
+tests/gws-1-1.h5 filter=lfs diff=lfs merge=lfs -text
+tests/gws-2-0-dev.h5 filter=lfs diff=lfs merge=lfs -text
diff --git a/lisainstrument/instrument.py b/lisainstrument/instrument.py
index e13c032a8d8b7478a7ea5e9e1dca210a16dfca87..144789e57714505ec9d2b61892ed47547c02ed44 100755
--- a/lisainstrument/instrument.py
+++ b/lisainstrument/instrument.py
@@ -682,10 +682,17 @@ class Instrument:
                 logger.debug("Using GW file version %s", version)
                 if version.is_devrelease:
                     logger.warning("You are using a GW file in a development version")
-                if version in SpecifierSet('~= 0.1', True) or version in SpecifierSet('~= 1.0', True):
-                    self.gws = ForEachMOSA(lambda mosa: InterpolatedUnivariateSpline(
-                        gwf['t'][:], gwf[f'l_{mosa}'][:], k=5, ext='zeros')(self.physics_t)
-                    )
+                if version in SpecifierSet('< 1.1', True):
+                    interpolate = lambda data, t: InterpolatedUnivariateSpline(gwf['t'][:], data, k=5, ext='zeros')(t)
+                    self.gws = ForEachMOSA(lambda mosa: interpolate(gwf[f'l_{mosa}'][:], self.physics_t))
+                elif version in SpecifierSet('== 1.1', True):
+                    interpolate = lambda data, t: InterpolatedUnivariateSpline(gwf['t'][:], data, k=5, ext='zeros')(t)
+                    self.gws = ForEachMOSA(lambda mosa: interpolate(gwf[f'tcb/l_{mosa}'][:], self.physics_t))
+                elif version in SpecifierSet('== 2.*', True):
+                    times = gwf.attrs['t0'] + np.arange(gwf.attrs['size']) * gwf.attrs['dt']
+                    interpolate = lambda data, t: InterpolatedUnivariateSpline(times, data, k=5, ext='zeros')(t)
+                    link_index = {'12': 0, '23': 1, '31': 2, '13': 3, '32': 4, '21': 5}
+                    self.gws = ForEachMOSA(lambda mosa: interpolate(gwf['tcb/y'][:, link_index[mosa]], self.physics_t))
                 else:
                     raise ValueError(f"unsupported GW file version '{version}'")
         elif gws is None:
@@ -792,6 +799,7 @@ class Instrument:
         self.sc_jitter_eta_asds = ForEachSC(0)
         self.sc_jitter_theta_asds = ForEachSC(0)
         self.mosa_jitter_phi_asds = ForEachMOSA(0)
+        self.mosa_jitter_eta_asds = ForEachMOSA(0)
 
     def disable_dopplers(self):
         """Set proper pseudo-range derivatives to zero to turn off Doppler effects."""
diff --git a/tests/gws-1-1.h5 b/tests/gws-1-1.h5
new file mode 100644
index 0000000000000000000000000000000000000000..c8c5979379be7bd8086f2a833422d0ea251fb248
--- /dev/null
+++ b/tests/gws-1-1.h5
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:95a12c32a7ab80c75e88d67329e7840760eff990a180a79360da6b1d0f74d150
+size 28672
diff --git a/tests/gws-2-0-dev.h5 b/tests/gws-2-0-dev.h5
new file mode 100644
index 0000000000000000000000000000000000000000..6abce64b1ca22d69e56f7473e8b8d36c60ec901d
--- /dev/null
+++ b/tests/gws-2-0-dev.h5
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b14f934a46606fffe413bfa4baaf461162ff76346f546b09c5cfb7895d1b8f41
+size 20272
diff --git a/tests/test_gws.py b/tests/test_gws.py
new file mode 100644
index 0000000000000000000000000000000000000000..5951f04988b7fe7ec56b7445ac885552aee90f5e
--- /dev/null
+++ b/tests/test_gws.py
@@ -0,0 +1,164 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""Test reading of GW response and GW files."""
+
+import numpy as np
+from pytest import approx
+from h5py import File
+from lisainstrument import Instrument
+
+
+def test_no_gws():
+    """Test that we simulate without GWs."""
+
+    instru = Instrument(size=100, gws=None)
+    instru.disable_all_noises()
+
+    assert instru.gw_file is None
+    for mosa in instru.MOSAS:
+        assert instru.gws[mosa] == 0
+
+    instru.simulate()
+
+    for mosa in instru.MOSAS:
+        assert instru.distant_carrier_fluctuations[mosa] == approx(0)
+        assert instru.distant_usb_fluctuations[mosa] == approx(0)
+        assert instru.tps_isi_carrier_fluctuations[mosa] == approx(0)
+        assert instru.tps_isi_usb_fluctuations[mosa] == approx(0)
+        assert instru.isi_carrier_fluctuations[mosa] == approx(0)
+        assert instru.isi_usb_fluctuations[mosa] == approx(0)
+
+def test_dict_of_gws():
+    """Test that we pass link responses in a dictionary."""
+
+    responses = {
+        mosa: np.random.normal(size=100 * 16)
+        for mosa in Instrument.MOSAS
+    }
+
+    instru = Instrument(size=100, lock='six', gws=responses)
+    instru.disable_all_noises()
+
+    assert instru.gw_file is None
+    for mosa in instru.MOSAS:
+        assert np.all(instru.gws[mosa] == responses[mosa])
+
+    instru.simulate()
+
+    for mosa in instru.MOSAS:
+        assert approx(instru.distant_carrier_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_carrier_offsets[mosa]) * responses[mosa]
+        assert approx(instru.distant_usb_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_usb_offsets[mosa]) * responses[mosa]
+        assert approx(instru.tps_isi_carrier_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_carrier_offsets[mosa]) * responses[mosa]
+        assert approx(instru.tps_isi_usb_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_usb_offsets[mosa]) * responses[mosa]
+
+def test_gw_file_1_1():
+    """Test that we can read GW files v1.1 with orbit files v1.0.2.
+
+    Test GW file can be generated using LISA GW Response and the following script.
+
+        from h5py import File
+        from lisagwresponse import GalacticBinary
+
+        orbits = 'tests/keplerian-orbits-1-0-2.h5'
+        with File(orbits, 'r') as f:
+            t0 = f.attrs['t0'] + 10
+
+        galbin = GalacticBinary(
+            A=1.0,
+            f=1E-3,
+            orbits=orbits,
+            t0=t0,
+            size=100,
+            gw_beta=0, gw_lambda=0,
+        )
+
+        galbin.write('tests/gws-1-1.h5')
+    """
+
+    gw_file = 'tests/gws-1-1.h5'
+    gwf = File(gw_file, 'r')
+
+    instru = Instrument(
+        size=100,
+        t0=gwf.attrs['t0'],
+        dt=gwf.attrs['dt'],
+        physics_upsampling=1,
+        aafilter=None,
+        lock='six',
+        gws=gw_file,
+        orbits='tests/keplerian-orbits-1-0-2.h5')
+    instru.disable_all_noises()
+
+    assert instru.gw_file is gw_file
+    for mosa in instru.MOSAS:
+        assert instru.gws[mosa] == approx(gwf[f'tcb/l_{mosa}'][:])
+
+    instru.simulate()
+
+    for mosa in instru.MOSAS:
+        assert approx(instru.distant_carrier_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:]
+        assert approx(instru.distant_usb_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:]
+        assert approx(instru.tps_isi_carrier_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:]
+        assert approx(instru.tps_isi_usb_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:]
+
+def test_gw_file_2_0_dev():
+    """Test that we can read GW files v2.0.dev with orbit files v2.0.
+
+    Test GW file can be generated using LISA GW Response and the following script.
+
+        from h5py import File
+        from lisagwresponse import GalacticBinary
+
+        orbits = 'tests/keplerian-orbits-2-0.h5'
+        with File(orbits, 'r') as f:
+            t0 = f.attrs['t0'] + 10
+
+        galbin = GalacticBinary(
+            A=1.0,
+            f=1E-3,
+            orbits=orbits,
+            t0=t0,
+            size=100,
+            gw_beta=0, gw_lambda=0,
+        )
+
+        galbin.write('tests/gws-2-0-dev.h5')
+    """
+
+    gw_file = 'tests/gws-2-0-dev.h5'
+    gwf = File(gw_file, 'r')
+
+    instru = Instrument(
+        size=100,
+        t0=gwf.attrs['t0'],
+        dt=gwf.attrs['dt'],
+        physics_upsampling=1,
+        aafilter=None,
+        lock='six',
+        gws=gw_file,
+        orbits='tests/keplerian-orbits-2-0.h5')
+    instru.disable_all_noises()
+
+    assert instru.gw_file is gw_file
+    for imosa, mosa in enumerate(instru.MOSAS):
+        assert instru.gws[mosa] == approx(gwf['tcb/y'][:, imosa])
+
+    instru.simulate()
+
+    for imosa, mosa in enumerate(instru.MOSAS):
+        assert approx(instru.distant_carrier_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf['tcb/y'][:, imosa]
+        assert approx(instru.distant_usb_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf['tcb/y'][:, imosa]
+        assert approx(instru.tps_isi_carrier_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf['tcb/y'][:, imosa]
+        assert approx(instru.tps_isi_usb_fluctuations[mosa]) == \
+            -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf['tcb/y'][:, imosa]