Repository: obspy/obspy

Issue:
time shift in Lanczos interpolation not shifting any data
Not sure if this is a bug or if it should work as it is now. The time shift parameter in Lanczos interpolation does only change the starttime for me, but does not shift the data:

```
In [1]: from obspy import read

In [2]: from obspy.signal.cross_correlation import correlate, xcorr_max

In [3]: tr = read()[0]

In [4]: tr.detrend()
Out[4]: BW.RJOB..EHZ | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples

In [5]: tr2 = tr.copy()

In [6]: tr2.interpolate(100, 'lanczos', a=20, time_shift=0.02)
Out[6]: BW.RJOB..EHZ | 2009-08-24T00:20:03.020000Z - 2009-08-24T00:20:33.010000Z | 100.0 Hz, 3000 samples

In [7]: cc = correlate(tr.data, tr2.data, 1000)

In [8]: xcorr_max(cc)  # expected shift 2 or -2
Out[8]: (0, 0.9999999999999997)

In [9]: tr2 = tr.copy()  # now try sub-sample shifting

In [10]: tr2.interpolate(100, 'lanczos', a=20, time_shift=0.005)
Out[10]: BW.RJOB..EHZ | 2009-08-24T00:20:03.005000Z - 2009-08-24T00:20:32.995000Z | 100.0 Hz, 3000 samples

In [11]: cc = correlate(tr.data, tr2.data, 1000)

In [12]: xcorr_max(cc)  # max cc should be a bit smaller than 1
Out[12]: (0, 0.9999999999999997)
```

Edit: Similar results for `'weighted_average_slopes'`. Am I missing something?


Discussion:
Uhm.. I think you're mixing up high-level and low-level views of the data. From a high-level perspective, changing the starttime of the `Trace` while not changing the `Trace.data` array is equal to performing an actual time shift on the data. From a low-level perspective, when working directly with `Trace.data` the change in trace start time won't affect the result, obviously.. you'll need a different approach in your workflow, I'd just remember the time shift and add it to the cross correlation shift at the very end.
OK, I get you point. But then, the time_shift parameter just changes the metadata. The docs say `time_shift: Interpolation can also shift the data with subsample accuracy...` which somehow implies that the data is actually shifted. I did not expect from an `interpolate` function, that it is performing subsample shifting by just changing the starttime which is of course trivial and can be done without the interpolate function.
I see your point and we should maybe change the documentation a bit. If I remember correctly I added this parameter but I don't really exactly recall why. I guess it was convenient to have a function that can "shift" the data and then exactly interpolate on chosen new time samples?

Nonetheless I actually think that changing the metadata with subsequent interpolation is a pretty good way to shift data in time assuming there is enough data at the boundaries to avoid any boundary effects.
@krischer Your comments made me believe that I was still missing something. And indeed, here is the code which does what I tried to achieve:

```
In [1]: from obspy import read

In [2]: from obspy.signal.cross_correlation import correlate, xcorr_max

In [3]: import numpy as np

In [4]: tr = read()[0]

In [5]: tr.detrend()
Out[5]: BW.RJOB..EHZ | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples

In [6]: tr2 = tr.copy()

In [7]: tr2.interpolate(100, 'lanczos', a=20, time_shift=-0.02, starttime=tr2.stats.starttime)
Out[7]: BW.RJOB..EHZ | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.960000Z | 100.0 Hz, 2997 samples

In [8]: tr2.data = np.hstack([tr2.data, np.zeros(3)])

In [9]: cc = correlate(tr.data, tr2.data, 1000)

In [10]: xcorr_max(cc)
Out[10]: (2, 0.9999998073074055)
```

To fulfill the doc promise `:param starttime: The start time (or timestamp) for the new
            interpolated stream. Will be set to current start time of the
            trace if not given.` may I suggest to move the codeblock setting the new starttime a bit up, so that it is not affected by the starttime manipulation of the `time_shift` parameter? 

It's a pity that extrapolation is not supported. Therefore, it is not possible to do:

```
tr2.interpolate(100, 'lanczos', a=20, time_shift=-0.02, starttime=tr2.stats.starttime, npts=len(tr2))
```
or
```
tr2.interpolate(100, 'lanczos', a=20, time_shift=+0.02, starttime=tr2.stats.starttime)
```
.

Maybe, it would be beneficial to add a parameter `extrapolate=None|'zeros'`?

Edit: Spending more thoughts on this I realized that the key parameter to shift the underlying data is `starttime`. The doc made me thought that `time_shift` is important, but as mentioned above it just manipulates the metadata. So, I agree that the doc should be changed a bit. The radical approach would be to remove the time_shift parameter.

Resolving patch:
diff --git a/obspy/core/trace.py b/obspy/core/trace.py
--- a/obspy/core/trace.py
+++ b/obspy/core/trace.py
@@ -2334,13 +2334,21 @@ def interpolate(self, sampling_rate, method="weighted_average_slopes",
             fitting  number to retain the current end time of the trace if
             not given.
         :type time_shift: float
-        :param time_shift: Interpolation can also shift the data with
-            subsample accuracy. The time shift is always given in seconds. A
-            positive shift means the data is shifted towards the future,
-            e.g. a positive time delta. Please note that a time shift in
-            the Fourier domain is always more accurate than this. When using
-            Lanczos interpolation with large values of ``a`` and away from the
-            boundaries this is nonetheless pretty good.
+        :param time_shift: Shift the trace by adding time_shift to the
+            starttime. The time shift is always given in seconds.
+            A positive shift means the data is shifted towards the future,
+            e.g. a positive time delta.
+            Note that this parameter solely affects the metadata.
+            The actual interpolation of the underlaying data is governed
+            by the parameters sampling_rate, starttime and npts.
+
+            .. note::
+
+                Interpolation can also shift the data with
+                subsample accuracy.  Please note that a time shift in
+                the Fourier domain is always more accurate than this.
+                When using Lanczos interpolation with large values of ``a``
+                and away from the boundaries this is nonetheless pretty good.
 
         .. rubric:: _`New in version 0.11:`
 


Test patch: