Implementing FK filter #405
Replies: 2 comments 2 replies
-
Hey @Shihao-Yuan, this is a good start, and the examples are compelling. As far as suggestions, a few things come to mind:
So implementing these ideas (I haven't tested this, its just to get you started): import dascore as dc
@dc.patch_function()
def ft_slope_filter(patch, filt, dims=("time", "distance"), directional=False, notch=False):
"""
Filter the patch over certain slopes in the 2D Fourier domain.
Most commonly this used as an F-K (frequency wavenumber) filter to attenuate energy with specified
apparent velocities.
Parameters
-----------------
patch
The patch to filter.
filt
A length 4 sequence of the form (va, vb, vc, vd). If notch is False, {describe filter shape}
dims
The dimensions to filter/transform which
directional
If True, the filter should be considered direction. That is to say, the sign of the values in `filt` indicate the
direction (towards or away) with increasing coordinate values. This can be used for up-down/left-right
separation.
notch
If True, the filter represents a notch.
Examples
-----------------
# need several examples of each feature here, including passing a patch that has already been dft'ed.
Notes
---------
- It is a good idea to first pad the transformed dimensions to fast fft lengths. See [Patch.pad](`dascore.Patch.pad`).
- See the [F-K filter page](`docs/processing/fk.qmd`).
"""
# Perform dft if needed.
dft_patch = patch.dft(dims)
transformed = dft_patch is not patch # if dft didn't create a new patch it was already in dft.
# Get slope array for specified dimensions
assert len(dims) == 2, "dims must be a length 2 tuple"
coord1 = dft_patch.get_array(f"ft_{dims[0]}")
coord2 = dft_patch.get_array(f"ft_{dims[1]}")
vel = coord1 / coord2[:, None]
if not directional:
vel = np.abs(vel)
# Apply filter with tapering function
fac = np.where((vel >= va) & (vel <= vb), 1.0 - np.sin(0.5 * np.pi * (vel - va) / (vb - va)), 1.0)
fac = np.where((vel >= vb) & (vel <= vc), 0.0, fac)
fac = np.where((vel >= vc) & (vel <= vd), np.sin(0.5 * np.pi * (vel - vc) / (vd - vc)), fac)
if passband:
fac = 1.0 - fac
# Apply filter
new_data = fft_patch.data * fac
out = fft_patch.update(data=new_data)
# Undo transformation if an un-transformed patch was passed in.
if transformed:
out = fft_patch.idft()
return out Since this is a really powerful filter, I suggest we create a recipe or processing page called f-k filtering. In that page we could show:
Does anyone else have any thoughts on this function design? |
Beta Was this translation helpful? Give feedback.
-
closed by #413 |
Beta Was this translation helpful? Give feedback.
-
I've implemented an F-K filter function for the Patch data type. Could any of you please test it and provide feedback?
Beta Was this translation helpful? Give feedback.
All reactions