Skip to content

Commit 29f7024

Browse files
committed
Added benchmark notebook
1 parent 79892e8 commit 29f7024

File tree

3 files changed

+236
-16
lines changed

3 files changed

+236
-16
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Features
3535
|**fCWT for real-time Electroencephalography (EEG) analysis** |**fCWT for real-time engine diagnostics** |
3636
|<img src="https://github.com/fastlib/fCWT/blob/main/img/eeg2.png" alt="fcwteeg2" width="400"/>|<img src="https://github.com/fastlib/fCWT/blob/main/img/engine.png" alt="fcwtengine" width="400"/>|
3737

38-
*Based on C++ performance. fCWT is the fastest CWT library in C++ and Matlab. In Python CCWT is faster for shorter signals and fCWT for longer signals. Please see the benchmark section for more details. Raise an issue if you found a new/faster implementation. I will try to add it to benchmark!
38+
*Based on C++ performance. **fCWT is the fastest CWT library in C++, Python and Matlab!** Please see the benchmark section for more details. Raise an issue if you found a new/faster implementation. I will try to add it to benchmark!
3939

4040
Quickstart
4141
============
@@ -88,16 +88,16 @@ See the Installation section for more details about building fCWT from source fo
8888
Benchmark
8989
========
9090

91-
Columns are formatted as X-Y, where X is signal length in samples and Y the number of frequencies. The benchmark has been performed on a MacBook Pro 2019 having a 2,3 GHz Intel Core i9 4.5 Ghz Boost, 16 GB 2400 MHz DDR4.
91+
Columns are formatted as X-Y, where X is signal length in samples and Y the number of frequencies. The benchmark has been performed on a MacBook Pro 2019 having a 2,3 GHz Intel Core i9 4.5 Ghz Boost, 16 GB 2400 MHz DDR4. See the 'Usage: Benchmark' section for more details about the C++ benchmark. See the [Benchmark Notebook](https://github.com/fastlib/fCWT/blob/main/benchmark.ipynb) for the fCWT Python benchmark.
9292

9393
| Implementation | 10k-300 | 10k-3000 | 100k-300 | 100k-3000 | Speedup factor |
9494
|-----------------------|---------|----------|----------|-----------|----------------|
9595
| fCWT (C++) | 0.005s | 0.04s | 0.03s | 0.32s | - |
96-
| fCWT (Python) | 0.027s | 0.23s | 0.05s | 0.49s | - |
96+
| fCWT (Python) | 0.011s | 0.089s | 0.074s | 0.66s | - |
9797
| fCWT (Matlab) | 0.072s | 0.44s | 0.17s | 1.55s | - |
9898
| | | | | | |
9999
| [CCWT] (Python) | 0.019s | 0.11s | 0.15s | 3.40s | 10.63x |
100-
| [PyWavelets] (Python) | 0.10s | 1.17s | 1.06s | 12.69s | 34.29x |
100+
| [PyWavelets] (Python) | 0.10s | 1.17s | 1.06s | 12.69s | 34.29x |
101101
| Matlab | 0.75s | 0.86s | 1.06s | 13.26s | 35.85x |
102102
| [SsqueezePy] (Python) | 0.04s | 0.43s | 1.16s | 17.76s | 48.00x |
103103
| SciPy (Python) | 0.19s | 1.82s | 2.11s | 18.70s | 50.54x |

benchmark.ipynb

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"import fcwt\n",
10+
"import numpy as np\n",
11+
"import timeit"
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": 2,
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"fs = 100\n",
21+
"\n",
22+
"n10k = 10000\n",
23+
"n100k = 100000\n",
24+
"\n",
25+
"#Generate signals\n",
26+
"sig_100k = np.sin(2*np.pi*((0.1+(2*np.arange(n100k))/n100k)*(np.arange(n100k)/fs)))\n",
27+
"sig_10k = np.sin(2*np.pi*((0.1+(2*np.arange(n10k))/n10k)*(np.arange(n10k)/fs)))\n"
28+
]
29+
},
30+
{
31+
"cell_type": "code",
32+
"execution_count": 3,
33+
"metadata": {},
34+
"outputs": [],
35+
"source": [
36+
"f0 = 1\n",
37+
"f1 = 101\n",
38+
"fn300 = 300\n",
39+
"fn3000 = 3000\n",
40+
"\n",
41+
"#make sure signal is a numpy float array\n",
42+
"sig_100k = np.array(sig_100k, dtype=np.float32)\n",
43+
"sig_10k = np.array(sig_10k, dtype=np.float32)\n",
44+
"\n",
45+
"#initialize Morlet wavelet with wavelet parameter (sigma) 2.0\n",
46+
"morl = fcwt.Morlet(2.0)\n",
47+
"\n",
48+
"#initialize scales\n",
49+
"scales300 = fcwt.Scales(morl, fcwt.FCWT_LINFREQS, fs, f0, f1, fn300)\n",
50+
"scales3000 = fcwt.Scales(morl, fcwt.FCWT_LINFREQS, fs, f0, f1, fn3000)\n",
51+
"\n",
52+
"#initialize fcwt\n",
53+
"nthreads = 8\n",
54+
"use_optimization_plan = True\n",
55+
"use_normalization = False\n",
56+
"fcwt_obj = fcwt.FCWT(morl, nthreads, use_optimization_plan, use_normalization)\n",
57+
"\n",
58+
"#initialize output array\n",
59+
"output_10k_300 = np.zeros((fn300,sig_10k.size), dtype=np.complex64)\n",
60+
"output_100k_300 = np.zeros((fn300,sig_100k.size), dtype=np.complex64)\n",
61+
"output_10k_3000 = np.zeros((fn3000,sig_100k.size), dtype=np.complex64)\n",
62+
"output_100k_3000 = np.zeros((fn3000,sig_100k.size), dtype=np.complex64)"
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": 11,
68+
"metadata": {},
69+
"outputs": [
70+
{
71+
"name": "stdout",
72+
"output_type": "stream",
73+
"text": [
74+
"Threads:8\n",
75+
"Calculating optimal scheme for forward FFT with N:2048\n",
76+
"Calculating optimal scheme for backward FFT with N:2048\n",
77+
"Optimization schemes for N: 2048 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n",
78+
"Threads:8\n",
79+
"Calculating optimal scheme for forward FFT with N:4096\n",
80+
"Calculating optimal scheme for backward FFT with N:4096\n",
81+
"Optimization schemes for N: 4096 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n",
82+
"Threads:8\n",
83+
"Calculating optimal scheme for forward FFT with N:8192\n",
84+
"Calculating optimal scheme for backward FFT with N:8192\n",
85+
"Optimization schemes for N: 8192 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n",
86+
"Threads:8\n",
87+
"Calculating optimal scheme for forward FFT with N:16384\n",
88+
"Calculating optimal scheme for backward FFT with N:16384\n",
89+
"Optimization schemes for N: 16384 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n",
90+
"Threads:8\n",
91+
"Calculating optimal scheme for forward FFT with N:32768\n",
92+
"Calculating optimal scheme for backward FFT with N:32768\n",
93+
"Optimization schemes for N: 32768 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n",
94+
"Threads:8\n",
95+
"Calculating optimal scheme for forward FFT with N:65536\n",
96+
"Calculating optimal scheme for backward FFT with N:65536\n",
97+
"Optimization schemes for N: 65536 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n",
98+
"Threads:8\n",
99+
"Calculating optimal scheme for forward FFT with N:131072\n",
100+
"Calculating optimal scheme for backward FFT with N:131072\n",
101+
"Optimization schemes for N: 131072 have been calculated. Next time you use fCWT it will automatically choose the right optimization scheme based on number of threads and signal length.\n"
102+
]
103+
}
104+
],
105+
"source": [
106+
"fcwt_obj.create_FFT_optimization_plan(100000,\"FFTW_MEASURE\")"
107+
]
108+
},
109+
{
110+
"cell_type": "code",
111+
"execution_count": 12,
112+
"metadata": {},
113+
"outputs": [
114+
{
115+
"name": "stdout",
116+
"output_type": "stream",
117+
"text": [
118+
"10k-300: 0.011435500299921842 seconds\n"
119+
]
120+
}
121+
],
122+
"source": [
123+
"#10k-300\n",
124+
"a = timeit.timeit('fcwt_obj.cwt(sig_10k, scales300, output_10k_300)', number=10, globals=globals())\n",
125+
"print(\"10k-300: \", a/10, \"seconds\")"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": 13,
131+
"metadata": {},
132+
"outputs": [
133+
{
134+
"name": "stdout",
135+
"output_type": "stream",
136+
"text": [
137+
"100k-300: 0.07430814850004026 seconds\n"
138+
]
139+
}
140+
],
141+
"source": [
142+
"#100k-300\n",
143+
"a = timeit.timeit('fcwt_obj.cwt(sig_100k, scales300, output_100k_300)', number=10, globals=globals())\n",
144+
"print(\"100k-300: \", a/10, \"seconds\")"
145+
]
146+
},
147+
{
148+
"cell_type": "code",
149+
"execution_count": 14,
150+
"metadata": {},
151+
"outputs": [
152+
{
153+
"name": "stdout",
154+
"output_type": "stream",
155+
"text": [
156+
"10k-3000: 0.08949035639998329 seconds\n"
157+
]
158+
}
159+
],
160+
"source": [
161+
"#10k-3000\n",
162+
"a = timeit.timeit('fcwt_obj.cwt(sig_10k, scales3000, output_10k_3000)', number=10, globals=globals())\n",
163+
"print(\"10k-3000: \", a/10, \"seconds\")"
164+
]
165+
},
166+
{
167+
"cell_type": "code",
168+
"execution_count": 17,
169+
"metadata": {},
170+
"outputs": [
171+
{
172+
"name": "stdout",
173+
"output_type": "stream",
174+
"text": [
175+
"100k-3000: 0.6612934732000213 seconds\n"
176+
]
177+
}
178+
],
179+
"source": [
180+
"#100k-3000\n",
181+
"a = timeit.timeit('fcwt_obj.cwt(sig_100k, scales3000, output_100k_3000)', number=10, globals=globals())\n",
182+
"print(\"100k-3000: \", a/10, \"seconds\")"
183+
]
184+
},
185+
{
186+
"cell_type": "code",
187+
"execution_count": null,
188+
"metadata": {},
189+
"outputs": [],
190+
"source": []
191+
}
192+
],
193+
"metadata": {
194+
"kernelspec": {
195+
"display_name": "Python 3",
196+
"language": "python",
197+
"name": "python3"
198+
},
199+
"language_info": {
200+
"codemirror_mode": {
201+
"name": "ipython",
202+
"version": 3
203+
},
204+
"file_extension": ".py",
205+
"mimetype": "text/x-python",
206+
"name": "python",
207+
"nbconvert_exporter": "python",
208+
"pygments_lexer": "ipython3",
209+
"version": "3.10.9"
210+
},
211+
"orig_nbformat": 4,
212+
"vscode": {
213+
"interpreter": {
214+
"hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
215+
}
216+
}
217+
},
218+
"nbformat": 4,
219+
"nbformat_minor": 2
220+
}

tutorial.ipynb

Lines changed: 12 additions & 12 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)