Step-by-step NMO correction

Abstract

Corresponding author: leouieda@gmail.com

This is a part of The Leading Edge “Geophysical Tutorials” series. You can read more about it in Hall (2016).

Open any textbook about seismic data processing and you will inevitably find a section about the normal moveout (NMO) correction. There you’ll see that we can correct the measured travel-time of a reflected wave \(t\) at a given offset \(x\) to obtain the travel-time at normal incidence \(t_{0}\) by applying the following equation

\begin{equation} \label{eq:traveltime}t_{0}^{2}=t^{2}-\dfrac{x^{2}}{v_{\mathrm{NMO}}^{2}}\\ \end{equation}

in which \(v_{\mathrm{NMO}}\) is the NMO velocity. There are variants of this equation with different degrees of accuracy, but we’ll use this one for simplicity.

When applied to a common midpoint (CMP) section, the equation above is supposed to turn the hyperbola associated with a reflection into a straight horizontal line. What most textbooks won’t tell you is how, exactly, do you apply this equation to the data?

Read on and I’ll explain step-by-step how the algorithm for NMO correction from Yilmaz (2001) works and how to implement it in Python. The accompanying Jupyter notebook (Perez et al., 2007) contains the full source code, with documentation and tests for each function. You can download the notebook at github.com/seg or github.com/pinga-lab/nmo-tutorial.

What the equation doesn’t tell us

Equation \ref{eq:traveltime} relates travel-times: the one we can measure (\(t\)) and the one we want to know (\(t_{0}\)). But the data in our CMP gather are actually a matrix of amplitudes measured as a function of time (\(t\)) and offset. Our NMO corrected gather will also be a matrix of amplitudes as a function of time (\(t_{0}\)) and offset. So what we really have to do transform one matrix of amplitudes into the other. But the equation has no amplitudes!

This is a major divide between the formula we’ve all seen before and what actually goes on in the software that implements it. You have probably never thought about it – I certainly hadn’t – so let’s bridge this divide. Next, I’ll explain an algorithm that maps the amplitudes in the CMP to amplitudes in an NMO corrected gather.

Doing it backwards

It’s surprisingly difficult to find a description of a method for calculating the amplitudes in the NMO correction. The only one I could find is a single paragraph in the book by Yilmaz (2001) (available on the SEG Wiki at wiki.seg.org/wiki/NMO_for_a_flat_reflector):

“The idea is to find the amplitude value at A’ on the NMO-corrected gather from the amplitude value at A on the original CMP gather. Given quantities \(t_{0}\), \(x\), and \(v_{\mathrm{NMO}}\), compute \(t\) from equation (1). […] The amplitude value at this time can be computed using the amplitudes at the neighboring integer sample values […] This is done by an interpolation scheme that involves the four samples.”

This paragraph is telling us to do the calculation backwards. Instead of mapping where each point in the CMP goes in the NMO corrected gather, we should map where each point in the NMO gather comes from in the CMP. Figure 1 shows a sketch of the procedure to calculate the amplitude of a point (\(t_{0}\), \(x\)) in the NMO gather.

Here is the full algorithm:

  1. 1.

    Start with an NMO gather filled with zeros.

  2. 2.

    For each point (\(t_{0},x\)) in the NMO gather, do:

    1. (a)

      Calculate the reflection travel-time (\(t\)) given \(v_{\mathrm{NMO}}\) using the equation in Figure 1.

    2. (b)

      Go to the trace at offset \(x\) in the CMP and find the two samples before and the two samples after time \(t\).

    3. (c)

      If \(t\) is greater than the recording time or if it doesn’t have two samples after it, skip the next two steps.

    4. (d)

      Use the amplitude in these four samples to interpolate the amplitude at time \(t\).

    5. (e)

      Copy the interpolated amplitude to the NMO gather at (\(t_{0},x\)).

At the end of this algorithm, we will have a fully populated NMO gather with the amplitudes sampled from the CMP. Notice that we didn’t actually use the equation for \(t_{0}\). Instead we calculate the reflection travel-time (\(t\)). Good luck guessing that from the equation alone.