next up previous print clean
Next: ADJOINT DEFINED: DOT-PRODUCT TEST Up: FAMILIAR OPERATORS Previous: Polarity-preserving low-cut filter

Nearest-neighbor normal moveout (NMO)

Normal-moveout correction (NMO) is a geometrical correction of reflection seismic data that stretches the time axis so that data recorded at nonzero separation x0 of shot and receiver, after stretching, appears to be at x0=0. NMO correction is roughly like time-to-depth conversion with the equation v2 t2 = z2 + x02. After the data at x0 is stretched from t to z, it should look like stretched data from any other x (assuming these are plane horizontal reflectors, etc.). In practice, z is not used; rather, traveltime depth $\tau$ is used, where $\tau =z/v$;so $t^2 = \tau^2+x_0^2/v^2$.(Because of the limited alphabet of programming languages, I often use the keystroke z to denote $\tau$.)

Typically, many receivers record each shot. Each seismogram can be transformed by NMO and the results all added. This is called ``stacking'' or ``NMO stacking.'' The adjoint to this operation is to begin from a model that is identical to the near-offset trace and spray this trace to all offsets. From a matrix viewpoint, stacking is like a row vector of normal moveout operators and modeling is like a column.

A module that does reverse moveout is hypotenusei. Given a zero-offset trace, it makes another at non-zero offset. The adjoint does the usual normal moveout correction.  

module hypotenusei {                                # Inverse normal moveout
integer :: nt
integer, dimension (nt), allocatable :: iz
#%  _init( nt, t0, dt, xs)
integer it
real t0, dt, xs, t, zsquared
do it= 1, nt {  t = t0 + dt*(it-1)
       	zsquared =  t * t - xs * xs
	if ( zsquared >= 0.) 
		iz (it) = 1.5 + (sqrt( zsquared) - t0) /dt
	else
		iz (it) = 0
	}
#%  _lop(   zz, tt)
integer   it
do it= 1, nt {
	     if ( iz (it) > 0 ) { if( adj)
					zz( iz(it))  +=   tt(    it )
				else
                                        tt(it)       +=   zz( iz(it))
                }
        }
}

A companion routine imospray loops over offsets and makes a trace for each. The adjoint of imospray is the industrial process of moveout and stack. My 1992 textbook (PVI) illustrates many additional features of normal moveout.  

module imospray {                   # inverse moveout and spray into a gather.
use hypotenusei
real :: x0,dx, t0,dt
integer :: nx,nt
#%  _init (slow, x0,dx, t0,dt, nt,nx)
		real slow
		x0 = x0*slow
		dx = dx*slow
#% _lop(  stack(nt),    gather(nt,nx))
integer ix, stat

do ix= 1, nx { call hypotenusei_init ( nt, t0, dt, x0 + dx*(ix-1))

stat = hypotenusei_lop ( adj, .true., stack, gather(:,ix)) } call hypotenusei_close () }


next up previous print clean
Next: ADJOINT DEFINED: DOT-PRODUCT TEST Up: FAMILIAR OPERATORS Previous: Polarity-preserving low-cut filter
Stanford Exploration Project
2/27/1998