"""
Psychoacoustic frequency-amplitude scaling utilities.
This module provides functions for scaling amplitude based on frequency
and loudness according to psychoacoustic principles, accounting for
human perception of sound at different frequencies and levels.
"""
import numpy as np
from scipy import interpolate
from .amplitude import dbamp
__all__ = [
'freq_amp_scale',
]
[docs]
def freq_amp_scale(freq: float, db_level: float, min_db: float = -60) -> float:
"""
Scale amplitude based on frequency and loudness according to psychoacoustic principles.
Parameters
----------
freq : float
The frequency in Hz.
db_level : float
The input level in dB.
min_db : float, optional
The minimum dB level in the dynamic range (default is -60).
Returns
-------
float
The perceptually scaled amplitude (linear scale).
"""
range_db = abs(min_db)
phon_level = 40 + ((db_level - min_db) / range_db) * 60
frequencies = np.array([20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000], dtype=float)
if phon_level <= 40:
scaling_curve = np.array([0.2, 0.3, 0.5, 0.7, 0.9, 1.0, 1.0, 0.9, 0.7, 0.4], dtype=float)
elif phon_level <= 70:
scaling_curve = np.array([0.3, 0.45, 0.6, 0.8, 0.95, 1.0, 1.0, 0.95, 0.8, 0.5], dtype=float)
else:
scaling_curve = np.array([0.5, 0.6, 0.7, 0.85, 0.95, 1.0, 1.0, 0.95, 0.85, 0.6], dtype=float)
spline = interpolate.CubicSpline(frequencies, scaling_curve, extrapolate=True)
scaling_factor = max(0.01, float(spline(freq)))
raw_amp = dbamp(db_level)
return raw_amp * scaling_factor