ringdownanalysis 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ringdownanalysis-0.1.0/PKG-INFO +453 -0
- ringdownanalysis-0.1.0/README.md +411 -0
- ringdownanalysis-0.1.0/pyproject.toml +174 -0
- ringdownanalysis-0.1.0/ringdownanalysis/__init__.py +105 -0
- ringdownanalysis-0.1.0/ringdownanalysis/analyzer.py +581 -0
- ringdownanalysis-0.1.0/ringdownanalysis/batch_analyzer.py +737 -0
- ringdownanalysis-0.1.0/ringdownanalysis/compat.py +140 -0
- ringdownanalysis-0.1.0/ringdownanalysis/crlb.py +256 -0
- ringdownanalysis-0.1.0/ringdownanalysis/data_loader.py +327 -0
- ringdownanalysis-0.1.0/ringdownanalysis/estimators.py +782 -0
- ringdownanalysis-0.1.0/ringdownanalysis/legacy_ring_down_mc.py +905 -0
- ringdownanalysis-0.1.0/ringdownanalysis/monte_carlo.py +582 -0
- ringdownanalysis-0.1.0/ringdownanalysis/plots.py +511 -0
- ringdownanalysis-0.1.0/ringdownanalysis/signal.py +152 -0
- ringdownanalysis-0.1.0/ringdownanalysis.egg-info/PKG-INFO +453 -0
- ringdownanalysis-0.1.0/ringdownanalysis.egg-info/SOURCES.txt +26 -0
- ringdownanalysis-0.1.0/ringdownanalysis.egg-info/dependency_links.txt +1 -0
- ringdownanalysis-0.1.0/ringdownanalysis.egg-info/requires.txt +22 -0
- ringdownanalysis-0.1.0/ringdownanalysis.egg-info/top_level.txt +1 -0
- ringdownanalysis-0.1.0/setup.cfg +4 -0
- ringdownanalysis-0.1.0/tests/test_analyzer.py +259 -0
- ringdownanalysis-0.1.0/tests/test_batch_analysis_methods.py +332 -0
- ringdownanalysis-0.1.0/tests/test_batch_analyzer.py +488 -0
- ringdownanalysis-0.1.0/tests/test_compat.py +74 -0
- ringdownanalysis-0.1.0/tests/test_crlb.py +151 -0
- ringdownanalysis-0.1.0/tests/test_data_loader.py +257 -0
- ringdownanalysis-0.1.0/tests/test_estimators.py +256 -0
- ringdownanalysis-0.1.0/tests/test_signal.py +96 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ringdownanalysis
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Frequency estimation of ring-down signals using NLS and DFT methods
|
|
5
|
+
Author-email: Miguel Dovale <mdovale@arizona.edu>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mdovale/RingDownAnalysis
|
|
8
|
+
Project-URL: Repository, https://github.com/mdovale/RingDownAnalysis
|
|
9
|
+
Project-URL: Issues, https://github.com/mdovale/RingDownAnalysis/issues
|
|
10
|
+
Keywords: signal-processing,frequency-estimation,ring-down,cramér-rao,crlb
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: numpy>=1.20.0
|
|
24
|
+
Requires-Dist: scipy>=1.7.0
|
|
25
|
+
Requires-Dist: matplotlib>=3.5.0
|
|
26
|
+
Requires-Dist: tqdm>=4.60.0
|
|
27
|
+
Requires-Dist: joblib>=1.0.0
|
|
28
|
+
Requires-Dist: pandas>=1.3.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: sphinx>=7.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "dev"
|
|
37
|
+
Provides-Extra: examples
|
|
38
|
+
Requires-Dist: pandas>=1.3.0; extra == "examples"
|
|
39
|
+
Requires-Dist: jupyter>=1.0.0; extra == "examples"
|
|
40
|
+
Provides-Extra: all
|
|
41
|
+
Requires-Dist: ringdownanalysis[dev,examples]; extra == "all"
|
|
42
|
+
|
|
43
|
+
# Frequency and quality factor estimation of exponentially decaying sinusoids
|
|
44
|
+
|
|
45
|
+
This repository contains theoretical analysis, numerical simulations, and experimental data analysis for frequency estimation of ring-down signals. Ring-down signals are exponentially decaying sinusoids that arise from measurements of harmonic oscillators with quality factor Q, where the amplitude decays exponentially due to energy dissipation.
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
### Installation
|
|
50
|
+
|
|
51
|
+
Since this package is not yet available on PyPI, install it from source:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Clone the repository
|
|
55
|
+
git clone https://github.com/mdovale/RingDownAnalysis.git
|
|
56
|
+
cd RingDownAnalysis
|
|
57
|
+
|
|
58
|
+
# Install in editable mode
|
|
59
|
+
pip install -e .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For development with testing and linting tools:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install -e ".[dev]"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
For examples and notebooks:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install -e ".[examples]"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Or install everything:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install -e ".[all]"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Basic Usage
|
|
81
|
+
|
|
82
|
+
#### Generate and Analyze a Ring-Down Signal
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from ringdownanalysis import RingDownSignal, NLSFrequencyEstimator, DFTFrequencyEstimator
|
|
86
|
+
import numpy as np
|
|
87
|
+
|
|
88
|
+
# Generate a ring-down signal
|
|
89
|
+
signal = RingDownSignal(
|
|
90
|
+
f0=5.0, # Frequency (Hz)
|
|
91
|
+
fs=100.0, # Sampling frequency (Hz)
|
|
92
|
+
N=10000, # Number of samples
|
|
93
|
+
A0=1.0, # Initial amplitude
|
|
94
|
+
snr_db=60.0, # Initial SNR (dB)
|
|
95
|
+
Q=10000.0, # Quality factor
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
rng = np.random.default_rng(42)
|
|
99
|
+
t, x, phi0 = signal.generate(rng=rng)
|
|
100
|
+
|
|
101
|
+
# Estimate frequency using NLS method
|
|
102
|
+
nls_estimator = NLSFrequencyEstimator(tau_known=None)
|
|
103
|
+
f_nls = nls_estimator.estimate(x, signal.fs)
|
|
104
|
+
|
|
105
|
+
# Estimate frequency using DFT method
|
|
106
|
+
dft_estimator = DFTFrequencyEstimator(window="rect")
|
|
107
|
+
f_dft = dft_estimator.estimate(x, signal.fs)
|
|
108
|
+
|
|
109
|
+
print(f"True frequency: {signal.f0:.6f} Hz")
|
|
110
|
+
print(f"NLS estimate: {f_nls:.6f} Hz")
|
|
111
|
+
print(f"DFT estimate: {f_dft:.6f} Hz")
|
|
112
|
+
|
|
113
|
+
# Or estimate frequency, tau, and Q together
|
|
114
|
+
result_nls = nls_estimator.estimate_full(x, signal.fs)
|
|
115
|
+
result_dft = dft_estimator.estimate_full(x, signal.fs)
|
|
116
|
+
|
|
117
|
+
print(f"\nNLS full result: f={result_nls.f:.6f} Hz, tau={result_nls.tau:.2f} s, Q={result_nls.Q:.2e}")
|
|
118
|
+
print(f"DFT full result: f={result_dft.f:.6f} Hz, tau={result_dft.tau:.2f} s, Q={result_dft.Q:.2e}")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Analyze Experimental Data
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from ringdownanalysis import BatchRingDownAnalyzer
|
|
125
|
+
import pandas as pd
|
|
126
|
+
|
|
127
|
+
# Initialize batch analyzer
|
|
128
|
+
batch_analyzer = BatchRingDownAnalyzer()
|
|
129
|
+
|
|
130
|
+
# Process all files in data directory
|
|
131
|
+
results = batch_analyzer.process_directory("data", verbose=True)
|
|
132
|
+
|
|
133
|
+
# Get summary table
|
|
134
|
+
summary = batch_analyzer.get_summary_table()
|
|
135
|
+
df_summary = pd.DataFrame(summary['data'])
|
|
136
|
+
print(df_summary)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See `examples/usage_example.py` and `examples/batch_analysis_example.py` for more complete examples.
|
|
140
|
+
|
|
141
|
+
#### Configure Logging
|
|
142
|
+
|
|
143
|
+
The package uses `NullHandler` by default (no log output). For easier debugging, enable console logging:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
import logging
|
|
147
|
+
from ringdownanalysis import configure_logging, BatchRingDownAnalyzer
|
|
148
|
+
|
|
149
|
+
# Quick setup: INFO-level console output
|
|
150
|
+
configure_logging(level=logging.INFO)
|
|
151
|
+
|
|
152
|
+
analyzer = BatchRingDownAnalyzer()
|
|
153
|
+
results = analyzer.process_directory("data")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
For production (file + console, rotation, structured format):
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from examples.logging_config_example import setup_production_logging
|
|
160
|
+
import logging
|
|
161
|
+
|
|
162
|
+
setup_production_logging(log_dir='logs', log_level=logging.INFO)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
See `examples/logging_config_example.py` for more logging configuration options.
|
|
166
|
+
|
|
167
|
+
## Overview
|
|
168
|
+
|
|
169
|
+
The project compares two complementary approaches for frequency estimation:
|
|
170
|
+
|
|
171
|
+
1. **Nonlinear Least Squares (NLS)** with explicit ring-down model
|
|
172
|
+
2. **Frequency-Domain Methods (DFT)** with Lorentzian peak fitting
|
|
173
|
+
|
|
174
|
+
Both methods are evaluated against the Cramér-Rao Lower Bound (CRLB) derived from the explicit Fisher information matrix for ring-down signals.
|
|
175
|
+
|
|
176
|
+
## Features
|
|
177
|
+
|
|
178
|
+
### Object-Oriented API
|
|
179
|
+
|
|
180
|
+
The package provides a modern object-oriented API:
|
|
181
|
+
|
|
182
|
+
- **`RingDownSignal`**: Generate synthetic ring-down signals with specified parameters
|
|
183
|
+
- **`FrequencyEstimator`**: Base class for frequency estimation methods
|
|
184
|
+
- **`NLSFrequencyEstimator`**: Nonlinear least squares estimation
|
|
185
|
+
- `estimate()`: Returns frequency only
|
|
186
|
+
- `estimate_full()`: Returns `EstimationResult` with frequency, tau, and Q
|
|
187
|
+
- **`DFTFrequencyEstimator`**: DFT-based estimation with Lorentzian fitting
|
|
188
|
+
- `estimate()`: Returns frequency only
|
|
189
|
+
- `estimate_full()`: Returns `EstimationResult` with frequency, tau (via NLS with fixed frequency), and Q
|
|
190
|
+
- **`EstimationResult`**: Named tuple containing (f, tau, Q) estimates
|
|
191
|
+
- **`CRLBCalculator`**: Calculate Cramér-Rao Lower Bound for frequency estimation
|
|
192
|
+
- **`RingDownAnalyzer`**: Analyze individual ring-down data files
|
|
193
|
+
- **`BatchRingDownAnalyzer`**: Batch process multiple data files
|
|
194
|
+
- **`MonteCarloAnalyzer`**: Run Monte Carlo simulations to compare methods
|
|
195
|
+
|
|
196
|
+
### Compatibility Layer
|
|
197
|
+
|
|
198
|
+
A function-based compatibility layer is also available for backward compatibility:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from ringdownanalysis import (
|
|
202
|
+
generate_ringdown,
|
|
203
|
+
estimate_freq_nls_ringdown,
|
|
204
|
+
estimate_freq_dft,
|
|
205
|
+
crlb_var_f_ringdown_explicit,
|
|
206
|
+
monte_carlo_analysis,
|
|
207
|
+
)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Usage Examples
|
|
211
|
+
|
|
212
|
+
### Monte Carlo Analysis
|
|
213
|
+
|
|
214
|
+
Compare estimation methods using Monte Carlo simulations:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from ringdownanalysis import MonteCarloAnalyzer
|
|
218
|
+
|
|
219
|
+
analyzer = MonteCarloAnalyzer()
|
|
220
|
+
|
|
221
|
+
results = analyzer.run(
|
|
222
|
+
f0=5.0,
|
|
223
|
+
fs=100.0,
|
|
224
|
+
N=1_000_000,
|
|
225
|
+
A0=1.0,
|
|
226
|
+
snr_db=60.0,
|
|
227
|
+
Q=10000.0,
|
|
228
|
+
n_mc=100,
|
|
229
|
+
seed=42,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
print(f"NLS std: {results['stats']['nls']['std']:.6e} Hz")
|
|
233
|
+
print(f"DFT std: {results['stats']['dft']['std']:.6e} Hz")
|
|
234
|
+
print(f"CRLB std: {results['crlb_std']:.6e} Hz")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Calculate CRLB
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from ringdownanalysis import CRLBCalculator
|
|
241
|
+
|
|
242
|
+
crlb_calc = CRLBCalculator()
|
|
243
|
+
crlb_std = crlb_calc.standard_deviation(
|
|
244
|
+
A0=1.0,
|
|
245
|
+
sigma=0.001,
|
|
246
|
+
fs=100.0,
|
|
247
|
+
N=10000,
|
|
248
|
+
tau=636.6,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
print(f"CRLB standard deviation: {crlb_std:.6e} Hz")
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Batch Analysis
|
|
255
|
+
|
|
256
|
+
Process multiple experimental data files:
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
from ringdownanalysis import BatchRingDownAnalyzer
|
|
260
|
+
import pandas as pd
|
|
261
|
+
|
|
262
|
+
batch_analyzer = BatchRingDownAnalyzer()
|
|
263
|
+
|
|
264
|
+
# Process all files in data directory
|
|
265
|
+
results = batch_analyzer.process_directory("data", verbose=True, n_jobs=-1)
|
|
266
|
+
|
|
267
|
+
# Q factors are automatically calculated during analysis (via estimate_full())
|
|
268
|
+
# Access them directly from results or use calculate_q_factors() for statistics
|
|
269
|
+
batch_analyzer.calculate_q_factors() # Ensures Q is in results dict
|
|
270
|
+
q_stats = batch_analyzer.get_q_factor_statistics()
|
|
271
|
+
|
|
272
|
+
# Get summary table
|
|
273
|
+
summary = batch_analyzer.get_summary_table()
|
|
274
|
+
df_summary = pd.DataFrame(summary['data'])
|
|
275
|
+
|
|
276
|
+
# Consistency analysis
|
|
277
|
+
consistency = batch_analyzer.consistency_analysis()
|
|
278
|
+
|
|
279
|
+
# CRLB comparison
|
|
280
|
+
crlb_analysis = batch_analyzer.crlb_comparison_analysis()
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
See `examples/batch_analysis_example.py` for a complete batch analysis example.
|
|
284
|
+
|
|
285
|
+
## Project Structure
|
|
286
|
+
|
|
287
|
+
### Core Package (`ringdownanalysis/`)
|
|
288
|
+
|
|
289
|
+
- **`signal.py`**: `RingDownSignal` class for signal generation
|
|
290
|
+
- **`estimators.py`**: Frequency estimation classes (NLS, DFT)
|
|
291
|
+
- **`crlb.py`**: CRLB calculation
|
|
292
|
+
- **`data_loader.py`**: Data loading utilities for CSV and MAT files
|
|
293
|
+
- **`analyzer.py`**: Single-file analysis
|
|
294
|
+
- **`batch_analyzer.py`**: Batch processing and analysis
|
|
295
|
+
- **`monte_carlo.py`**: Monte Carlo simulation framework
|
|
296
|
+
- **`compat.py`**: Compatibility layer (function-based API)
|
|
297
|
+
|
|
298
|
+
### Documentation (`docs/`)
|
|
299
|
+
|
|
300
|
+
- **`api/`**: Sphinx API documentation — build with ``make -C docs/api html``
|
|
301
|
+
- **`data_format.md`**: Data format specification for CSV and MAT files
|
|
302
|
+
- **`tn/main.tex`**: Comprehensive LaTeX document with theoretical foundation
|
|
303
|
+
- **`tn/main.pdf`**: Compiled technical note
|
|
304
|
+
|
|
305
|
+
### Examples (`examples/`)
|
|
306
|
+
|
|
307
|
+
- **`usage_example.py`**: Comprehensive usage examples for all features
|
|
308
|
+
- **`batch_analysis_example.py`**: Batch analysis workflow example
|
|
309
|
+
- **`benchmark.py`**: Simple performance benchmark comparing NLS and DFT methods
|
|
310
|
+
- **`logging_config_example.py`**: Examples for configuring logging in production and debugging
|
|
311
|
+
|
|
312
|
+
### Benchmarks (`benchmarks/`)
|
|
313
|
+
|
|
314
|
+
- **`benchmark_suite.py`**: Comprehensive pytest-benchmark test suite
|
|
315
|
+
- **`run_benchmarks.py`**: Script to run benchmarks and generate reports
|
|
316
|
+
- **`run_profiling.py`**: Script to profile workloads and identify bottlenecks
|
|
317
|
+
- **`profile_utils.py`**: cProfile utilities for profiling workloads
|
|
318
|
+
- **`README.md`**: Detailed guide for benchmarking and profiling
|
|
319
|
+
|
|
320
|
+
See `benchmarks/README.md` for detailed information on performance benchmarking and profiling.
|
|
321
|
+
|
|
322
|
+
### Notebooks (`notebooks/`)
|
|
323
|
+
|
|
324
|
+
- **`analysis_example.ipynb`**: Interactive analysis examples
|
|
325
|
+
- **`batch_analysis_example.ipynb`**: Batch analysis in notebook format
|
|
326
|
+
|
|
327
|
+
## Key Results
|
|
328
|
+
|
|
329
|
+
- **NLS Method**: Achieves statistical efficiency, approaching the CRLB for ring-down signals when using the explicit ring-down model
|
|
330
|
+
- **DFT Method**: Provides computationally efficient estimation with Lorentzian peak fitting, but suffers from statistical inefficiency due to discrete frequency sampling
|
|
331
|
+
- **Exponential Decay Impact**: The exponential amplitude decay reduces effective observation time and SNR, degrading estimation performance compared to constant-amplitude signals. The degradation depends on the ratio T/τ (observation time to decay time constant)
|
|
332
|
+
- **Scaling Relationships**: For slow decay (T ≪ τ), accuracy scales as T⁻³/². For rapid decay (T ≫ τ), accuracy is limited by τ and scales as τ⁻³/²
|
|
333
|
+
|
|
334
|
+
## Security
|
|
335
|
+
|
|
336
|
+
**File input**: Load only CSV and MAT files from trusted sources. MAT files use `struct_as_record=False` to reduce deserialization risks; for untrusted input, consider sandboxing or alternative loaders. CSV files via Pandas are generally safe for typical scientific data.
|
|
337
|
+
|
|
338
|
+
**Path handling**: `process_directory()` validates that the directory exists and rejects path traversal in the glob pattern (e.g., `../`). For production use with user-supplied paths (e.g., from a web form), validate and resolve paths to a trusted base directory before passing them to the API.
|
|
339
|
+
|
|
340
|
+
## Data Format
|
|
341
|
+
|
|
342
|
+
Experimental data files should be placed in the `data/` directory:
|
|
343
|
+
|
|
344
|
+
- **CSV files**: Moku:Lab Phasemeter format with time in column 1 and phase (cycles) in column 4
|
|
345
|
+
- **MAT files**: MATLAB format with `moku.data` structure containing time in column 1 and phase in column 4
|
|
346
|
+
|
|
347
|
+
See `docs/data_format.md` for the full specification (column indices, units, validation rules, edge cases).
|
|
348
|
+
|
|
349
|
+
## Dependencies
|
|
350
|
+
|
|
351
|
+
Core dependencies (automatically installed via `pip install -e .`):
|
|
352
|
+
- NumPy >= 1.20.0
|
|
353
|
+
- SciPy >= 1.7.0
|
|
354
|
+
- Matplotlib >= 3.5.0
|
|
355
|
+
- tqdm >= 4.60.0
|
|
356
|
+
- joblib >= 1.0.0
|
|
357
|
+
- pandas >= 1.3.0
|
|
358
|
+
|
|
359
|
+
For reproducible environments (examples, notebooks), install from pinned versions:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
pip install -r requirements.txt
|
|
363
|
+
pip install -e .
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Optional dependencies:
|
|
367
|
+
- Jupyter >= 1.0.0 (for notebooks)
|
|
368
|
+
- pytest >= 7.0.0 (for testing)
|
|
369
|
+
- pytest-cov >= 4.0.0 (for coverage)
|
|
370
|
+
- pytest-benchmark >= 4.0.0 (for benchmarking)
|
|
371
|
+
- ruff >= 0.1.0 (for linting)
|
|
372
|
+
|
|
373
|
+
## API Documentation
|
|
374
|
+
|
|
375
|
+
Build the Sphinx API docs:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
make -C docs/api html
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Open `docs/api/_build/html/index.html` in a browser. Or install dev dependencies and run:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
pip install -e ".[dev]"
|
|
385
|
+
cd docs/api && make html
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Testing
|
|
389
|
+
|
|
390
|
+
Run the test suite:
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
pytest
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
With coverage:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
pytest --cov=ringdownanalysis --cov-report=html
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Benchmarking
|
|
403
|
+
|
|
404
|
+
The package includes a comprehensive benchmarking and profiling suite to measure performance and identify bottlenecks:
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
# Run benchmarks with medium workload
|
|
408
|
+
python benchmarks/run_benchmarks.py --size medium
|
|
409
|
+
|
|
410
|
+
# Profile critical workloads
|
|
411
|
+
python benchmarks/run_profiling.py all --size medium
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Or run benchmarks directly with pytest:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
pytest benchmarks/benchmark_suite.py --benchmark-only
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
See `benchmarks/README.md` for detailed information on benchmarking and profiling workflows.
|
|
421
|
+
|
|
422
|
+
## Development
|
|
423
|
+
|
|
424
|
+
### CI/CD
|
|
425
|
+
|
|
426
|
+
GitHub Actions run on every push and pull request:
|
|
427
|
+
|
|
428
|
+
- **Lint**: Ruff check and format
|
|
429
|
+
- **Test**: pytest with coverage on Python 3.8, 3.11, 3.12
|
|
430
|
+
- **Typecheck**: mypy
|
|
431
|
+
|
|
432
|
+
Coverage is uploaded to [Codecov](https://codecov.io) (optional; add `CODECOV_TOKEN` secret for private repos).
|
|
433
|
+
|
|
434
|
+
### Releasing
|
|
435
|
+
|
|
436
|
+
To publish a new version to PyPI:
|
|
437
|
+
|
|
438
|
+
1. Update `version` in `pyproject.toml`
|
|
439
|
+
2. Create and push a tag:
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
git tag v0.1.0
|
|
443
|
+
git push origin v0.1.0
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
3. The release workflow builds and publishes to PyPI automatically.
|
|
447
|
+
|
|
448
|
+
**Setup**: Add `PYPI_API_TOKEN` as a repository secret (Settings → Secrets → Actions). Create a token at [pypi.org/manage/account/token/](https://pypi.org/manage/account/token/).
|
|
449
|
+
|
|
450
|
+
## References
|
|
451
|
+
|
|
452
|
+
- S. M. Kay, *Fundamentals of Statistical Signal Processing: Estimation Theory*. Prentice Hall, 1993.
|
|
453
|
+
- D. C. Rife and R. R. Boorstyn, "Single tone parameter estimation from discrete-time observations," *IEEE Trans. Information Theory*, 1974.
|