<!-- canonical: https://jmrplens.github.io/phonometry/es/perception/psychoacoustics/sound-quality/ -->
Source: https://jmrplens.github.io/phonometry/es/perception/psychoacoustics/sound-quality/

Dos sonidos igual de sonoros pueden diferir aún en cuán *afilados*, cuán
*tonales*, cuán *ásperos* o cuán *fluctuantes* son. Esta página cubre las
métricas de calidad sonora que complementan a la sonoridad: la agudeza (*sharpness*,
DIN 45692) y la tonalidad, la aspereza y la intensidad de fluctuación de
ECMA-418-2 del modelo de Sottek. La sonoridad está en
[Sonoridad](/phonometry/es/perception/psychoacoustics/loudness/); la de ECMA-418-2, que
comparte el mismo front-end auditivo, está en
[Sonoridad avanzada](/phonometry/es/perception/psychoacoustics/advanced-loudness/).

Las cuatro métricas forman una familia: una única señal calibrada se reparte
entre dos etapas auditivas, y cada rama se ancla a un sonido de referencia
cuyo objetivo normativo es exactamente 1. El diagrama traza la familia con
los valores que la biblioteca calcula realmente para cada referencia
(resultados redondeados como 0,9999 asper y 0,9957 vacil_HMS frente a ese
objetivo de 1).

## Grabar la señal que estas métricas necesitan

ECMA-418-2 es un cálculo que se aplica a una grabación, y su apartado 2 hace de
la grabación parte de la conformidad: una medición solo es conforme si se toma
conforme a ECMA-74 y se realiza a 48 kHz, o se remuestrea a esa frecuencia. Eso
arrastra un entorno de ensayo cualificado al grado de exactitud 2 de ISO 11201,
un modo de funcionamiento declarado y el micrófono en las posiciones de
ECMA-74 — la posición de operador a 0,25 m de la caja de referencia y a 1,20 m
sentado o 1,50 m de pie, o al menos cuatro posiciones de observador a 1,00 m de
distancia y 1,50 m de altura —, con el ruido de fondo medido con el equipo
apagado y un calibrador aplicado antes y después. Las posiciones son las mismas
de las que parte la
[guía de tonos prominentes](/phonometry/es/perception/psychoacoustics/tone-prominence/),
que las enuncia enteras:

**Cuánto tiene que durar el registro** es la pregunta que las tres métricas de
ECMA contestan de forma distinta, y que ningún fragmento de esta página te
diría: el intervalo de medición debe cubrir al menos tres ciclos de
funcionamiento, o la secuencia completa en equipos que varían, y encima de eso
cada métrica tiene su propio tiempo de establecimiento. La tonalidad se
establece en torno a un segundo con un tono estable, porque la autocorrelación
trabaja dentro de cada bloque. La aspereza necesita un par de segundos: su
valor único es el percentil 90 de $R(l_{50})$ sobre los bloques que sobreviven
al transitorio inicial, y la traza que se dibuja más abajo tarda unos 0,5 s en
alcanzar su meseta. La intensidad de fluctuación es la que más registro
necesita, del orden de diez segundos, porque resuelve tasas de modulación
cercanas a 4 Hz: su traza sigue subiendo a los 3 s y solo se asienta hacia los
4 s, así que un extracto de dos segundos contiene un puñado de periodos de
modulación y se queda corto.

Saca las consecuencias: los valores calculados sobre fragmentos cortos quedan
sesgados a la baja para $R$ y $F$, así que compara solo valores calculados
sobre duraciones comparables, y toma por costumbre indicar la longitud de
análisis junto al valor. Los fragmentos de abajo usan 1,2 s, 2,0 s y 8,0 s
justo por esto.

:::caution
Una grabación binaural o con cabeza artificial debe venir ya ecualizada a campo
libre o a campo difuso antes de llegar a `tonality_ecma`, `roughness_ecma` o
`fluctuation_strength_ecma`. El apartado 5.1.3 lo da por supuesto: en un campo
ideal, los dos canales ecualizados corresponden a un micrófono en el centro de
la cabeza artificial, ya ausente, que es para lo que está hecho el filtro de
`field=`. Meter una grabación de maniquí sin ecualizar aplica dos veces el
filtro del oído externo. Cada canal se analiza por separado, ya que las
combinaciones binaurales no están implementadas.
:::

## Agudeza en acum (DIN 45692)

Dos sonidos pueden ser igual de sonoros y aun así uno se percibe más
«afilado» (siseante, metálico) porque su sonoridad se sitúa más arriba en la
escala Bark. La agudeza es el primer momento del patrón de sonoridad
específica ponderado por $g(z)$:

$$
S = k\ \frac{\int_0^{24} N'(z)\ g(z)\ z\ dz}{\int_0^{24} N'(z)\ dz}\ \text{acum}
$$

con $g(z) = 1$ hasta 15,8 Bark y creciendo exponencialmente a partir de ahí, y
$k$ normalizada para que el sonido de referencia (ruido de ancho de banda
crítico a 1 kHz, 60 dB) sea exactamente **1,00 acum** (DIN 45692 apartado 6;
la $k = 0{,}108$ resultante queda dentro de la ventana normativa 0,105–0,115).

*Las tres ponderaciones. Todas son planas hasta unos 15 Bark y crecen
exponencialmente por encima, que es lo que hace que la sonoridad de alta
frecuencia cuente más; la curva de Aures, a diferencia de las otras dos, se
mueve con la sonoridad total.*

<details>
<summary>Mostrar el código de esta figura</summary>

```python

# Ponderación de agudeza g(z) de DIN 45692: Ec. (1) más las variantes informativas del Anexo B
z = np.arange(1, 241) * 0.1                     # bins de Bark, 0.1 .. 24.0
g_din = np.where(z > 15.8, 0.15 * np.exp(0.42 * (z - 15.8)) + 0.85, 1.0)
g_bis = np.where(z > 15.0, 0.2 * np.exp(0.308 * (z - 15.0)) + 0.8, 1.0)
n = 4.0                                         # Aures depende de la sonoridad total (sonios)
g_aures = 0.078 * np.exp(0.171 * z) / z * (n / np.log(n * 0.05 + 1.0))

fig, ax = plt.subplots()
ax.semilogy(z, g_din, label="DIN 45692 g(z)")
ax.semilogy(z, g_bis, "--", label="von Bismarck (Anexo B)")
ax.semilogy(z, g_aures, "-.", label="Aures (Anexo B, N = 4 sonios)")
ax.axvline(15.8, linestyle=":", color="0.5")    # codo DIN: g crece a partir de 15.8 Bark
ax.set(xlabel="Razón de banda crítica z [Bark]", ylabel="Ponderación g(z)")
ax.grid(True, which="both", alpha=0.3)
ax.legend()
plt.show()
```

</details>

```python

from phonometry import psychoacoustics

# Una grabación y su calibración para que la guía funcione por sí sola
fs = 48000
x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)   # cualquier grabación (unidades digitales)
sens = 1.0                                                # calibration_factor a pascales

s = psychoacoustics.sharpness_din(x, fs, calibration_factor=sens)      # acum
s_aures = psychoacoustics.sharpness_din(x, fs, method="aures")        # variante del Anexo B
print(f"S = {s:.2f} acum  (Aures {s_aures:.2f} acum)")                # 1.03 acum (Aures 1.23)
```

CI verifica los valores objetivo de la Tabla A.2 (desde 0,38 acum a 250 Hz
hasta 2,82 acum a 4 kHz) dentro de la tolerancia del 5 % / 0,05 acum de la
norma.

**La agudeza es una posición, no un nivel.** Tanto el numerador como el
denominador de $S$ contienen $N'(z)$, así que el nivel se cancela: lo que
responde el cociente es *dónde se sitúa sobre el eje de Bark la sonoridad de
este sonido*. Por eso el apartado 6 de DIN 45692 fija el sonido de referencia y
todas y cada una de sus señales de verificación a la misma sonoridad, 4 sonios,
y por eso comparar la agudeza de dos sonidos de sonoridad muy distinta casi no
significa nada. Conviene memorizar el margen: una banda crítica de ruido a
250 Hz vale unos 0,4 acum, la referencia de 1 kHz exactamente 1 acum, una banda
crítica a 4 kHz unos 2,8 acum, y el ruido de banda ancha de un producto suele
caer entre 1 y 3 acum, con los sonidos dominados por el siseo que los clientes
llaman chillones por encima de 2 acum.

*La misma sonoridad, siete veces la agudeza. Los dos patrones integran 4 sonios;
lo que cambia es dónde se sitúan, y eso es todo el contenido de la métrica. A
la derecha, el mismo cálculo frente a los objetivos de los ensayos de audición
de la propia norma, con todos los puntos dentro de la desviación permitida.*

<details>
<summary>Mostrar el código de esta figura</summary>

```python

from scipy import signal as sp_signal

# `psychoacoustics` lo importan los fragmentos de arriba.
# Una banda crítica de ruido de la Tabla A.1 de DIN 45692, a un nivel de banda dado.
def critical_band_noise(f_low, f_high, level_db):
    rng = np.random.default_rng(7)
    sos = sp_signal.butter(8, [f_low, f_high], btype="band", fs=48000, output="sos")
    band = sp_signal.sosfilt(sos, rng.standard_normal(48000 * 2))
    band /= np.sqrt(np.mean(band**2))
    return band * 2e-5 * 10 ** (level_db / 20)

# La Tabla A.2 compara señales de igual sonoridad, así que cada banda se ajusta a 4 sonios.
def level_for_four_sone(f_low, f_high):
    low, high = 30.0, 95.0
    for _ in range(14):
        mid = (low + high) / 2
        loud = psychoacoustics.loudness_zwicker(
            critical_band_noise(f_low, f_high, mid), 48000, stationary=True).loudness
        low, high = (mid, high) if loud < 4.0 else (low, mid)
    return (low + high) / 2

for centre, f_low, f_high, target in [(250.0, 200.0, 300.0, 0.38),
                                      (4000.0, 3700.0, 4400.0, 2.82)]:
    band = critical_band_noise(f_low, f_high, level_for_four_sone(f_low, f_high))
    print(centre, round(float(psychoacoustics.sharpness_din(band, 48000)), 2), target)
#   250.0 0.37 0.38
#   4000.0 2.75 2.82
```

</details>

**Qué variante.** La ponderación DIN es independiente de la sonoridad, una
buena aproximación cerca de los 4 sonios a los que se calibró, pero se queda
corta frente a la agudeza que declaran los oyentes con sonidos muy silenciosos;
la ponderación informativa de Aures escala con la sonoridad total y es por
tanto la variante a la que recurrir cuando los sonidos que se comparan difieren
mucho en sonoridad. La de von Bismarck es la curva histórica, con su codo en
15 Bark, y se conserva por continuidad con datos antiguos. Para un sonido cuyo
espectro se mueve, el apartado 6 de DIN 45692 recomienda citar el percentil
$S_{50}$ sobre el análisis en lugar de un único valor instantáneo.

### Parámetros de `sharpness_din()`

| Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas |
| :--- | :--- | :--- | :--- | :--- |
| `x` | array 1D | Pa (tras calibración) | no vacío | La señal de la que se calcula el patrón de sonoridad específica |
| `fs` | int | Hz | > 0 | |
| `field` | str | — | `'free'` (por defecto) / `'diffuse'` | La corrección de campo sonoro de ISO 532-1, heredada de la etapa de sonoridad |
| `method` | str | — | `'din'` (por defecto, apartado 6) / `'bismarck'` / `'aures'` | La ponderación $g(z)$; las dos últimas son del Anexo B |
| `calibration_factor` | float | Pa por unidad digital | por defecto `1.0` | De `sensitivity()` |

A diferencia de las tres métricas de ECMA de abajo, `sharpness_din()` devuelve
un float pelado en acum, no un objeto de resultado con su propio `.plot()`.

## Tonalidad (ECMA-418-2)

Una componente tonal (un silbido, el tono de paso de pala de un ventilador)
destaca incluso a bajo nivel. ECMA-418-2 la cuantifica a partir de la **función
de autocorrelación** (ACF) de la señal rectificada de cada banda: una componente
periódica (tonal) mantiene una ACF alta a retardo no nulo, y la relación entre
sonoridad tonal y de ruido impulsa la tonalidad específica $T'(z)$. El valor
único $T$ se da en **tu_HMS**, calibrado de modo que un tono de 1 kHz/40 dB
sea $\approx 1$ tu_HMS; el resultado también sigue la frecuencia tonal
$f_\text{ton}$ por banda.

```python

from phonometry import psychoacoustics

fs = 48000
t = np.arange(int(1.2 * fs)) / fs
x = np.sqrt(2) * 2e-5 * 10 ** (40 / 20) * np.sin(2 * np.pi * 1000 * t)

res = psychoacoustics.tonality_ecma(x, fs, field="free")
peak = int(np.argmax(res.specific_tonality))
print(f"T = {res.tonality:.3f} tu_HMS")                    # 1.000 tu_HMS
print(f"f_ton = {res.tonal_frequencies[peak]:.0f} Hz")     # 999 Hz

res.plot()   # tonalidad específica media T'(z) + T(l) dependiente del tiempo
```

*El ancla de calibración vista banda a banda: un tono de 1 kHz a 40 dB pone
toda su tonalidad en una sola banda crítica, que es lo que hace que ahí la
relación entre sonoridad tonal y de ruido sea grande y despreciable en todas
las demás.*

<details>
<summary>Mostrar el código de esta figura</summary>

```python

from phonometry import psychoacoustics

# El ancla de calibración: un tono de 1 kHz a 40 dB SPL vale cerca de 1 tu_HMS.
fs = 48000
t = np.arange(int(1.2 * fs)) / fs
x = np.sqrt(2) * 2e-5 * 10 ** (40 / 20) * np.sin(2 * np.pi * 1000 * t)
res = psychoacoustics.tonality_ecma(x, fs, field="free")

# En una línea: al pasar unos ejes se dibuja solo el panel de tonalidad específica.
fig, ax = plt.subplots()
res.plot(ax=ax, language="es")
plt.show()

# O dibuja T'(z) a mano frente a la escala de razón de banda crítica:
fig, ax = plt.subplots()
ax.fill_between(res.bark, res.specific_tonality, alpha=0.3, color="#d62728")
ax.plot(res.bark, res.specific_tonality, color="#d62728")
ax.set_xlabel("Razón de banda crítica z [Bark_HMS]")
ax.set_ylabel("Tonalidad específica T' [tu_HMS]")
plt.show()
```

</details>

Esa concentración es lo que distingue un sonido tonal de uno de banda ancha
con la misma sonoridad: la etapa de autocorrelación encuentra una componente
periódica en una banda y casi nada en las demás. Un ventilador con tono de paso
de pala y su serie armónica muestra varios picos así; un siseo muestra un
patrón plano y bajo. Llamar a `.plot()` sin ejes añade el panel de $T(l)$
dependiente del tiempo, que es donde aparece un tono intermitente.

**Cómo se lee una tonalidad.** El apartado 6.3 de ECMA-418-2 ata su criterio de
prominencia al *patrón*, no al valor único: una componente tonal en la banda
$z_\text{tonal}$ cuenta como prominente cuando la tonalidad específica
$T'(z_\text{tonal})$ supera 0,4 tu_HMS, es un máximo local a lo largo de $z$ y
lleva una frecuencia tonal comprendida entre los centros de las bandas vecinas.
Así que una afirmación de prominencia se lee de `specific_tonality` y
`tonal_frequencies`, nunca de $T$ a secas. La norma no fija ningún límite a la
$T$ global, lo que la convierte en una magnitud para comparar diseños y no en
un ensayo de cumple/no cumple; el ensayo es la relación tono-ruido y la
relación de prominencia de ECMA-418-1 de
[Tonos discretos prominentes](/phonometry/es/perception/psychoacoustics/tone-prominence/).

### Parámetros de `tonality_ecma()`

| Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas |
| :--- | :--- | :--- | :--- | :--- |
| `signal_in` | array 1D | Pa | no vacío | Señal de presión calibrada |
| `fs` | float | Hz | > 0 | Se remuestrea a 48 kHz internamente si es necesario |
| `field` | str | — | `'free'` (por defecto) / `'diffuse'` | Filtro del oído externo/medio |
| `f_low` | float, opcional | Hz | por defecto `None` | Borde inferior de una banda de usuario para la búsqueda de $T(l)$ |
| `f_high` | float, opcional | Hz | por defecto `None` | Borde superior de la banda de usuario |

Devuelve un `EcmaTonality`: `tonality` ($T$, tu_HMS), `specific_tonality`
($T'(z)$, 53 bandas), `bark`, `centre_frequencies`, `tonal_frequencies`
($f_{\text{ton},z}$), `time`, `tonality_vs_time` ($T(l)$),
`tonal_frequency_vs_time`,
`field`.

## Aspereza en asper (ECMA-418-2)

La aspereza es la sensación áspera y zumbante de una modulación de amplitud
rápida (aproximadamente 20–300 Hz, con máximo cerca de 70 Hz): la cualidad de
un ralentí diésel o de un altavoz distorsionado.
ECMA-418-2 extrae la envolvente de cada banda, pondera su espectro
de modulación por la tasa y la profundidad de modulación, y correlaciona la
modulación entre bandas; el resultado $R$ se da en **asper**. El sonido de
referencia (portadora de 1 kHz, modulada en amplitud al 100 % a 70 Hz, nivel
global de 60 dB SPL) se define como 1 asper; esta implementación de sala
limpia devuelve 0,9999 asper con la constante de calibración tabulada $c_R$
(Fórmula 104) usada **sin** reajustarla hacia atrás al objetivo.

```python

from phonometry import psychoacoustics

fs = 48000
t = np.arange(int(2.0 * fs)) / fs
x = (1.0 + np.cos(2 * np.pi * 70 * t)) * np.sin(2 * np.pi * 1000 * t)
x *= 2e-5 * 10 ** (60 / 20) / np.sqrt(np.mean(x**2))   # nivel global de 60 dB SPL

res = psychoacoustics.roughness_ecma(x, fs, field="free")
print(f"R = {res.roughness:.4f} asper")   # 0.9999 asper (referencia: 1 asper)

res.plot()   # aspereza R(l50) dependiente del tiempo + mapa de calor de aspereza específica
```

*Las dos sensaciones, cada una leída como la define su apartado: la tonalidad
como traza temporal, que separa un tono en ruido del ruido solo, y la aspereza
en función de la tasa de modulación, cuyo máximo a 70 Hz sobre una portadora de
1 kHz totalmente modulada a 60 dB es el punto de calibración del asper.*

<details>
<summary>Mostrar el código de esta figura</summary>

```python

from phonometry import psychoacoustics

fs, p0 = 48000, 2e-5

# Panel superior: la tonalidad T(t) de un tono de 1 kHz en ruido frente al
# ruido solo, cada componente a 50 dB SPL durante 2 s.
t = np.arange(int(2.0 * fs)) / fs
rng = np.random.default_rng(2026)
noise = rng.standard_normal(t.size)
noise *= p0 * 10 ** (50 / 20) / np.sqrt(np.mean(noise**2))
tone = p0 * 10 ** (50 / 20) * np.sqrt(2) * np.sin(2 * np.pi * 1000 * t)
tin = psychoacoustics.tonality_ecma(tone + noise, fs)
pn = psychoacoustics.tonality_ecma(noise, fs)

# Panel inferior: la aspereza de una portadora de 1 kHz con AM del 100 %,
# barriendo la frecuencia de modulación (1 s por punto a 60 dB SPL).
tm = np.arange(fs) / fs
fmods = np.array([20.0, 30, 40, 50, 60, 70, 80, 100, 120, 150, 180, 200])
r = []
for fm in fmods:
    am = (1 + np.sin(2 * np.pi * fm * tm)) * np.sin(2 * np.pi * 1000 * tm)
    am *= p0 * 10 ** (60 / 20) / np.sqrt(np.mean(am**2))
    r.append(psychoacoustics.roughness_ecma(am, fs).roughness)

fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(10, 8.5))
ax0.plot(tin.time, tin.tonality_vs_time,
         label=f"Tono en ruido (T = {tin.tonality:.2f} tu_HMS)")   # 1,19
ax0.plot(pn.time, pn.tonality_vs_time,
         label=f"Ruido puro (T = {pn.tonality:.2f} tu_HMS)")       # 0,02
ax0.set(xlabel="Tiempo [s]", ylabel="Tonalidad T [tu_HMS]")
ax0.legend()
ax1.plot(fmods, r, "o-", label="Portadora de 1 kHz, AM del 100 %")  # máximo 1,0 asper
ax1.set(xlabel="Frecuencia de modulación f_mod [Hz]", ylabel="Aspereza R [asper]")
ax1.legend()
plt.show()
```

</details>

**Cómo se lee una aspereza.** El apartado 7.2 da el criterio que la sección de
tonalidad se guarda: una señal tiene una aspereza *prominente* cuando el valor
único $R$ — el percentil 90 de la $R(l_{50})$ dependiente del tiempo, no su
media — supera 0,2 asper. El percentil importa: las rachas breves de dureza no
se promedian hasta desaparecer, lo que también significa que el registro tiene
que ser lo bastante largo como para que ese percentil se asiente. La figura de
abajo es el sonido de referencia visto de las dos maneras en que lo lleva el
objeto de resultado.

*El sonido de referencia, banda a banda e instante a instante. El valor único
es la línea discontinua: un percentil de la traza de la derecha, integrada a
partir del patrón de la izquierda. Ese medio segundo de arranque es la razón de
que dos segundos de registro sean el mínimo práctico.*

<details>
<summary>Mostrar el código de esta figura</summary>

```python

# `res` es el resultado de aspereza del fragmento de arriba.
fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(12, 4.8))
ax0.plot(res.bark, res.specific_roughness)
ax0.set(xlabel="Razón de banda crítica z [Bark_HMS]",
        ylabel="Aspereza específica R'(z) [asper/Bark_HMS]")
ax1.plot(res.time, res.roughness_vs_time)
ax1.axhline(res.roughness, linestyle="--")     # el percentil 90
ax1.set(xlabel="Tiempo [s]", ylabel="Aspereza R [asper]")
plt.show()
```

</details>

### Parámetros de `roughness_ecma()`

| Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas |
| :--- | :--- | :--- | :--- | :--- |
| `signal_in` | array 1D | Pa | no vacío | Señal de presión calibrada |
| `fs` | float | Hz | > 0 | Se remuestrea a 48 kHz internamente si es necesario |
| `field` | str | — | `'free'` (por defecto) / `'diffuse'` | Filtro del oído externo/medio |

Devuelve un `EcmaRoughness`: `roughness` ($R$, asper, el percentil 90 de
$R(l_{50})$), `specific_roughness` ($R'(z)$, 53 bandas), `bark`,
`centre_frequencies`, `time`, `roughness_vs_time` ($R(l_{50})$),
`specific_roughness_vs_time` (array de (n_times, 53)), `field`.

## Intensidad de fluctuación en vacil_HMS (ECMA-418-2)

La intensidad de fluctuación es la sensación lenta y ondulante de la
modulación de amplitud o de frecuencia por debajo de unos 20 Hz: una
sirena, tonos batientes, el habla al ritmo silábico. Es la contraparte lenta
de la aspereza: el mismo modelo auditivo separa la modulación de la
envolvente en un paso de banda lento con máximo cerca de 4 Hz (intensidad de
fluctuación, en **vacil_HMS**) y otro rápido con máximo cerca de 70 Hz
(aspereza). El apartado 9 de ECMA-418-2 analiza la envolvente de cada banda
con análisis espectral de alta resolución (HSA), un ajuste por mínimos
cuadrados de pares de líneas espectrales del núcleo de la ventana que
resuelve tasas de modulación muy por debajo del ancho de bin de la DFT, con
ventanas de análisis dependientes de la envolvente que omiten los periodos
más silenciosos, y después pondera el complejo armónico dominante y lo
escala con una sonoridad específica basada en el HSA. El sonido de
referencia (portadora de 1 kHz, modulada en amplitud al 100 % a 4 Hz, nivel
global de 60 dB SPL) se define como 1 vacil_HMS; esta implementación de
sala limpia converge a 0,9958 vacil_HMS a los 12 s con la constante de
calibración tabulada $c_F$ (fórmula 163) usada **sin** reajustarla al objetivo
(el ejemplo de 8 s de abajo imprime 0,9957). Una señal cuyo valor único $F$
supera 0,2 vacil_HMS tiene una intensidad de fluctuación *prominente*
(apartado 9.2).

```python

from phonometry import psychoacoustics

fs = 48000
t = np.arange(int(8.0 * fs)) / fs
x = (1.0 + np.cos(2 * np.pi * 4 * t)) * np.sin(2 * np.pi * 1000 * t)
x *= 2e-5 * 10 ** (60 / 20) / np.sqrt(np.mean(x**2))   # 60 dB SPL globales

res = psychoacoustics.fluctuation_strength_ecma(x, fs, field="free")
print(f"F = {res.fluctuation_strength:.4f} vacil_HMS")   # 0.9957 vacil_HMS (referencia: 1 vacil_HMS)

res.plot()   # F(l50) temporal + mapa de calor de la específica
```

*Dos pasos de banda sobre la misma envolvente. La misma portadora modulada se
oye como fluctuación por debajo de unos 20 Hz y como aspereza por encima, que
es la razón de que las dos métricas se repartan el eje de modulación en vez de
competir en él.*

*Las mismas dos vistas para la sensación lenta, y la razón de que esta métrica
sea la que más registro necesita de la página: la traza sigue subiendo a los
3 s. Un extracto de dos segundos de este mismísimo sonido de referencia daría
bastante por debajo de 1 vacil_HMS.*

<details>
<summary>Mostrar el código de esta figura</summary>

```python

from phonometry import psychoacoustics

fs = 48000
t = np.arange(int(3.0 * fs)) / fs
carrier = np.sin(2 * np.pi * 1000 * t)

def am_tone(fmod):
    # AM del 100 % a un nivel global de 60 dB SPL (convención de los apartados 7/9)
    x = (1.0 + np.sin(2 * np.pi * fmod * t)) * carrier
    return x * 2e-5 * 10 ** (60 / 20) / np.sqrt(np.mean(x**2))

fm_slow = [0.5, 1, 2, 4, 8, 16, 32]
fm_fast = [20, 40, 70, 100, 150, 200]
f_vals = [psychoacoustics.fluctuation_strength_ecma(am_tone(fm), fs).fluctuation_strength
          for fm in fm_slow]
r_vals = [psychoacoustics.roughness_ecma(am_tone(fm), fs).roughness for fm in fm_fast]

fig, ax = plt.subplots()
ax.semilogx(fm_slow, f_vals, "o-", label="Intensidad de fluctuación F [vacil_HMS]")
ax.semilogx(fm_fast, r_vals, "s-", label="Aspereza R [asper]")
ax.set(xlabel="Frecuencia de modulación [Hz]", ylabel="F [vacil_HMS] / R [asper]")
ax.legend()
plt.show()
```

</details>

### Parámetros de `fluctuation_strength_ecma()`

| Parámetro | Tipo | Unidades | Rango / valor por defecto | Notas |
| :--- | :--- | :--- | :--- | :--- |
| `signal_in` | array 1D | Pa | no vacío | Señal de presión calibrada |
| `fs` | float | Hz | > 0 | Se remuestrea a 48 kHz internamente si es necesario |
| `field` | str | — | `'free'` (por defecto) / `'diffuse'` | Filtro del oído externo/medio |

Devuelve un `EcmaFluctuationStrength`: `fluctuation_strength` ($F$, vacil_HMS,
el percentil 90 de $F(l_{50})$), `specific_fluctuation_strength`
($F'(z)$, 53 bandas), `bark`, `centre_frequencies`, `time`,
`fluctuation_strength_vs_time` ($F(l_{50})$),
`specific_fluctuation_strength_vs_time` (array de (n_times, 53)), `field`.

Los modelos de intensidad de fluctuación de Fastl y Zwicker (forma cerrada
para ruido de banda ancha AM y el modelo de señal de Osses 2016) están en
[Molestia
psicoacústica](/phonometry/es/perception/psychoacoustics/psychoacoustic-annoyance/);
esta métrica del apartado 9 es la contraparte normativa del modelo de
Sottek.

Consulta [Tonos discretos prominentes](/phonometry/es/perception/psychoacoustics/tone-prominence/)
para los veredictos TNR/PR de ECMA-418-1, el
[índice de transmisión del habla](/phonometry/es/perception/speech/speech-transmission/)
para el STI/STIPA, y [Teoría](/phonometry/es/reference/theory/perception/) para la
matemática subyacente.

## Qué cubre esta guía

La DIN 45692:2009 mediante `sharpness_din()`: la ponderación del apartado 6
sobre el patrón de sonoridad específica de ISO 532-1, más las variantes
informativas de von Bismarck y Aures del Anexo B, con los valores objetivo de
la Tabla A.2 comprobados en CI. La ECMA-418-2:2025 sobre el front-end auditivo
común del apartado 5: las etapas de salida de tonalidad del apartado 6.2
(`tonality_ecma()`), la cadena de aspereza del apartado 7 (`roughness_ecma()`)
y la intensidad de fluctuación por HSA del apartado 9
(`fluctuation_strength_ecma()`). Cada una usa la constante de calibración
tabulada de la norma, no un ajuste inverso al sonido de referencia.

Los tres puntos de entrada de ECMA-418-2 son monoaurales: las combinaciones
binaurales de media cuadrática de la Fórmula 112 (apartado 7.1.11) y la
Fórmula 170 (apartado 9.1.15) no están implementadas, así que analiza cada
canal por separado. La ponderación de entropía opcional del apartado 7.1.6
necesita una señal externa de velocidad de giro y queda fuera, igual que el
ajuste de ±0,25 % de $c_F$ que permite la nota al pie 47. La sonoridad de
ECMA-418-2 que comparte este front-end está en [Sonoridad
avanzada](/phonometry/es/perception/psychoacoustics/advanced-loudness/), y los
modelos de intensidad de fluctuación de Fastl y Zwicker, en [Molestia
psicoacústica](/phonometry/es/perception/psychoacoustics/psychoacoustic-annoyance/).

## Véase también

- Referencia de la API: [`psychoacoustics.quality.sharpness`](/phonometry/es/reference/api/psychoacoustics/sharpness/), [`psychoacoustics.quality.tonality_ecma`](/phonometry/es/reference/api/psychoacoustics/tonality-ecma/), [`psychoacoustics.quality.roughness_ecma`](/phonometry/es/reference/api/psychoacoustics/roughness-ecma/) y [`psychoacoustics.quality.fluctuation_strength_ecma`](/phonometry/es/reference/api/psychoacoustics/fluctuation-strength-ecma/).
- Teoría: [Modelos avanzados de sonoridad y calidad sonora](/phonometry/es/reference/theory/perception/#modelos-avanzados-de-sonoridad-y-calidad-sonora): el patrón de sonoridad específica sobre el que se construyen la agudeza, la aspereza y la intensidad de fluctuación.
