next up previous [pdf]

Next: Coding chains and arrays Up: FAMILIAR OPERATORS Previous: Smoothing with box and

Nearest-neighbor normal moveout (NMO)

Normal-moveout correction is a geometrical correction of reflection seismic data that stretches the time axis so that data recorded at nonzero separation $x_0$ of shot and receiver, after stretching, appears to be at $x_0=0$. NMO correction is roughly like time-to-depth conversion with the equation $v^2 t^2 = z^2 + x_0^2$. After the data at $x_0$ 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. The whole process is called ``NMO stacking.'' The adjoint to this operation is to begin from a model that ideally is the zero-offset trace, and spray this model to all offsets. From a matrix viewpoint, stacking is like a row vector of NMO operators, and modeling is like a column. An example is shown in Figure 8.

cunha
Figure 8.
Hypothetical model, synthetic data, and model image.
cunha
[pdf] [png] [scons]

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

user/gee/hypotenusei.c
void hypotenusei_set(float t0 /* time origin */, 
		     float dt /* time sampling */, 
		     float xs /* offset times slowness */)
/*< set up >*/
{
    int it;
    float t, z2;

    for (it=0; it < nt; it++) {  
	t = t0 + dt*it;
        z2 =  t * t - xs * xs;
	iz[it] = ( z2 >= 0.)? 0.5 + (sqrtf(z2) - t0) /dt: -1;
    }
}

void hypotenusei_lop(bool adj, bool add, 
		     int n1, int n2, float *zz, float *tt)
/*< linear operator >*/
{
    int  it;
    
    sf_adjnull(adj,add,n1,n2,zz,tt);

    for (it=0; it < nt; it++) {  
	if (iz[it] < 0) continue;

	if (adj) 
	    zz[iz[it]] +=  tt[it];
	else 
	    tt[it] +=  zz[iz[it]];
    }
}
My 1992 textbookPVI (Earth Soundings Analysis : Processing Versus Inversion) illustrates many additional features of NMO. 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.
user/gee/imospray.c
void imospray_lop(bool adj, bool add, int n1, int n2, 
		  float *stack, float *gather)
/*< linear operator >*/
{
    int ix;
    float x;

    sf_adjnull(adj,add,n1,n2,stack,gather);

    for (ix=0; ix < nx; ix++) {
	x = x0 + dx*ix;

        hypotenusei_set (t0, dt, x);
	hypotenusei_lop (adj, true, nt, nt, stack, gather+ix*nt);
    }
}


next up previous [pdf]

Next: Coding chains and arrays Up: FAMILIAR OPERATORS Previous: Smoothing with box and

2014-09-27