166 lines
4.9 KiB
Plaintext
166 lines
4.9 KiB
Plaintext
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# Nonlinear Thresholding\n",
|
||
|
"When noise and signal share a common frequency band, spectral filtering would lead to a loss in signal. For these cases, we need different techniques to reduce the disturibing noise. We start with a reocorde signal $x(t)$, contains some signal $s(t)$ and additive noise $n(t)$:\n",
|
||
|
"$$\n",
|
||
|
"x(t) = s(t) + n(t)\n",
|
||
|
"$$\n",
|
||
|
"We can rewrite the equation above in time-frequency domain as\n",
|
||
|
"$$\n",
|
||
|
"X(t, f) = S(t, f) + N(t, f) ~.\n",
|
||
|
"$$\n",
|
||
|
"Assuming that some time-frequnecy coefficients can be associated by noise, we set all coefficients, which a below this threshold, to zero:\n",
|
||
|
"$$\n",
|
||
|
"\\tilde{X}(t, f) = \\left\\{\n",
|
||
|
" \\begin{array}{@{}ll@{}}\n",
|
||
|
" X(t, f) & \\mathrm{if}~ |X(t, f)| \\geq \\beta(f) \\\\\n",
|
||
|
" 0 & \\mathrm{otherwise}\n",
|
||
|
" \\end{array}\\right.\n",
|
||
|
" ~,\n",
|
||
|
"$$\n",
|
||
|
"where $\\beta(f)$ denotes the threshold function. The threshold function is defined as \n",
|
||
|
"$$\n",
|
||
|
"\\beta(f) = \\mathrm{ECDF}_f^{-1} (P = 0.99) ~,\n",
|
||
|
"$$\n",
|
||
|
"where $\\mathrm{ECDF}_f^{-1}$ denotes the inverse cumulative distribution function or quantile function, e.g. before the first arrival of earthquake waves."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Load all required packages\n",
|
||
|
"import os\n",
|
||
|
"import numpy as np\n",
|
||
|
"from scipy.signal import stft, istft\n",
|
||
|
"import matplotlib.pyplot as plt"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Load our earthquake data and plot\n",
|
||
|
"d = np.load(os.path.join(os.path.expanduser('~'),'work', 'data', 'events', 'bug2019mgoh_Z.npz'))\n",
|
||
|
"#d = np.load(os.path.join(os.path.expanduser('~'),'work', 'data', 'events', 'bug2019gbbo_Z.npz'))\n",
|
||
|
"#d = np.load(os.path.join(os.path.expanduser('~'),'work', 'data', 'events', 'bug2019ibsd_Z.npz'))\n",
|
||
|
"plt.figure(figsize=(15, 8))\n",
|
||
|
"plt.plot(d['data']);"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Compute spectrogram of data\n",
|
||
|
"f, t, X = stft(d['data'], fs=1/0.01, nfft=198, nperseg=99) # Be careful with choice of nfft and nperseg, \n",
|
||
|
" # because istft does not work for all pairs\n",
|
||
|
"print(X.shape)\n",
|
||
|
"plt.figure(figsize=(15, 8))\n",
|
||
|
"plt.pcolormesh(t, f, np.abs(X))\n",
|
||
|
"plt.xlabel(\"Frequency (Hz)\")\n",
|
||
|
"plt.ylabel(\"Time (s)\");"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Functions for thresholding\n",
|
||
|
"def threshold(X, quantile=0.99):\n",
|
||
|
" \"\"\"\n",
|
||
|
" X: time-frequency coefficients\n",
|
||
|
" q: quantile [0-1]\n",
|
||
|
" \"\"\"\n",
|
||
|
" # Loop over frequencies to build threshold function\n",
|
||
|
" beta = np.zeros(X.shape[0])\n",
|
||
|
" for i in range(X.shape[0]):\n",
|
||
|
" beta[i] = np.quantile(np.abs(X[i, :]), q=quantile)\n",
|
||
|
" \n",
|
||
|
" return beta\n",
|
||
|
"\n",
|
||
|
"def modify_spectrogram(X, beta):\n",
|
||
|
" # Loop over all items in X and apply threshold\n",
|
||
|
" # Task: modify X!\n",
|
||
|
" \n",
|
||
|
" return X"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Compute STFT of data before first arrival of P\n",
|
||
|
"_, _, X_thres = stft(d['data'][:2500], fs=1/0.01, nfft=198, nperseg=99)\n",
|
||
|
"# Estimate threshold fucntion\n",
|
||
|
"beta = threshold(X_thres)\n",
|
||
|
"\n",
|
||
|
"# Modifiy original spectrogram\n",
|
||
|
"X_mod = modify_spectrogram(X, beta)\n",
|
||
|
"\n",
|
||
|
"# Plot modified spectrogram\n",
|
||
|
"plt.figure(figsize=(15, 8))\n",
|
||
|
"plt.pcolormesh(t, f, np.abs(X_mod))\n",
|
||
|
"plt.xlabel(\"Frequency (Hz)\")\n",
|
||
|
"plt.ylabel(\"Time (s)\");"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Inverse STFT of modified spectrogram\n",
|
||
|
"t, x_mod = istft(X_mod, fs=1/0.01, nfft=198, nperseg=99)\n",
|
||
|
"\n",
|
||
|
"# Plot corrected seismogram\n",
|
||
|
"plt.figure(figsize=(15, 8))\n",
|
||
|
"plt.plot(t, x_mod);"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": []
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"kernelspec": {
|
||
|
"display_name": "Python 3",
|
||
|
"language": "python",
|
||
|
"name": "python3"
|
||
|
},
|
||
|
"language_info": {
|
||
|
"codemirror_mode": {
|
||
|
"name": "ipython",
|
||
|
"version": 3
|
||
|
},
|
||
|
"file_extension": ".py",
|
||
|
"mimetype": "text/x-python",
|
||
|
"name": "python",
|
||
|
"nbconvert_exporter": "python",
|
||
|
"pygments_lexer": "ipython3",
|
||
|
"version": "3.6.7"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 2
|
||
|
}
|