A comprehensive toolkit for joint estimation of multiple decay slopes across Room Impulse Response (RIR) signals using piecewise linear fitting in the log energy domain.
This repository implements advanced algorithms for analyzing room acoustics by estimating multiple decay rates from RIR measurements. The method jointly fits common decay slopes across multiple RIRs while allowing individual crossover points, leveraging shared physical properties of the acoustic space.
- Joint Multi-Slope Estimation: Simultaneously fit multiple decay rates across multiple RIRs
- Multiple Loss Functions: Support for both quadratic (least squares) and linex loss functions
- Synthetic Data Generation: Create realistic RIR datasets with known ground truth parameters
- Interactive Visualization: Animated fitting process and comprehensive plotting tools
- Noise Floor Estimation: Optional estimation of background noise levels
- Real Data Processing: Apply methods to actual RIR recordings
- Even Crossover Initialization: Start with equally spaced segments dividing RIRs into chunks
- Closed-Form Solutions: Analytical least squares fitting for each chunk order across all RIRs
- Efficient Crossover Updates: Update crossover points based on linear segment intersections
- No Gradient Descent: Eliminates need for iterative optimization within each step
- Direct Log Energy Fitting: Clean, direct approach without preprocessing
- Initialize: Evenly divide each RIR into
n_slopesequal chunks - Fit Slopes: For each chunk order (1st, 2nd, 3rd...), collect all corresponding chunks across RIRs and fit shared decay rate with individual amplitudes using
β = (X^T X)^{-1} X^T y - Update Crossovers: Find intersections of adjacent linear segments:
t = (intercept2 - intercept1) / (slope1 - slope2) - Converge: Repeat until slope changes are below tolerance
├── README.md # This file
├── multislope_joint_estimator.py # Core estimation algorithm
├── generate_synthetic_rirs.py # Synthetic RIR data generation
├── multislope_decay_estimation_demo.ipynb # Interactive demonstration notebook
├── create_fitting_animation.py # Animation generation tools
└── data/ # Example datasets (if any)
# Clone repository
git clone <repository-url>
cd 2025_DecayEstimation
# Install core dependencies only
pip install -r requirements.txt# Install core + optional dependencies
pip install -r requirements.txt
pip install -r requirements_optional.txt# Core packages via conda
conda install numpy scipy matplotlib jupyter notebook soundfile pillow
# Additional packages as needed
conda install -c conda-forge seaborn pandas tqdm h5pynumpy>=1.21.0- Numerical computingscipy>=1.7.0- Scientific computing and optimizationmatplotlib>=3.4.0- Basic plottingjupyter>=1.0.0- Interactive notebookssoundfile>=0.10.0- Audio file processingpillow>=8.0.0- Image processing for animations
import numpy as np
from multislope_joint_estimator import MultiSlopeJointEstimator
from generate_synthetic_rirs import generate_synthetic_rir_dataset
# Generate synthetic test data
amplitude_db_vectors = [
np.array([-15.0, -20.0]), # RIR 1: descending amplitudes (fastest→slowest decay)
np.array([-13.0, -18.0]), # RIR 2
np.array([-17.0, -22.0]) # RIR 3
]
decay_rates_db_per_s = np.array([-50.0, -15.0]) # Fastest to slowest decay
rirs, metadata = generate_synthetic_rir_dataset(
n_rirs=3,
n_samples=2000,
amplitude_db_vectors=amplitude_db_vectors,
decay_rates_db_per_s=decay_rates_db_per_s,
noise_level_db=-40.0,
sample_rate=44100,
seed=42
)
# Fit model with quadratic loss
estimator = MultiSlopeJointEstimator(
n_slopes=2,
loss_function='quadratic' # or 'linex'
)
estimator.fit(rirs, sample_rate=44100)
# Get results
params = estimator.get_parameters()
print(f"Estimated decay slopes: {params['decay_slopes_db_per_s']} dB/s")
# Plot results
estimator.plot_fit(rirs, show_original=True)# Use asymmetric linex loss function
estimator_linex = MultiSlopeJointEstimator(
n_slopes=2,
loss_function='linex',
linex_alpha=0.5 # Controls asymmetry
)
estimator_linex.fit(rirs, sample_rate=44100)# Include noise floor estimation
estimator_nf = MultiSlopeJointEstimator(
n_slopes=2,
estimate_noise_floor=True
)
estimator_nf.fit(rirs, sample_rate=44100)
params = estimator_nf.get_parameters()
print(f"Noise floor amplitude: {params['noise_floor_amplitude_db']:.2f} dB")Launch the Jupyter notebook for a comprehensive interactive demonstration:
jupyter notebook multislope_decay_estimation_demo.ipynbThe notebook includes:
- Synthetic data generation with customizable parameters
- Comparison of quadratic vs linex loss functions
- Parameter sensitivity analysis
- Animated fitting process visualization
- Real RIR data processing examples
- Performance comparison between methods
- Function:
L(r) = r² - Properties: Symmetric, closed-form solution
- Use Case: Standard estimation, fast computation
- Function:
L(r) = exp(α·r) - α·r - 1 - Properties: Asymmetric, gradient-based optimization
- Parameters:
α > 0: Penalizes overestimation more than underestimationα < 0: Penalizes underestimation more than overestimation
- Use Case: When asymmetric error costs are important
The system expects decay rates in ascending order (fastest to slowest):
# Correct ordering: fastest to slowest decay (most negative to less negative)
decay_rates_db_per_s = np.array([-50.0, -30.0, -15.0]) # dB/s
# Corresponding amplitudes: highest for fastest decay
amplitude_db_vectors = [
np.array([-10.0, -15.0, -20.0]) # Descending amplitudes
]For real RIR processing, the system accepts:
- WAV files in the
rir_dataset/directory - Numpy arrays with shape
(n_rirs, n_samples) - Automatic handling of stereo files (uses first channel)
n_slopes: Number of decay slopes to estimatemax_iter: Maximum iterations for alternating optimization (default: 100)tol: Convergence tolerance for slope changes (default: 1e-6)min_segment_length: Minimum samples per segment (default: 10)loss_function: 'quadratic' or 'linex' (default: 'quadratic')linex_alpha: Asymmetry parameter for linex loss (default: 0.5)
- n_slopes: Start with 2-3 for most applications
- min_segment_length: Adjust based on signal length and noise level
- linex_alpha:
- 0.1-1.0 for mild asymmetry
- 1.0-5.0 for strong asymmetry
- Use domain knowledge about error costs
- Faster Convergence: Closed-form solutions avoid iterative inner loops
- Better Numerical Stability: Direct matrix solutions with pseudo-inverse fallback
- Shared Physical Constraints: Joint estimation leverages common room properties
- Robust Parameter Constraints: Ensures physically meaningful negative decay rates
- Room Acoustics Research: Characterize reverberation properties
- Audio Processing: Extract room characteristics for spatial audio
- Architectural Acoustics: Analyze acoustic performance of spaces
- Psychoacoustics: Study perception of reverberation decay
If you use this code in your research, please cite:
@software{multislope_decay_estimation,
title={Multi-Slope Decay Estimation for Room Impulse Responses},
author={[Your Name]},
year={2025},
url={[Repository URL]}
}Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
[Specify your license here]
[Your contact information]
This implementation is particularly well-suited for acoustics research, room characterization, and applications requiring fast, robust multi-slope decay estimation across multiple RIR measurements.