{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":87331,"databundleVersionId":9932741,"sourceType":"competition"},{"sourceId":9730902,"sourceType":"datasetVersion","datasetId":5954952}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport os\nimport librosa\nimport numpy as np\n\naudio_dir = '/kaggle/input/mscc-full-dataset-v-1/sounds_original_6sec/'\n\ntrain = pd.read_csv('/kaggle/input/airs-ai-in-respiratory-sounds/train.csv')\ntest = pd.read_csv('/kaggle/input/airs-ai-in-respiratory-sounds/test.csv')","metadata":{"execution":{"iopub.status.busy":"2024-10-28T07:07:39.501541Z","iopub.execute_input":"2024-10-28T07:07:39.502549Z","iopub.status.idle":"2024-10-28T07:07:40.086546Z","shell.execute_reply.started":"2024-10-28T07:07:39.502472Z","shell.execute_reply":"2024-10-28T07:07:40.085034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Функция для расчета всех необходимых аудиофич\ndef calculate_audio_features(file_path):\n    if os.path.isfile(file_path) and os.path.getsize(file_path) > 0:\n        try:\n            y, sr = librosa.load(file_path, sr=None)\n            \n            # Нормализация амплитуды\n            normalized_y = y / np.max(np.abs(y)) if np.max(np.abs(y)) != 0 else y\n            \n            # Основная частота\n            pitches, magnitudes = librosa.piptrack(y=y, sr=sr)\n            frequencies = [pitch for pitch in pitches.flatten() if pitch > 0]\n            main_freq = np.mean(frequencies) if frequencies else None\n            \n            # Средняя амплитуда и громкость в дБ\n            amplitude = np.mean(np.abs(y))\n            volume_db = librosa.amplitude_to_db([amplitude])[0] if amplitude > 0 else None\n            \n            # Пики громкости\n            peaks = np.where(y > 0.1)[0]  # Порог для пиков\n            peak_count = len(peaks)\n            \n            # MFCC\n            mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)\n            mean_mfccs = np.mean(mfccs, axis=1)\n            \n            # ДБ-преобразование амплитуды\n            D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)\n            D_mean = np.mean(D)\n\n            # Свистящие частоты\n            freqs = np.fft.rfftfreq(len(y), d=1/sr)\n            spectrum = np.abs(np.fft.rfft(y))\n            whistle_freqs = np.sum(spectrum[(freqs > 1000) & (freqs < 3000)])\n            \n            # Обнаружение начальных точек (пиков) кашля\n            onset_frames = librosa.onset.onset_detect(y=y, sr=sr, hop_length=512, backtrack=True)\n            onset_times = librosa.frames_to_time(onset_frames, sr=sr)\n            if len(onset_times) < 2:\n                average_interval = 0\n            else:\n                intervals = np.diff(onset_times)\n                average_interval = np.mean(intervals)\n\n            # Вычисление мощности сигнала и мощности шума\n            signal_power = np.mean(normalized_y**2)\n            threshold = 0.05  # Порог для шума\n            noise = normalized_y[normalized_y < threshold]\n            noise_power = np.mean(noise**2) if len(noise) > 0 else 1e-10\n            snr = 10 * np.log10(signal_power / noise_power)\n\n            return main_freq, volume_db, peak_count, mean_mfccs, D_mean, whistle_freqs, average_interval, snr\n        except Exception as e:\n            print(f\"Ошибка при обработке файла {file_path}: {e}\")\n    return None, None, None, [None] * 13, None, None, 0, None\n\n# Добавляем новые колонки в DataFrames train и test\nmfcc_columns = [f'mfcc_{i}' for i in range(1, 14)]\nfor df in [train, test]:\n    df['H_freq'] = None\n    df['H_volume_db'] = None\n    df['H_peak_count'] = None\n    df['H_D_mean'] = None\n    df['H_whistle_freqs'] = None\n    df['H_average_interval'] = None\n    df['H_snr'] = None\n    for mfcc_col in mfcc_columns:\n        df[mfcc_col] = None  # Инициализация колонок для MFCC\n\n    for idx, candidate_id in enumerate(df['candidateID']):\n        # Путь к файлу кашля\n        cough_file = os.path.join(audio_dir, f\"{candidate_id}_cough.wav\")\n        \n        # Вычисляем фичи аудио\n        main_freq, volume_db, peak_count, mean_mfccs, D_mean, whistle_freqs, average_interval, snr = calculate_audio_features(cough_file)\n        \n        # Заполняем значения в DataFrame\n        df.at[idx, 'H_freq'] = main_freq\n        df.at[idx, 'H_volume_db'] = volume_db\n        df.at[idx, 'H_peak_count'] = peak_count\n        df.at[idx, 'H_D_mean'] = D_mean\n        df.at[idx, 'H_whistle_freqs'] = whistle_freqs\n        df.at[idx, 'H_average_interval'] = average_interval\n        df.at[idx, 'H_snr'] = snr\n        for i, mfcc_val in enumerate(mean_mfccs):\n            df.at[idx, mfcc_columns[i]] = mfcc_val","metadata":{"execution":{"iopub.status.busy":"2024-10-28T07:07:45.919178Z","iopub.execute_input":"2024-10-28T07:07:45.919692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.to_csv('train_heuristics.csv', index=False)\ntest.to_csv('test_heuristics.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1. Тембр и частота\nЭвристика: Определение высоты звука и тембра кашля, что может указывать на различные состояния здоровья.","metadata":{}},{"cell_type":"code","source":"import librosa\nimport numpy as np\n\n# Загрузка аудиофайла\ny, sr = librosa.load('/kaggle/input/airs-ai-in-respiratory-sounds/sounds/sounds/004db89f19f9b/cough.wav')\n\n# Определение частоты основного тона\npitches, magnitudes = librosa.piptrack(y=y, sr=sr)\n\n# Фильтруем нулевые значения\nfrequencies = [pitch for pitch in pitches.flatten() if pitch > 0]\nmain_freq = np.mean(frequencies)\n\nprint(f'Основная частота: {main_freq:.2f} Гц')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-28T06:39:55.869304Z","iopub.execute_input":"2024-10-28T06:39:55.869724Z","iopub.status.idle":"2024-10-28T06:40:18.308689Z","shell.execute_reply.started":"2024-10-28T06:39:55.869681Z","shell.execute_reply":"2024-10-28T06:40:18.307444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Рассуждение: Этот код позволяет извлечь основную частоту кашля. Чем выше основная частота, тем больше вероятность, что кашель вызван раздражением верхних дыхательных путей. Однако наличие других частот также может влиять на интерпретацию, и не всегда основная частота может быть показательна.","metadata":{}},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2024-10-28T06:50:32.943180Z","iopub.execute_input":"2024-10-28T06:50:32.943760Z","iopub.status.idle":"2024-10-28T07:00:39.841258Z","shell.execute_reply.started":"2024-10-28T06:50:32.943703Z","shell.execute_reply":"2024-10-28T07:00:39.840075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Динамика звука\nЭвристика: Анализ громкости и амплитуды звука для понимания характера кашля.","metadata":{}},{"cell_type":"code","source":"# Средняя амплитуда\namplitude = np.mean(np.abs(y))\nvolume_db = librosa.amplitude_to_db(amplitude)\n\n# Пики громкости\npeaks = np.where(y > 0.1)[0]  # Устанавливаем порог\npeak_count = len(peaks)\n\nprint(f'Громкость: {volume_db:.2f} дБ')\nprint(f'Количество пиков громкости: {peak_count}')","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:12:44.175200Z","iopub.execute_input":"2024-10-26T21:12:44.175652Z","iopub.status.idle":"2024-10-26T21:12:44.184669Z","shell.execute_reply.started":"2024-10-26T21:12:44.175602Z","shell.execute_reply":"2024-10-26T21:12:44.183535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Рассуждение: Громкость и количество пиков могут указывать на интенсивность кашля. Громкий кашель может свидетельствовать о серьезных состояниях. Однако не всегда высокий уровень громкости является признаком патологии, поэтому необходимо учитывать и другие факторы.","metadata":{}},{"cell_type":"markdown","source":"## 3. Структура кашля\nЭвристика: Определение типа кашля (сухой или влажный) на основе наличия отхаркивания.","metadata":{}},{"cell_type":"code","source":"import scipy.signal\n\n# Находим колебания (можно использовать простое фильтрование)\nfiltered_y = scipy.signal.medfilt(y, kernel_size=5)\nzero_crossings = np.where(np.diff(np.sign(filtered_y)))[0]\nzero_cross_count = len(zero_crossings)\n\nprint(f'Количество нулевых пересечений: {zero_cross_count}')","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:13:28.036099Z","iopub.execute_input":"2024-10-26T21:13:28.036519Z","iopub.status.idle":"2024-10-26T21:13:28.064443Z","shell.execute_reply.started":"2024-10-26T21:13:28.036480Z","shell.execute_reply":"2024-10-26T21:13:28.063063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Рассуждение: Количество нулевых пересечений может помочь понять, есть ли отхаркивание (влажный кашель). Однако этот метод может не всегда быть надежным, поскольку не учитывает фактическую структуру звука.","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Спектрограмма\nD = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)\nplt.figure(figsize=(10, 4))\nlibrosa.display.specshow(D, sr=sr, x_axis='time', y_axis='log')\nplt.colorbar(format='%+2.0f dB')\nplt.title('Спектрограмма')\nplt.tight_layout()\nplt.show()\n\n# MFCC\nmfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)\nmean_mfccs = np.mean(mfccs, axis=1)\n\nprint(f'MFCC: {mean_mfccs}')\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:22:27.713953Z","iopub.execute_input":"2024-10-26T21:22:27.714381Z","iopub.status.idle":"2024-10-26T21:22:28.785212Z","shell.execute_reply.started":"2024-10-26T21:22:27.714340Z","shell.execute_reply":"2024-10-26T21:22:28.783796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4. Наличие звуковых изменений\nЭвристика: Выявление хрипящих и свистящих звуков, которые могут указывать на астму или другие проблемы.","metadata":{}},{"cell_type":"code","source":"# Спектрограмма\nD = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)\n\n# Упрощенный подход для нахождения свистящих звуков\nfreqs = np.fft.rfftfreq(len(y), d=1/sr)\nspectrum = np.abs(np.fft.rfft(y))\n\n# Нахождение диапазона частот, характерных для свиста (примерно 1000-3000 Гц)\nwhistle_freqs = np.sum(spectrum[(freqs > 1000) & (freqs < 3000)])\n\nprint(f'Суммарная мощность свистящих частот: {whistle_freqs:.2f}')","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:14:10.442493Z","iopub.execute_input":"2024-10-26T21:14:10.442939Z","iopub.status.idle":"2024-10-26T21:14:10.610875Z","shell.execute_reply.started":"2024-10-26T21:14:10.442899Z","shell.execute_reply":"2024-10-26T21:14:10.609757Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Рассуждение: Этот код позволяет оценить наличие свистящих звуков. Высокая мощность в диапазоне 1000-3000 Гц может указывать на астму или бронхит. Однако для более точного анализа необходимо будет использовать более сложные алгоритмы обработки.","metadata":{}},{"cell_type":"markdown","source":"## 5. Темп и ритм кашля\nЭвристика: Анализ частоты кашля и ритма для определения патологии.","metadata":{}},{"cell_type":"code","source":"# Темп кашля (число кашлей на единицу времени)\n# Определяем интервалы между пиками\nintervals = np.diff(zero_crossings)  # Находим интервалы между нулевыми пересечениями\naverage_interval = np.mean(intervals) / sr  # Время между кашлями в секундах\n\nprint(f'Средний интервал между кашлями: {average_interval:.2f} сек')","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:17:32.067326Z","iopub.execute_input":"2024-10-26T21:17:32.067752Z","iopub.status.idle":"2024-10-26T21:17:32.074714Z","shell.execute_reply.started":"2024-10-26T21:17:32.067716Z","shell.execute_reply":"2024-10-26T21:17:32.073621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Рассуждение: Этот код вычисляет средний интервал между кашлями. Уменьшение интервалов может указывать на острые реакции, в то время как большие интервалы могут свидетельствовать о хронических заболеваниях. Однако это лишь косвенный показатель.","metadata":{}},{"cell_type":"code","source":"# Нормализация сигнала\n#y = y / np.max(np.abs(y))  # Нормализация амплитуды","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:32:50.260051Z","iopub.execute_input":"2024-10-26T21:32:50.260437Z","iopub.status.idle":"2024-10-26T21:32:50.266123Z","shell.execute_reply.started":"2024-10-26T21:32:50.260401Z","shell.execute_reply":"2024-10-26T21:32:50.264896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Нормализация сигнала\ny = y / np.max(np.abs(y))  # Нормализация амплитуды\n\n# Обнаружение начальных точек (пиков)\nonset_frames = librosa.onset.onset_detect(y=y, sr=sr, hop_length=512, backtrack=True)\nonset_times = librosa.frames_to_time(onset_frames, sr=sr)\n\n# Если нет пиков, можно вывести предупреждение\nif len(onset_times) < 2:\n    print(\"Недостаточно пиков для определения интервалов.\")\nelse:\n    # Находим интервалы между пиками\n    intervals = np.diff(onset_times)  # Время между кашлями в секундах\n    average_interval = np.mean(intervals)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:33:06.698171Z","iopub.execute_input":"2024-10-26T21:33:06.698615Z","iopub.status.idle":"2024-10-26T21:33:10.941692Z","shell.execute_reply.started":"2024-10-26T21:33:06.698574Z","shell.execute_reply":"2024-10-26T21:33:10.940535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(12, 6))\nplt.plot(np.arange(len(y)) / sr, y)\nplt.vlines(onset_times, -1, 1, color='r', label='Обнаруженные пики')\nplt.title('Сигнал кашля с обнаруженными пиками')\nplt.xlabel('Время (с)')\nplt.ylabel('Амплитуда')\nplt.legend()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:33:31.295275Z","iopub.execute_input":"2024-10-26T21:33:31.295938Z","iopub.status.idle":"2024-10-26T21:33:31.890265Z","shell.execute_reply.started":"2024-10-26T21:33:31.295896Z","shell.execute_reply":"2024-10-26T21:33:31.889302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"threshold = 0.05","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(12, 6))\nplt.plot(y)\nplt.axhline(threshold, color='red', linestyle='--', label='Порог')\nplt.scatter(peaks, y[peaks], color='green', label='Пики')\nplt.title('Сигнал кашля и определенные пики')\nplt.xlabel('Время (сэмплы)')\nplt.ylabel('Амплитуда')\nplt.legend()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:34:10.956527Z","iopub.execute_input":"2024-10-26T21:34:10.957054Z","iopub.status.idle":"2024-10-26T21:34:11.808647Z","shell.execute_reply.started":"2024-10-26T21:34:10.956991Z","shell.execute_reply":"2024-10-26T21:34:11.807517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6. Качество звука\nЭвристика: Анализ чистоты звука на наличие шума или искажений.","metadata":{}},{"cell_type":"code","source":"import librosa\nimport numpy as np\n\n# Загрузка аудиофайла\ny, sr = librosa.load('/kaggle/input/airs-ai-in-respiratory-sounds/sounds/sounds/007238490a3f1/cough.wav', sr=None)\n\n# Нормализация сигнала\nnormalized_y = y / np.max(np.abs(y))\n\n# Вычисление мощности сигнала\nsignal_power = np.mean(normalized_y**2)\n\n# Определим шум как все, что ниже определенного порога\nthreshold = 0.05  # Порог для отделения сигнала от шума\nnoise = normalized_y[normalized_y < threshold]\n\n# Вычисление мощности шума\nif len(noise) > 0:\n    noise_power = np.mean(noise**2)\nelse:\n    noise_power = 1e-10  # Минимальное значение для предотвращения деления на ноль\n\n# Вычисление SNR\nsnr = 10 * np.log10(signal_power / noise_power)\n\nprint(f'Отношение сигнал/шум (SNR): {snr:.2f} дБ')\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:36:29.129950Z","iopub.execute_input":"2024-10-26T21:36:29.130864Z","iopub.status.idle":"2024-10-26T21:36:29.150041Z","shell.execute_reply.started":"2024-10-26T21:36:29.130797Z","shell.execute_reply":"2024-10-26T21:36:29.148554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(12, 6))\nplt.plot(normalized_y)\nplt.title('Нормализованный сигнал кашля')\nplt.xlabel('Время (сэмплы)')\nplt.ylabel('Амплитуда')\nplt.axhline(threshold, color='red', linestyle='--', label='Порог шума')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:37:28.379607Z","iopub.execute_input":"2024-10-26T21:37:28.380738Z","iopub.status.idle":"2024-10-26T21:37:29.388892Z","shell.execute_reply.started":"2024-10-26T21:37:28.380677Z","shell.execute_reply":"2024-10-26T21:37:29.387869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Рассуждение: SNR может помочь определить, насколько чистым является звук кашля. Низкий уровень SNR может указывать на присутствие шума, что затрудняет интерпретацию. Однако это также зависит от качества записи.","metadata":{}},{"cell_type":"markdown","source":"## MFCC","metadata":{}},{"cell_type":"code","source":"import librosa\nimport librosa.display\nimport matplotlib.pyplot as plt\n\n# Загрузка аудиофайла\ny, sr = librosa.load('/kaggle/input/airs-ai-in-respiratory-sounds/sounds/sounds/004db89f19f9b/cough.wav', sr=None)\n\n# Вычисление MFCC\nmfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)\nmfccs_dB = librosa.power_to_db(mfccs, ref=np.max)\n\n# Визуализация MFCC\nplt.figure(figsize=(12, 6))\nlibrosa.display.specshow(mfccs_dB, sr=sr, x_axis='time', y_axis='mel')\nplt.title('MFCC спектрограмма')\nplt.colorbar(format='%+2.0f dB')\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:41:38.632306Z","iopub.execute_input":"2024-10-26T21:41:38.633084Z","iopub.status.idle":"2024-10-26T21:41:39.263360Z","shell.execute_reply.started":"2024-10-26T21:41:38.633041Z","shell.execute_reply":"2024-10-26T21:41:39.262289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## SFTT","metadata":{}},{"cell_type":"code","source":"# Вычисление STFT\nD = librosa.stft(y)\nS_db = librosa.amplitude_to_db(np.abs(D), ref=np.max)\n\n# Визуализация STFT спектрограммы\nplt.figure(figsize=(12, 6))\nlibrosa.display.specshow(S_db, sr=sr, x_axis='time', y_axis='log')\nplt.title('STFT спектрограмма')\nplt.colorbar(format='%+2.0f dB')\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:41:27.457028Z","iopub.execute_input":"2024-10-26T21:41:27.457792Z","iopub.status.idle":"2024-10-26T21:41:29.034722Z","shell.execute_reply.started":"2024-10-26T21:41:27.457748Z","shell.execute_reply":"2024-10-26T21:41:29.033604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## TorchAudio","metadata":{}},{"cell_type":"code","source":"import torch\nimport torchaudio\nimport torchaudio.functional as F\nimport torchaudio.transforms as T\n\nprint(torch.__version__)\nprint(torchaudio.__version__)\n\nimport librosa\nimport matplotlib.pyplot as plt\n\nfrom IPython.display import Audio\nfrom matplotlib.patches import Rectangle\nfrom torchaudio.utils import download_asset\n\ntorch.random.manual_seed(0)\n\nSAMPLE_SPEECH = download_asset(\"/kaggle/input/airs-ai-in-respiratory-sounds/sounds/sounds/004db89f19f9b/cough.wav\")\n\n# Load audio\nSPEECH_WAVEFORM, SAMPLE_RATE = torchaudio.load(SAMPLE_SPEECH)\n\n# Define transform\nspectrogram = T.Spectrogram(n_fft=512)\n\n# Perform transform\nspec = spectrogram(SPEECH_WAVEFORM)\n\n# Define transform\nspectrogram = T.Spectrogram(n_fft=512)\n\n# Perform transform\nspec = spectrogram(SPEECH_WAVEFORM)\n\n\ndef plot_waveform(waveform, sr, title=\"Waveform\", ax=None):\n    waveform = waveform.numpy()\n\n    num_channels, num_frames = waveform.shape\n    time_axis = torch.arange(0, num_frames) / sr\n\n    if ax is None:\n        _, ax = plt.subplots(num_channels, 1)\n    ax.plot(time_axis, waveform[0], linewidth=1)\n    ax.grid(True)\n    ax.set_xlim([0, time_axis[-1]])\n    ax.set_title(title)\n\n\ndef plot_spectrogram(specgram, title=None, ylabel=\"freq_bin\", ax=None):\n    if ax is None:\n        _, ax = plt.subplots(1, 1)\n    if title is not None:\n        ax.set_title(title)\n    ax.set_ylabel(ylabel)\n    ax.imshow(librosa.power_to_db(specgram), origin=\"lower\", aspect=\"auto\", interpolation=\"nearest\")\n\n\ndef plot_fbank(fbank, title=None):\n    fig, axs = plt.subplots(1, 1)\n    axs.set_title(title or \"Filter bank\")\n    axs.imshow(fbank, aspect=\"auto\")\n    axs.set_ylabel(\"frequency bin\")\n    axs.set_xlabel(\"mel bin\")","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:54:20.596807Z","iopub.execute_input":"2024-10-26T21:54:20.597220Z","iopub.status.idle":"2024-10-26T21:54:20.656383Z","shell.execute_reply.started":"2024-10-26T21:54:20.597181Z","shell.execute_reply":"2024-10-26T21:54:20.655128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(2, 1)\nplot_waveform(SPEECH_WAVEFORM, SAMPLE_RATE, title=\"Original waveform\", ax=axs[0])\nplot_spectrogram(spec[0], title=\"spectrogram\", ax=axs[1])\nfig.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:54:22.992209Z","iopub.execute_input":"2024-10-26T21:54:22.992640Z","iopub.status.idle":"2024-10-26T21:54:40.917895Z","shell.execute_reply.started":"2024-10-26T21:54:22.992598Z","shell.execute_reply":"2024-10-26T21:54:40.916849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_ffts = [32, 128, 512, 2048]\nhop_length = 64\n\nspecs = []\nfor n_fft in n_ffts:\n    spectrogram = T.Spectrogram(n_fft=n_fft, hop_length=hop_length)\n    spec = spectrogram(SPEECH_WAVEFORM)\n    specs.append(spec)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:50:22.548093Z","iopub.execute_input":"2024-10-26T21:50:22.548589Z","iopub.status.idle":"2024-10-26T21:50:22.896391Z","shell.execute_reply.started":"2024-10-26T21:50:22.548538Z","shell.execute_reply":"2024-10-26T21:50:22.895193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(len(specs), 1, sharex=True)\nfor i, (spec, n_fft) in enumerate(zip(specs, n_ffts)):\n    plot_spectrogram(spec[0], ylabel=f\"n_fft={n_fft}\", ax=axs[i])\n    axs[i].set_xlabel(None)\nfig.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:51:08.462510Z","iopub.execute_input":"2024-10-26T21:51:08.462976Z","iopub.status.idle":"2024-10-26T21:51:10.535661Z","shell.execute_reply.started":"2024-10-26T21:51:08.462931Z","shell.execute_reply":"2024-10-26T21:51:10.534635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Downsample to half of the original sample rate\nspeech2 = torchaudio.functional.resample(SPEECH_WAVEFORM, SAMPLE_RATE, SAMPLE_RATE // 2)\n# Upsample to the original sample rate\nspeech3 = torchaudio.functional.resample(speech2, SAMPLE_RATE // 2, SAMPLE_RATE)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:51:51.114711Z","iopub.execute_input":"2024-10-26T21:51:51.115165Z","iopub.status.idle":"2024-10-26T21:51:51.227141Z","shell.execute_reply.started":"2024-10-26T21:51:51.115121Z","shell.execute_reply":"2024-10-26T21:51:51.225909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Apply the same spectrogram\nspectrogram = T.Spectrogram(n_fft=512)\n\nspec0 = spectrogram(SPEECH_WAVEFORM)\nspec2 = spectrogram(speech2)\nspec3 = spectrogram(speech3)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:52:00.106313Z","iopub.execute_input":"2024-10-26T21:52:00.106733Z","iopub.status.idle":"2024-10-26T21:52:00.131504Z","shell.execute_reply.started":"2024-10-26T21:52:00.106691Z","shell.execute_reply":"2024-10-26T21:52:00.130381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Visualize it\nfig, axs = plt.subplots(3, 1)\nplot_spectrogram(spec0[0], ylabel=\"Original\", ax=axs[0])\naxs[0].add_patch(Rectangle((0, 3), 212, 128, edgecolor=\"r\", facecolor=\"none\"))\nplot_spectrogram(spec2[0], ylabel=\"Downsampled\", ax=axs[1])\nplot_spectrogram(spec3[0], ylabel=\"Upsampled\", ax=axs[2])\nfig.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:52:08.709993Z","iopub.execute_input":"2024-10-26T21:52:08.710443Z","iopub.status.idle":"2024-10-26T21:52:09.551207Z","shell.execute_reply.started":"2024-10-26T21:52:08.710385Z","shell.execute_reply":"2024-10-26T21:52:09.548914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_fft = 1024\nwin_length = None\nhop_length = 512\nn_mels = 128\n\nmel_spectrogram = T.MelSpectrogram(\n    sample_rate=16000,\n    n_fft=n_fft,\n    win_length=win_length,\n    hop_length=hop_length,\n    center=True,\n    pad_mode=\"reflect\",\n    power=2.0,\n    norm=\"slaney\",\n    n_mels=n_mels,\n    mel_scale=\"htk\",\n)\n\nmelspec = mel_spectrogram(SPEECH_WAVEFORM)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:59:46.998968Z","iopub.execute_input":"2024-10-26T21:59:46.999396Z","iopub.status.idle":"2024-10-26T21:59:47.018380Z","shell.execute_reply.started":"2024-10-26T21:59:46.999355Z","shell.execute_reply":"2024-10-26T21:59:47.017296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_spectrogram(melspec[0], title=\"MelSpectrogram - torchaudio\", ylabel=\"mel freq\")","metadata":{"execution":{"iopub.status.busy":"2024-10-26T22:00:00.816950Z","iopub.execute_input":"2024-10-26T22:00:00.818209Z","iopub.status.idle":"2024-10-26T22:00:01.178690Z","shell.execute_reply.started":"2024-10-26T22:00:00.818164Z","shell.execute_reply":"2024-10-26T22:00:01.177606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_fft = 2048\nwin_length = None\nhop_length = 512\nn_mels = 256\nn_mfcc = 256\n\nmfcc_transform = T.MFCC(\n    sample_rate=16000,\n    n_mfcc=n_mfcc,\n    melkwargs={\n        \"n_fft\": n_fft,\n        \"n_mels\": n_mels,\n        \"hop_length\": hop_length,\n        \"mel_scale\": \"htk\",\n    },\n)\n\nmfcc = mfcc_transform(SPEECH_WAVEFORM)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:55:56.164486Z","iopub.execute_input":"2024-10-26T21:55:56.165318Z","iopub.status.idle":"2024-10-26T21:55:56.196742Z","shell.execute_reply.started":"2024-10-26T21:55:56.165272Z","shell.execute_reply":"2024-10-26T21:55:56.195672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_spectrogram(mfcc[0], title=\"MFCC\")","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:56:00.739778Z","iopub.execute_input":"2024-10-26T21:56:00.740598Z","iopub.status.idle":"2024-10-26T21:56:01.073893Z","shell.execute_reply.started":"2024-10-26T21:56:00.740552Z","shell.execute_reply":"2024-10-26T21:56:01.072732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_fft = 2048\nwin_length = None\nhop_length = 512\nn_lfcc = 256\n\nlfcc_transform = T.LFCC(\n    sample_rate=16000,\n    n_lfcc=n_lfcc,\n    speckwargs={\n        \"n_fft\": n_fft,\n        \"win_length\": win_length,\n        \"hop_length\": hop_length,\n    },\n)\n\nlfcc = lfcc_transform(SPEECH_WAVEFORM)\nplot_spectrogram(lfcc[0], title=\"LFCC\")","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:56:36.405057Z","iopub.execute_input":"2024-10-26T21:56:36.405974Z","iopub.status.idle":"2024-10-26T21:56:36.764364Z","shell.execute_reply.started":"2024-10-26T21:56:36.405923Z","shell.execute_reply":"2024-10-26T21:56:36.763179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pitch = F.detect_pitch_frequency(SPEECH_WAVEFORM, SAMPLE_RATE)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:57:11.586878Z","iopub.execute_input":"2024-10-26T21:57:11.587853Z","iopub.status.idle":"2024-10-26T21:57:11.917334Z","shell.execute_reply.started":"2024-10-26T21:57:11.587794Z","shell.execute_reply":"2024-10-26T21:57:11.916220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_pitch(waveform, sr, pitch):\n    figure, axis = plt.subplots(1, 1)\n    axis.set_title(\"Pitch Feature\")\n    axis.grid(True)\n\n    end_time = waveform.shape[1] / sr\n    time_axis = torch.linspace(0, end_time, waveform.shape[1])\n    axis.plot(time_axis, waveform[0], linewidth=1, color=\"gray\", alpha=0.3)\n\n    axis2 = axis.twinx()\n    time_axis = torch.linspace(0, end_time, pitch.shape[1])\n    axis2.plot(time_axis, pitch[0], linewidth=2, label=\"Pitch\", color=\"green\")\n\n    axis2.legend(loc=0)\n\n\nplot_pitch(SPEECH_WAVEFORM, SAMPLE_RATE, pitch)","metadata":{"execution":{"iopub.status.busy":"2024-10-26T21:57:22.816431Z","iopub.execute_input":"2024-10-26T21:57:22.816862Z","iopub.status.idle":"2024-10-26T21:57:58.811480Z","shell.execute_reply.started":"2024-10-26T21:57:22.816787Z","shell.execute_reply":"2024-10-26T21:57:58.810345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}