|
|
|
|
Basic operators and adjoints |
Normal-moveout
correction (NMO) is a geometrical correction
of reflection seismic data
that stretches the time axis so that data recorded
at nonzero separation
of shot and receiver,
after stretching, appears to be at
.
NMO correction is roughly like time-to-depth conversion
with the equation
.
After the data at
is stretched from
to
,
it should look like stretched data from any other
(assuming these are plane horizontal reflectors, etc.).
In practice,
is not used; rather,
traveltime depth
is used,
where
;
so
.
(Because of the limited alphabet of programming languages,
I often use the keystroke z to denote
.)
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 which ideally is the zero-offset trace and spray this model to all offsets. From a matrix viewpoint, stacking is like a row vector of normal moveout operators and modeling is like a column. An example is shown in Figure 1.7.
|
cunha
Figure 7. Hypothetical model, synthetic data, and model image. |
|
|---|---|
|
|
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.
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]];
}
}
|
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);
}
}
|
This is the first time we have built an operator (moveout and stack) from a collection of other operators (moveout at various offsets) and there are new possibilities for confusion and program bugs. As earlier with the matrix multiplication operator, to use the imospray operator, there are two steps, one that we use to set things up
imospray_init( slow, x0,dx, t0,dt, nt,nx);
and another step that we use a lot in the next chapter
for analysis and data fitting.
imospray_lop( adj, add, n1, n2, stack, gather);
Later we'll see programs that are not operators.
Consider the the adjoint of spraying which is stacking.
Here the occurance of the
add=true in
imospray assures we do not erase the stack each time
we add in another trace.
|
|
|
|
Basic operators and adjoints |