{ "cells": [ { "cell_type": "markdown", "id": "79345bf6", "metadata": {}, "source": [ "# Fourier Processor\n", "\n", "The `Fourier` processor performs a sliding-window FFT (Short-Time Fourier Transform) on a time series. It slides a window over the series, computes an FFT per window and aggregates the amplitude spectrum into frequency ranges. The result is a multivariate time series where each column is a frequency range." ] }, { "cell_type": "code", "execution_count": 1, "id": "c43db203", "metadata": { "execution": { "iopub.execute_input": "2026-07-22T22:22:59.859557Z", "iopub.status.busy": "2026-07-22T22:22:59.859312Z", "iopub.status.idle": "2026-07-22T22:22:59.865354Z", "shell.execute_reply": "2026-07-22T22:22:59.864710Z" } }, "outputs": [], "source": [ "# Import to be able to import python package from src\n", "import sys\n", "sys.path.insert(0, '../../src')" ] }, { "cell_type": "code", "execution_count": 2, "id": "0a6f35b1", "metadata": { "execution": { "iopub.execute_input": "2026-07-22T22:22:59.866710Z", "iopub.status.busy": "2026-07-22T22:22:59.866625Z", "iopub.status.idle": "2026-07-22T22:23:05.782793Z", "shell.execute_reply": "2026-07-22T22:23:05.782394Z" } }, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import ontime as on" ] }, { "cell_type": "markdown", "id": "b491e9fc", "metadata": {}, "source": [ "---\n", "## Generation of a signal with two frequencies\n", "\n", "We build a signal made of a slow sine wave (period of 48 samples) that is present all along, plus a fast sine wave (period of 6 samples) that only appears in the second half of the series." ] }, { "cell_type": "code", "execution_count": 3, "id": "44319a61", "metadata": { "execution": { "iopub.execute_input": "2026-07-22T22:23:05.784737Z", "iopub.status.busy": "2026-07-22T22:23:05.784570Z", "iopub.status.idle": "2026-07-22T22:23:05.790068Z", "shell.execute_reply": "2026-07-22T22:23:05.789629Z" } }, "outputs": [], "source": [ "n = 512\n", "index = pd.date_range('2022-01-01', periods=n, freq='h')\n", "t = np.arange(n)\n", "\n", "slow = np.sin(2 * np.pi * t / 48)\n", "fast = np.sin(2 * np.pi * t / 6) * (t >= n // 2)\n", "\n", "ts = on.TimeSeries.from_times_and_values(index, slow + fast)" ] }, { "cell_type": "code", "execution_count": 4, "id": "5bdaee4f", "metadata": { "execution": { "iopub.execute_input": "2026-07-22T22:23:05.791623Z", "iopub.status.busy": "2026-07-22T22:23:05.791544Z", "iopub.status.idle": "2026-07-22T22:23:08.776986Z", "shell.execute_reply": "2026-07-22T22:23:08.776505Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "" ], "text/plain": [ "alt.LayerChart(...)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ts.plot()" ] }, { "cell_type": "markdown", "id": "ad26ba60", "metadata": {}, "source": [ "---\n", "## Apply the FFT on sliding windows\n", "\n", "The parameters are:\n", "\n", "- `window_size`: number of samples per FFT window\n", "- `step_size`: number of samples the window slides by\n", "- `n_bins`: number of frequency ranges in the output\n", "- `frequency_cap`: optional `(min, max)` tuple to restrict the frequency range\n", "\n", "Frequencies are expressed in cycles per sample, from 0 to 0.5 (the Nyquist frequency). Here, the slow wave has a frequency of 1/48 ≈ 0.02 and the fast wave 1/6 ≈ 0.17 cycles per sample." ] }, { "cell_type": "code", "execution_count": 5, "id": "66fe2beb", "metadata": { "execution": { "iopub.execute_input": "2026-07-22T22:23:08.778484Z", "iopub.status.busy": "2026-07-22T22:23:08.778387Z", "iopub.status.idle": "2026-07-22T22:23:08.793198Z", "shell.execute_reply": "2026-07-22T22:23:08.792821Z" } }, "outputs": [ { "data": { "text/html": [ "<TimeSeries (DataArray) (time: 5, component: 8, sample: 1)> Size: 320B\n",
"array([[[0.22070334],\n",
" [0.03416374],\n",
" [0.01765641],\n",
" [0.01251935],\n",
" [0.01005724],\n",
" [0.00870652],\n",
" [0.00795725],\n",
" [0.00759005]],\n",
"\n",
" [[0.22255655],\n",
" [0.02869736],\n",
" [0.01428615],\n",
" [0.01003409],\n",
" [0.0080311 ],\n",
" [0.00694045],\n",
" [0.00633767],\n",
" [0.00604279]],\n",
"\n",
" [[0.18277584],\n",
" [0.05702162],\n",
"...\n",
" [0.01428417],\n",
" [0.01363151]],\n",
"\n",
" [[0.22070334],\n",
" [0.03416374],\n",
" [0.01765641],\n",
" [0.01251935],\n",
" [0.01005724],\n",
" [0.00870652],\n",
" [0.00795725],\n",
" [0.00759005]],\n",
"\n",
" [[0.22255655],\n",
" [0.02869736],\n",
" [0.01428615],\n",
" [0.01003409],\n",
" [0.0080311 ],\n",
" [0.00694045],\n",
" [0.00633767],\n",
" [0.00604279]]])\n",
"Coordinates:\n",
" * time (time) datetime64[ns] 40B 2022-01-03T15:00:00 ... 2022-01-04T2...\n",
" * component (component) object 64B 'freq_0.0000_0.0625' ... 'freq_0.4375_0...\n",
"Dimensions without coordinates: sample\n",
"Attributes:\n",
" static_covariates: None\n",
" hierarchy: None<TimeSeries (DataArray) (time: 5, component: 4, sample: 1)> Size: 160B\n",
"array([[[0.02237228],\n",
" [0.01662483],\n",
" [0.01334846],\n",
" [0.01137745]],\n",
"\n",
" [[0.01826692],\n",
" [0.01342067],\n",
" [0.01071169],\n",
" [0.00910219]],\n",
"\n",
" [[0.03891696],\n",
" [0.02935155],\n",
" [0.02374411],\n",
" [0.02031414]],\n",
"\n",
" [[0.02237228],\n",
" [0.01662483],\n",
" [0.01334846],\n",
" [0.01137745]],\n",
"\n",
" [[0.01826692],\n",
" [0.01342067],\n",
" [0.01071169],\n",
" [0.00910219]]])\n",
"Coordinates:\n",
" * time (time) datetime64[ns] 40B 2022-01-03T15:00:00 ... 2022-01-04T2...\n",
" * component (component) object 32B 'freq_0.1000_0.1375' ... 'freq_0.2125_0...\n",
"Dimensions without coordinates: sample\n",
"Attributes:\n",
" static_covariates: None\n",
" hierarchy: None