<!-- canonical: https://docs.jmrp.io/phonometry/reference/api/psychoacoustics/roughness-ecma/ -->
Source: https://docs.jmrp.io/phonometry/reference/api/psychoacoustics/roughness-ecma/

Psychoacoustic roughness per ECMA-418-2:2025 (4th ed., Sottek Hearing Model).

Clean-room implementation of the roughness signal chain of ECMA-418-2:2025
(Clause 7). The shared auditory front-end (Clause 5: outer/middle-ear filter,
53-band gammatone-like filter bank, half-wave rectification, compressive
nonlinearity to the specific basis loudness `N'_basis(l, z)` of Formula 25)
is reused from [`phonometry.psychoacoustics.loudness.ecma`](/phonometry/reference/api/psychoacoustics/ecma/); this module
adds the roughness-specific chain:

* roughness-specific zero-padding (Clause 5.1.2.2) and segmentation
  (Clause 5.1.5.2) with the fixed block/hop $s_\mathrm{b} = 16384$ /
  $s_\mathrm{h} = 4096$
  (Clause 7.1.1);
* the Hilbert envelope of each critical-band block and a factor-32 downsampling
  to 1500 Hz (Clause 7.1.2, Formula 65);
* the scaled envelope power spectrum `Phi_E,l,z(k)` (Clause 7.1.3,
  Formulae 66-67);
* the two-step noise reduction of the envelope spectra (Clause 7.1.4,
  Formulae 68-71);
* the four-stage spectral weighting (Clause 7.1.5, Formulae 72-96): peak
  picking with a quadratic-fit modulation-rate refinement and a bias
  correction, the high-modulation-rate weighting, the fundamental
  modulation-rate estimation, and the low-modulation-rate weighting;
* the interpolation to 50 Hz, the distribution-dependent nonlinear transform
  with the calibration constant `c_R`, and the asymmetric time smoothing
  (Clause 7.1.7, Formulae 103-110); and
* the average specific roughness `R'(z)` (Clause 7.1.8), the time-dependent
  roughness `R(l50)` (Clause 7.1.9, Formula 111) and the representative
  90th-percentile single value `R` (Clause 7.1.10).

The optional entropy weighting of Clause 7.1.6 requires an external rotational
speed signal and is not implemented (see `notes-ecma418-2-roughness.md`).
The API is monaural: the quadratic-mean binaural combination of
Formula (112) (Clause 7.1.11) is not implemented -- analyse each channel
separately.

The calibration constant `c_R` of Formula (104) is the standard's tabulated
value (not reverse-fit), and the chain reproduces the Clause 7 reference
point exactly: a 1 kHz carrier 100 %-amplitude-modulated at 70 Hz with an
overall sound pressure level of 60 dB SPL computes to 0.9999 asper against
the defined 1 asper. Note the level convention: Clause 7 states the *sound
pressure level of the signal* (its overall RMS level), not the level of the
unmodulated carrier -- a fully modulated signal whose carrier alone sits at
60 dB is +1.76 dB hot overall and reads ~4 % high.

> Auto-generated from the source docstrings by `scripts/generate_api_docs.py` (`make api-docs`). Do not edit by hand.

## EcmaRoughness

```python
EcmaRoughness(
    roughness: float,
    specific_roughness: np.ndarray,
    bark: np.ndarray,
    centre_frequencies: np.ndarray,
    times: np.ndarray,
    roughness_vs_time: np.ndarray,
    specific_roughness_vs_time: np.ndarray,
    field: str,
)
```

Result of an ECMA-418-2:2025 (Sottek) roughness calculation.

`roughness` is the single representative roughness R in asper (the
90th percentile of R(l50), Clause 7.1.10). `specific_roughness` is the
average specific roughness R'(z) in asper/Bark_HMS over the 53 auditory
bands (Clause 7.1.8), with `bark` the critical-band-rate scale z
(0.5..26.5 Bark_HMS) and `centre_frequencies` the band centre
frequencies F(z). `times` and `roughness_vs_time` hold the
time-dependent roughness R(l50) at 50 Hz (Formula 111);
`specific_roughness_vs_time` is the time-dependent specific roughness
R'(l50, z) (Formula 109) of shape `(n_times, 53)`. `field` records the
assumed sound field.

### EcmaRoughness.plot()

```python
EcmaRoughness.plot(
    ax: Axes | None = None,
    *,
    language: str = 'en',
    **kwargs: Any,
) -> Axes | np.ndarray
```

Plot the roughness result (see `phonometry._plot.psychoacoustics`).

Draws the time-dependent roughness R(l50) and a specific-roughness
heatmap. Requires matplotlib (`pip install phonometry[plot]`).

## roughness_ecma

```python
roughness_ecma(
    signal_in: Signal | np.ndarray,
    fs: float | None = None,
    field: Literal['free', 'diffuse'] = 'free',
) -> EcmaRoughness
```

Psychoacoustic roughness per ECMA-418-2:2025 (Sottek Hearing Model).

**Parameters**

| Name | Description |
| :--- | :--- |
| `signal_in` | Calibrated sound pressure signal in pascals. Accepts a [`phonometry.io.Signal`](/phonometry/reference/api/io/io/#signal), which is where "calibrated" comes from without arithmetic: this model reads absolute levels, so an uncalibrated record is taken as if one digital unit were one pascal and the answer is wrong by however far that is from true. |
| `fs` | Sampling rate in Hz. Signals not at 48 kHz are resampled (Clause 5.1.1). Required for a bare array; a [`Signal`](/phonometry/reference/api/io/io/#signal) brings its own, and an explicit value that disagrees with it raises instead of silently winning. |
| `field` | `"free"` (default) or `"diffuse"` sound field, selecting the outer/middle-ear filter of Clause 5.1.3. |

**Returns:** An [`EcmaRoughness`](/phonometry/reference/api/psychoacoustics/roughness-ecma/#ecmaroughness) with the single value R (Clause 7.1.10), the average specific roughness R'(z) (Clause 7.1.8) and the time-dependent roughness R(l50) (Formula 111).

A 1 kHz carrier 100 %-amplitude-modulated at 70 Hz with an overall level
of 60 dB SPL yields 1 asper (Clause 7 calibration; reproduced to 0.9999
asper with the tabulated c_R of Formula (104)).
