{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"This notebook shows how Constant Q-transform from waves can be calculated with usage of nnAudio package (https://github.com/KinWaiCheuk/nnAudio). \n\nnnAudio is an audio processing toolbox using PyTorch convolutional neural network as its backend.\n\nHave any questions or suggestions? Please comment below.\n\n**<font color='red'>And if you liked this notebook, please upvote it!</font>**\n\n**Changelog**\n* v6 - number of processed samples can be now easily changed via num_samples variable\n* v5 - added Tukey window\n* v4 - added a bandpass filter (idea taken from https://www.kaggle.com/c/g2net-gravitational-wave-detection/discussion/261721#1458564) + wave plots\n* v3 - small markup fix :)\n* v2 - changed CQT1992v2 to CQT (alias)","metadata":{}},{"cell_type":"markdown","source":"## Import packages","metadata":{}},{"cell_type":"code","source":"!pip install -q nnAudio","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:33.137377Z","iopub.execute_input":"2021-08-24T10:25:33.137768Z","iopub.status.idle":"2021-08-24T10:25:41.918081Z","shell.execute_reply.started":"2021-08-24T10:25:33.137688Z","shell.execute_reply":"2021-08-24T10:25:41.916873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt\nfrom scipy import signal\nimport torch\nfrom torch.utils.data import Dataset\nfrom nnAudio.Spectrogram import CQT # CQT is an alias of CQT1992v2\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n%matplotlib inline","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-08-24T10:25:41.919573Z","iopub.execute_input":"2021-08-24T10:25:41.919828Z","iopub.status.idle":"2021-08-24T10:25:43.677560Z","shell.execute_reply.started":"2021-08-24T10:25:41.919802Z","shell.execute_reply":"2021-08-24T10:25:43.676387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_samples = 4 # first N samples to process","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:43.679825Z","iopub.execute_input":"2021-08-24T10:25:43.680275Z","iopub.status.idle":"2021-08-24T10:25:43.684609Z","shell.execute_reply.started":"2021-08-24T10:25:43.680229Z","shell.execute_reply":"2021-08-24T10:25:43.683626Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Define dataset","metadata":{}},{"cell_type":"markdown","source":"Let's define a dataset to work with.","metadata":{}},{"cell_type":"code","source":"class G2NetDataset(Dataset):\n    def __init__(self, paths, targets, use_filter=True): \n        self.paths = paths\n        self.targets = targets\n        self.use_filter = use_filter\n        if self.use_filter:\n            self.bHP, self.aHP = signal.butter(8, (20, 500), btype='bandpass', fs=2048)\n\n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):      \n        waves = np.load(self.paths[index])\n        waves = np.concatenate(waves, axis=0)\n        if self.use_filter:\n            waves *= signal.tukey(4096*3, 0.2)\n            waves = signal.filtfilt(self.bHP, self.aHP, waves)\n        waves = waves/np.max(waves)\n        targets = self.targets[index]\n                \n        return {\n            \"waves\": torch.tensor(waves, dtype=torch.float),\n            \"target\": torch.tensor(targets, dtype=torch.long),\n        }","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:43.686449Z","iopub.execute_input":"2021-08-24T10:25:43.686782Z","iopub.status.idle":"2021-08-24T10:25:43.696327Z","shell.execute_reply.started":"2021-08-24T10:25:43.686753Z","shell.execute_reply":"2021-08-24T10:25:43.695310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Read training labels","metadata":{}},{"cell_type":"markdown","source":"Now we read training labels data, and get npy paths.","metadata":{}},{"cell_type":"code","source":"ROOT_DIR = '../input/g2net-gravitational-wave-detection'\ndf = pd.read_csv(os.path.join(ROOT_DIR, 'training_labels.csv'))\ndf['path'] = df['id'].apply(lambda x: f'{ROOT_DIR}/train/{x[0]}/{x[1]}/{x[2]}/{x}.npy')","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:43.697994Z","iopub.execute_input":"2021-08-24T10:25:43.698291Z","iopub.status.idle":"2021-08-24T10:25:44.585313Z","shell.execute_reply.started":"2021-08-24T10:25:43.698265Z","shell.execute_reply":"2021-08-24T10:25:44.584404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Demonstrate CQT usage","metadata":{}},{"cell_type":"markdown","source":"nnAudio has several implementations of CQT; we will use the recommended one - CQT1992v2 (see https://github.com/KinWaiCheuk/nnAudio/blob/master/Installation/nnAudio/Spectrogram.py for details). You can simply call CQT, since it's an alias of CQT1992v2. If you want other CQT version, you'll have to import it directly.\n\nLet's calculate CQT for 4 first signals with and without usage of a bandpass filter (20-500Hz), and plot results!","metadata":{}},{"cell_type":"code","source":"transform = CQT(sr=2048,        # sample rate\n                fmin=20,        # min freq\n                fmax=1024,      # max freq (set to Nyquist frequency)\n                hop_length=64,  # hop length\n                verbose=False)  \n\nds = G2NetDataset(df['path'], df['target'], use_filter=False)\nds_f = G2NetDataset(df['path'], df['target'], use_filter=True)\n\nwaves = []\nwaves_f = []\ncqts = []\ncqts_f = []\nfor i in range(num_samples):\n    waves.append(ds.__getitem__(i)['waves'])\n    waves_f.append(ds_f.__getitem__(i)['waves'])\n    cqts.append(transform(waves[i]).squeeze())\n    cqts_f.append(transform(waves_f[i]).squeeze())","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:44.586904Z","iopub.execute_input":"2021-08-24T10:25:44.587371Z","iopub.status.idle":"2021-08-24T10:25:44.890622Z","shell.execute_reply.started":"2021-08-24T10:25:44.587324Z","shell.execute_reply":"2021-08-24T10:25:44.889633Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Without a filter","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(num_samples)\nfig.set_figheight(15)\nfig.set_figwidth(15)\nfor i in range(num_samples):\n    nid = df['id'][i]\n    ntarget = df['target'][i]\n    axs[i].title.set_text(f'{nid}.npy, target: {ntarget}')\n    axs[i].plot(waves[i])","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:44.891918Z","iopub.execute_input":"2021-08-24T10:25:44.892222Z","iopub.status.idle":"2021-08-24T10:25:45.991129Z","shell.execute_reply.started":"2021-08-24T10:25:44.892191Z","shell.execute_reply":"2021-08-24T10:25:45.989856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(num_samples)\nfig.set_figheight(15)\nfig.set_figwidth(15)\nfor i in range(num_samples):\n    nid = df['id'][i]\n    ntarget = df['target'][i]\n    axs[i].title.set_text(f'{nid}.npy, target: {ntarget}')\n    axs[i].pcolormesh(cqts[i])","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:45.993324Z","iopub.execute_input":"2021-08-24T10:25:45.993626Z","iopub.status.idle":"2021-08-24T10:25:46.614782Z","shell.execute_reply.started":"2021-08-24T10:25:45.993597Z","shell.execute_reply":"2021-08-24T10:25:46.613797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### With a filter with Tukey window","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(num_samples)\nfig.set_figheight(15)\nfig.set_figwidth(15)\nfor i in range(num_samples):\n    nid = df['id'][i]\n    ntarget = df['target'][i]\n    axs[i].title.set_text(f'{nid}.npy, target: {ntarget}')\n    axs[i].plot(waves_f[i])","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:46.616074Z","iopub.execute_input":"2021-08-24T10:25:46.616372Z","iopub.status.idle":"2021-08-24T10:25:47.671020Z","shell.execute_reply.started":"2021-08-24T10:25:46.616345Z","shell.execute_reply":"2021-08-24T10:25:47.670044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(num_samples)\nfig.set_figheight(15)\nfig.set_figwidth(15)\nfor i in range(num_samples):\n    nid = df['id'][i]\n    ntarget = df['target'][i]\n    axs[i].title.set_text(f'{nid}.npy, target: {ntarget}')\n    axs[i].pcolormesh(cqts_f[i])","metadata":{"execution":{"iopub.status.busy":"2021-08-24T10:25:47.672202Z","iopub.execute_input":"2021-08-24T10:25:47.672539Z","iopub.status.idle":"2021-08-24T10:25:48.278806Z","shell.execute_reply.started":"2021-08-24T10:25:47.672501Z","shell.execute_reply":"2021-08-24T10:25:48.277720Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"You can use CQT() as your model block to convert waves to CQT on-the-fly.","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:29:22.62631Z","iopub.execute_input":"2021-07-03T14:29:22.626623Z","iopub.status.idle":"2021-07-03T14:29:22.632544Z","shell.execute_reply.started":"2021-07-03T14:29:22.626594Z","shell.execute_reply":"2021-07-03T14:29:22.63147Z"}}}]}