|
| 1 | +# Contributing to PySDKit |
| 2 | + |
| 3 | +Thank you for helping grow PySDKit. This page is the contributor guide for |
| 4 | +the GitHub project; the same material lives in the documentation under |
| 5 | +[Development](https://pysdkit.readthedocs.io/en/stable/development/index.html). |
| 6 | + |
| 7 | +## Why PySDKit exists |
| 8 | + |
| 9 | +**Signal decomposition** treats a non-stationary recording as a sum of simpler |
| 10 | +modes (intrinsic mode functions). Those modes are a practical |
| 11 | +time-frequency / feature-engineering tool: they can be plotted, used as |
| 12 | +features, or fed to a downstream model. |
| 13 | + |
| 14 | +Fourier analysis assumes stationarity; fixed wavelet dictionaries still |
| 15 | +impose a predefined basis. Since the Hilbert–Huang Transform (1998), a |
| 16 | +family of adaptive univariate and multivariate decompositions has grown |
| 17 | +quickly in MATLAB, but Python (the usual home of machine learning) still |
| 18 | +lacks a library comparable to [PyWavelets](https://pywavelets.readthedocs.io/) |
| 19 | +for this class of algorithms. |
| 20 | + |
| 21 | +PySDKit was started in April 2024 to close that gap: one package, a |
| 22 | +shared `fit_transform` style API, and enough visualization that |
| 23 | +decomposition can sit next to NumPy, SciPy, and neural-network stacks |
| 24 | +without a MATLAB detour. |
| 25 | + |
| 26 | +Please cite the **original paper** of each algorithm you use; class and |
| 27 | +module docstrings point to those references. |
| 28 | + |
| 29 | +## Project layout: where a new algorithm belongs |
| 30 | + |
| 31 | +Implementation lives under `pysdkit/`. Algorithm families use a leading |
| 32 | +underscore (`pysdkit/_emd`, `pysdkit/_vmd`, …). Shared helpers live |
| 33 | +beside them (`pysdkit/data`, `pysdkit/plot`, `pysdkit/utils`, |
| 34 | +`pysdkit/tsa`, `pysdkit/entropy`, `pysdkit/models`). |
| 35 | + |
| 36 | +**Put a new method in the family it resembles.** If the principle is |
| 37 | +close to an existing package, add a module there and export it from that |
| 38 | +package’s `__init__.py`. If the idea is genuinely different, create a |
| 39 | +new package (for example `pysdkit/_yourmethod/`) rather than stretching |
| 40 | +an unrelated folder. |
| 41 | + |
| 42 | +| Package | Typical contents | Example gallery folder | |
| 43 | +|---|---|---| |
| 44 | +| `pysdkit/_emd` | EMD, EEMD, CEEMDAN, REMD, SEMD, TVF-EMD, ESMD, HHT; also MEMD / APITMEMD / NSTEMD | `examples/emd`, `examples/emd_variants`, `examples/memd` | |
| 45 | +| `pysdkit/_emd2d` | EMD2D, BMEMD | `examples/image` | |
| 46 | +| `pysdkit/_ewt` | EWT, EWT2D, EFD | `examples/ewt` | |
| 47 | +| `pysdkit/_faemd` | FAEMD (1-D / 2-D / 3-D) | `examples/faemd` | |
| 48 | +| `pysdkit/_vmd` | VMD, MVMD, OVMD, STVMD, SVMD, VME | `examples/vmd` | |
| 49 | +| `pysdkit/_vmd2d` | VMD2D, CVMD2D | `examples/image` | |
| 50 | +| `pysdkit/_acmd` | ACMD, BA-ACMD, DD-ACMD | `examples/acmd` | |
| 51 | +| `pysdkit/_vncmd` | VNCMD, AVNCMD, STNBMD | `examples/vncmd` | |
| 52 | +| `pysdkit/_gdmd` | GDMD, VGNMD, IVGNMD, AGNCMD | `examples/gdmd` | |
| 53 | +| `pysdkit/_tid` | ALIF, FMD, HVD, ITD, SSA | `examples/temp_iter`, `examples/ssa` | |
| 54 | +| `pysdkit/_tfa` | SST, SET, VTFMTD | `examples/tfa` | |
| 55 | +| `pysdkit/_lmd` | LMD, RLMD | `examples/lmd` | |
| 56 | +| `pysdkit/_osd` | OSD, SWD | `examples/osd` | |
| 57 | +| `pysdkit/_imd` | IMD, APMD | `examples/imd` | |
| 58 | +| `pysdkit/_jmd` | JMD, SJMD | `examples/jmd` | |
| 59 | +| `pysdkit/tsa` | STL, MSTL, moving-average decomposition | `examples/tsa` | |
| 60 | +| `pysdkit/utils` | BSS, deconvolution, kurtogram | `examples/utils`, `examples/deconvolution` | |
| 61 | + |
| 62 | +After the implementation: |
| 63 | + |
| 64 | +1. Export the public class / function from the family `__init__.py`. |
| 65 | +2. Re-export it from `pysdkit/__init__.py` and add the name to `__all__`. |
| 66 | +3. Add a thin `autoclass` / `autofunction` line on the matching page under |
| 67 | + `docs/source/API/`. |
| 68 | +4. Prefer `pysdkit.data` loaders for demo arrays; put `.npy` files in |
| 69 | + `pysdkit/data/real_world`. |
| 70 | + |
| 71 | +Do not import the gitignored `repo/` tree (local MATLAB / paper sources) |
| 72 | +from installed code or from examples. |
| 73 | + |
| 74 | +## Tests |
| 75 | + |
| 76 | +Please add unit tests in `pysdkit/tests/` so the public surface stays |
| 77 | +stable. Name the file `test_<algo>.py` and follow the existing |
| 78 | +`unittest` style (see `pysdkit/tests/test_emd.py`, `test_vmd.py`). |
| 79 | + |
| 80 | +Aim to cover **every public class and method** you introduce, not only a |
| 81 | +single happy-path call. A useful minimum is: |
| 82 | + |
| 83 | +- construction / default parameters |
| 84 | +- `fit_transform` (shape: modes × samples, length matches the input) |
| 85 | +- `__call__` if the class is callable |
| 86 | +- functional aliases (`emd`, `vmd`, …) when you export them |
| 87 | +- invalid inputs (`ValueError` / `TypeError`) |
| 88 | +- a trivial or reconstructible signal when the algorithm claims completeness |
| 89 | + |
| 90 | +Use `pysdkit.data` generators (`test_emd`, `test_univariate_signal`, …) |
| 91 | +instead of huge private fixtures. |
| 92 | + |
| 93 | +```bash |
| 94 | +python -m unittest discover -s pysdkit/tests -p "test_*.py" -v |
| 95 | +``` |
| 96 | + |
| 97 | +## Examples |
| 98 | + |
| 99 | +Please ship a gallery script that shows the algorithm on a small demo |
| 100 | +(theory plus figures). Examples are **Python files**, not notebooks. |
| 101 | + |
| 102 | +- Put the script in the matching folder under `examples/` (see the table |
| 103 | + above). A new family gets a new folder and a `GALLERY_HEADER.rst` with |
| 104 | + a title. |
| 105 | +- Start with a **raw** title docstring (`r"""..."""`). Extra theory goes |
| 106 | + in `# %%` comment blocks (Sphinx-Gallery turns those into HTML text and |
| 107 | + into markdown cells in the generated `.ipynb` download). |
| 108 | +- Do **not** inject `sys.path` and do **not** use `__file__`. The docs |
| 109 | + build already installs the package. |
| 110 | +- Prefer `pysdkit.data` over local `.mat` files. |
| 111 | + |
| 112 | +```python |
| 113 | +r""" |
| 114 | +My algorithm |
| 115 | +============ |
| 116 | +
|
| 117 | +Short theory paragraph and a paper reference. |
| 118 | +""" |
| 119 | + |
| 120 | +# %% |
| 121 | +# Demo |
| 122 | +# ---- |
| 123 | + |
| 124 | +import numpy as np |
| 125 | +from pysdkit import EMD |
| 126 | +from pysdkit.plot import plot_IMFs |
| 127 | +``` |
| 128 | + |
| 129 | +Look at `examples/emd/emd.py` or `examples/vmd/` for the expected tone: |
| 130 | +motivation, a compact statement of the method, then executable plots. |
| 131 | + |
| 132 | +The docs gallery is generated by Sphinx-Gallery; see |
| 133 | +[`.github/docs-build.md`](.github/docs-build.md) if you need to rebuild |
| 134 | +HTML locally. |
| 135 | + |
| 136 | +## Pull requests |
| 137 | + |
| 138 | +- Keep the change focused: one algorithm (or one tightly related family) |
| 139 | + per PR is easier to review. |
| 140 | +- Run the unit tests before you open the PR. |
| 141 | +- English for public docstrings, gallery headers, and commit messages. |
0 commit comments