<!-- canonical: https://jmrplens.github.io/phonometry/es/vibration/human/meter-verification/ -->
Source: https://jmrplens.github.io/phonometry/es/vibration/human/meter-verification/

Todas las demás páginas de esta sección calculan algo sobre una vibración a la
que está expuesta una persona: lo que una jornada le hace al cuerpo, lo que
unos choques repetidos le hacen a la columna, lo que un asiento transmite.
Esta calcula algo sobre el **instrumento**. La ISO 8041-1 no es un método para
medir vibración; es la especificación frente a la que se diseña y se ensaya un
vibrómetro de uso general para vibración en humanos, y el resto de la sección
lleva todo este tiempo citando uno de sus apartados, porque las nueve
ponderaciones frecuenciales que aplica la [exposición humana a
vibración](/phonometry/es/vibration/human/human-vibration/) se definen aquí y en ningún otro sitio.

Ese «en humanos» sostiene el resto. La norma especifica instrumentos
«diseñados para medir valores de vibración con el fin de evaluar la respuesta
humana a la vibración» (apartado 1), para vibración transmitida a las manos
(ISO 5349-1), vibración de cuerpo entero (ISO 2631-1, ISO 2631-2 e ISO 2631-4)
y vibración de cuerpo entero de baja frecuencia de 0,1 Hz a 0,5 Hz. Lo de **uso
general** la separa de la ISO 8041-2, que especifica medidores personales de
exposición con la mayoría de las mismas tablas (la sección 11 dice cuáles), y
no de algún otro tipo de vibrómetro: un instrumento de
mantenimiento predictivo de máquina o de daño en edificios se juzga contra
otros documentos, y nada de esta página le aplica.

El apartado que viene justo después de esas definiciones es donde empieza esta
página: cuánto puede apartarse un instrumento real de esas ponderaciones antes
de dejar de ser conforme. Ese apartado es una tabla de frecuencias y
porcentajes, y una resta. Resulta que no está solo. La desviación
característica de fase, el decaimiento del valor eficaz móvil y la ráfaga de
señal en diente de sierra están especificados los tres como números que un
vibrómetro conforme tiene que producir, y todos y cada uno de esos números se
pueden calcular. Esta página trata de las partes del ensayo de un instrumento
que son aritmética y no trabajo de laboratorio, y de dejar claro dónde termina
cada una.

## 1. Por qué una norma de instrumentación está en una biblioteca de cálculo

La ISO 8041-1 define tres niveles de ensayo de prestaciones (apartado 1): el
**ensayo de tipo**, un ensayo completo del instrumento frente a todas las
especificaciones del documento, con la **validación** como su forma reducida
para un instrumento de ejemplar único; la **verificación periódica**, un
conjunto intermedio de ensayos que confirma que un instrumento sigue
funcionando según lo especificado; y las **comprobaciones in situ**, el mínimo
que indica que probablemente esté funcionando. Los tres son trabajo sobre
hardware, hecho en un laboratorio o en campo. Ninguno de ellos se
ejecuta aquí.

Lo que se repite dentro de los tres es un único cálculo. Alguien midió la
respuesta en frecuencia de un canal de ponderación; la norma imprime la
respuesta que debería haber tenido y la banda dentro de la que se le permite
quedarse; ¿cae la medición dentro de la banda? Para responder a eso no hacen
falta ni excitador, ni transductor de referencia, ni cámara climática, solo el
objetivo de diseño y dos tablas. Eso es lo que hace `verify_weighting`, y es
todo lo que hace.

Así que el alcance de esta página es muy acotado, y conviene enunciarlo antes que
nada. Lo que la biblioteca tiene es la aritmética: el objetivo de diseño (las
funciones de transferencia exactas del apartado 5.6, ya usadas para ponderar
señales en otras páginas de esta sección), las frecuencias de transición de la
Tabla 4 y las bandas de tolerancia de la Tabla 5, las condiciones de
referencia de la Tabla 1 y las tolerancias de indicación de la Tabla 2, la
desviación característica de fase de la Fórmula (6), los tiempos de
decaimiento del valor eficaz móvil de las Tablas 10 y 11, y las 228 indicaciones de
la ráfaga de señal de las Tablas 7 a 9. Cada una de esas cosas es o bien un
número que la norma imprime o bien un número que la norma define en forma cerrada,
y cada una es un lado de una comparación cuyo otro lado sale de un banco de
ensayo.

Lo que la biblioteca no tiene es el banco de ensayo. La exactitud de la
indicación en condiciones de referencia (5.5), la linealidad de amplitud
(5.7), el ruido del instrumento (5.8), la indicación de sobrecarga y la de
señal por debajo del rango (5.10 y 5.11), la diafonía eléctrica (5.16), el
montaje del apartado 6 y los criterios ambientales y electromagnéticos del
apartado 7 son medidas sobre hardware; y también lo es, en el momento en
que alguien tiene que hacer vibrar un transductor y leer una pantalla,
cualquier ensayo de esta página. **Superar la comprobación de ponderación es
condición necesaria para la conformidad y nunca un certificado de ella.**

Conviene llevarse una frase del 5.6.6 al resto de la página: los límites de
tolerancia *incluyen* las incertidumbres expandidas máximas de medida
aplicables. La banda no es la holgura del instrumento con la incertidumbre
de la medida en el banco añadida aparte; esa incertidumbre tiene que caber
también dentro de la banda. Hay una segunda frase sobre incertidumbre, en 13.1
y 14.1, y dice algo distinto; distinguir las dos es de lo que trata la
sección 4.

### Cómo se hace la medida

En un ensayo de tipo (apartado 12), entrega el vibrómetro completo,
adaptadores de entrada incluidos, con la sensibilidad ajustada según su
documentación; el banco, con calibración trazable y cada frecuencia dentro de
±0,2 %. En la frecuencia de referencia, toma al menos tres lecturas frente a un
transductor de referencia calibrado en el mismo punto: a menos de un 3 % entre
sí y con la media dentro de la Tabla 2.

Por aplicación, una ponderación pasa los dos ensayos y las demás uno de ellos,
a tercios de octava o menos sobre la Tabla 15. En el excitador, con los dos
transductores montados como describe la ISO 16063-21, fija la lectura con
limitación de banda 20 dB sobre el límite inferior de linealidad en la
frecuencia de referencia, mantén esa entrada en el transductor de referencia y
anota la lectura en cada frecuencia: Fórmula (9), con incertidumbre expandida
de hasta 4,5 %. Por la entrada eléctrica, mantén la lectura y anota el valor de
la señal de entrada, con señal más ruido al menos diez veces el ruido:
Fórmula (12), hasta 3 %. El error del transductor de la ponderación ensayada
por las dos vías completa las demás, frente a la Tabla 5, hasta 5 %. Para las
ráfagas, lleva una sinusoide estable al 50 % del límite superior, aplica el
diente de sierra de la Tabla 6 a cada ponderación y repite diez veces más bajo
hasta tres veces el límite inferior. Si el vibrómetro lee pico, MTVV o VDV, la
fase se comprueba por el anexo H; un instrumento de ejemplar único se excita a
las frecuencias fijas de 13.10. Informa de cada configuración, condición,
resultado e incertidumbre real, y de si el vibrómetro es conforme. La
verificación periódica (apartado 14) es otro banco: conserva solo las
comprobaciones mecánicas de sensibilidad, linealidad y respuesta en frecuencia,
para un vibrómetro de cuerpo entero a 1,995, 7,943, 15,85 y 63,10 Hz a
1,00 m/s² con U de hasta 5 %.

## 2. Las nueve ponderaciones, y la banda que se ensancha a su alrededor

El objetivo de diseño no es una tabla de números, es una función de
transferencia. El apartado 5.6 construye cada ponderación a partir de cuatro
etapas analógicas, un par paso alto y paso bajo Butterworth de segundo orden que
limita la banda, una transición aceleración-velocidad que porta la ganancia
global y un escalón ascendente, multiplicadas entre sí como
$H(s) = H_\mathrm{h}(s)\,H_\mathrm{l}(s)\,H_\mathrm{t}(s)\,H_\mathrm{s}(s)$
(Fórmula (5)). [Vibración en humanos](/phonometry/es/vibration/human/human-vibration/) cubre esa cascada y el
conjunto de parámetros de la Tabla 3 que la especializa en las nueve
ponderaciones `Wb`, `Wc`, `Wd`, `We`, `Wf`, `Wh`, `Wj`, `Wk` y `Wm`.
`weighting_factors` evalúa esa función a cualquier frecuencia, y es ese valor, y
no uno tabulado, con el que se compara una medida. El Anexo B sí tabula esas
mismas ponderaciones con cuatro cifras significativas, y dice de sí mismo que
los valores se calcularon a partir de los objetivos de diseño en vez de
definirlos.

Alrededor del objetivo de diseño está la **Tabla 5**, y es fácil leerla como una
sola tolerancia cuando son tres. Las filas van referidas a cuatro frecuencias de
transición, de $f_\mathrm{t1}$ a $f_\mathrm{t4}$, que la **Tabla 4** da para
cada ponderación y que cortan el eje en cinco regiones; las cinco filas impresas
solo llevan tres pares de límites, distintos entre sí, porque las dos faldas comparten los
suyos y las dos colas también:

| Región de frecuencia | Tolerancia de magnitud | Desviación característica de fase |
| :--- | :---: | :---: |
| $f \le f_\mathrm{t1}$ | +26 %, −100 % | ±∞ |
| $f_\mathrm{t1} < f < f_\mathrm{t2}$ | +26 %, −21 % | ±12° |
| $f_\mathrm{t2} \le f \le f_\mathrm{t3}$ | +12 %, −11 % | ±6° |
| $f_\mathrm{t3} < f < f_\mathrm{t4}$ | +26 %, −21 % | ±12° |
| $f_\mathrm{t4} \le f$ | +26 %, −100 % | ±∞ |

Fíjate en qué filas son cerradas. La región central incluye sus dos cortes, las
faldas excluyen los suyos, así que una medida justo en $f_\mathrm{t2}$ o en
$f_\mathrm{t3}$ toma el límite más estrecho y no el más ancho que hay al otro
lado.

La Tabla 4 imprime cada corte dos veces, como potencia $10^{k/10}$ y como
decimal redondeado al lado, y la biblioteca los construye a partir de los
exponentes. Así que $f_\mathrm{t3}$ de `Wk` son 63,0957 Hz y los 63,1 Hz
impresos al lado son la cortesía, no el valor:

```python
from phonometry import vibration

# La Tabla 4 para Wk: ft1, ft2, ft3, ft4.
print([round(f, 4) for f in vibration.TRANSITION_FREQUENCIES_HZ["Wk"]])
# [0.2512, 0.631, 63.0957, 158.4893]

# La Tabla 5 leída a lo largo de ellas: cola, falda, central, falda, cola.
upper, lower = vibration.weighting_tolerance_percent(
    "Wk", [0.2, 0.5, 16.0, 100.0, 200.0]
)
print(upper)   # [26. 26. 12. 26. 26.]
print(lower)   # [-100.  -21.  -11.  -21. -100.]
```

Los centros de tercio de octava son también potencias exactas, $f_\mathrm{c}(n) =
10^{n/10}$ Hz (Fórmula (B.1)), que es lo que hace que los cortes caigan sobre
centros de banda y no al lado de ellos. La banda 18 es $10^{1{,}8}$ Hz y es la
última banda de la región central, exactamente como lo enseña la columna de
tolerancia del Anexo B; esa misma medida introducida como los 63,1 Hz impresos
cae unas milésimas de hercio por encima de $f_\mathrm{t3}$ y se califica contra
la falda en su lugar. El Anexo B dice lo mismo de los factores de ponderación:
usa las frecuencias centrales verdaderas, nunca las etiquetas nominales de
banda.

```python
print(vibration.weighting_tolerance_percent("Wk", [10 ** 1.8, 63.1])[1])
# [-11. -21.]
```

**Dónde caen los cortes.** La Tabla 1 da además un rango nominal de frecuencias
para cada aplicación, y los cortes de la Tabla 4 quedan a caballo de él en vez
de coincidir con él. La vibración de cuerpo entero se especifica de 0,5 Hz a
80 Hz mientras que la región estrecha va de 0,631 Hz a 63,1 Hz; la vibración
transmitida a la mano, de 8 Hz a 1 000 Hz frente a 10 Hz a 794,3 Hz; la
vibración de cuerpo entero de baja frecuencia, de 0,1 Hz a 0,5 Hz frente a
0,1259 Hz a 0,3981 Hz. En los tres casos los dos extremos del rango de trabajo
caen en una falda, y las colas empiezan más allá.

**Por qué la banda se ensancha al alejarse del centro.** Los porcentajes crecen
hacia fuera, y el margen que representan no. Un porcentaje no dice nada de
cuánto error deja pasar hasta que se multiplica por el factor del que es
porcentaje. En el corte superior el factor de diseño ya ha caído más de una
década, y en el inferior, a una quinta parte de su máximo:

```python
from phonometry import vibration

ft1, ft2, ft3, ft4 = vibration.TRANSITION_FREQUENCIES_HZ["Wk"]
corners = [ft1, ft2, 6.31, ft3, ft4]
design = vibration.weighting_factors("Wk", corners)
upper, _ = vibration.weighting_tolerance_percent("Wk", corners)

print(design.round(4))                   # [0.1832 0.4588 1.0544 0.1857 0.0292]
print((design * upper / 100).round(4))   # [0.0476 0.0551 0.1265 0.0223 0.0076]
```

A 6,31 Hz el ajustado +12 % vale 0,1265 en unidades de factor; a 158,5 Hz el
generoso +26 % vale 0,0076, unas diecisiete veces menos. La lectura que hay
detrás de eso, que la norma no explicita, es la forma de la respuesta: fuera del
rango de trabajo la ponderación está en la caída abrupta de la limitación de
banda, donde un error pequeño en una frecuencia de corte se convierte en un
error porcentual grande en el factor, mientras que esa misma banda no aporta
casi nada a un valor eficaz ponderado. Donde la contribución es grande, en el
centro, la norma es estricta.

**Calificar una respuesta medida.** `verify_weighting` toma las frecuencias a
las que se midió una respuesta y los factores leídos en ellas, evalúa el
objetivo de diseño en esas mismas frecuencias y aplica el criterio de aceptación
en el que están escritas las columnas de tolerancia,
$(\text{medida} / \text{diseño} - 1) \times 100$ frente a la banda de la región
en la que cae cada frecuencia:

```python

from phonometry import vibration

# Un barrido de banco del canal Wk de un vibrómetro de cuerpo entero. Los
# centros se construyen con la Fórmula (B.1) en vez de escribirse como
# decimales: 63.096 redondea hacia arriba por encima de ft3 y se calificaría
# frente a la falda, como avisa el párrafo de arriba.
bands = np.array([-3, 0, 3, 6, 9, 12, 15, 18, 19])
frequencies = 10.0 ** (bands / 10.0)
measured = np.array([0.4314, 0.4969, 0.5466, 0.9937, 1.068,
                     0.7897, 0.3427, 0.1894, 0.1366])

check = vibration.verify_weighting("Wk", frequencies, measured)
print(check.passes)                             # False
print(check.deviation_percent.round(1))
# [  3.   3.   3.   3.   3.   2. -15.   2.   2.]
print(check.failing_frequencies_hz.round(2))    # [31.62]
print(round(check.worst_deviation_percent, 1))  # -15.0

check.plot(language="es")   # la medida dentro de su banda (requiere matplotlib)
```

Un canal que lee entre un 2 % y un 3 % de más en todo el rango cumple, porque
eso está dentro del +12 % y dentro del +26 %. La única banda que lee un 15 % de
menos incumple, e incumple por dónde está: 31,62 Hz cae en la región central,
cuyo límite inferior es el −11 %. Lleva ese mismo déficit a 79,43 Hz, que está
entre $f_\mathrm{t3}$ y $f_\mathrm{t4}$, y el instrumento es conforme:

```python
moved = np.array([0.4314, 0.4969, 0.5466, 0.9937, 1.068,
                  0.7897, 0.4112, 0.1894, 0.1138])
print(vibration.verify_weighting("Wk", frequencies, moved).passes)   # True
```

<details>
<summary>Mostrar el código de la vista de la banda de tolerancia con un solo barrido</summary>

```python

from phonometry import vibration

check = vibration.verify_weighting("Wk", frequencies, measured)

# En una línea:
check.plot(language="es")
plt.show()

# A mano, a partir de los campos del resultado, replicando lo que dibuja
# WeightingVerification.plot():
upper, lower = vibration.weighting_tolerance_percent(
    check.weighting, check.frequencies_hz
)
inside = check.within_tolerance
fig, ax = plt.subplots()
ax.fill_between(check.frequencies_hz,
                check.design * (1.0 + lower / 100.0),
                check.design * (1.0 + upper / 100.0),
                color="#1f77b4", alpha=0.15, label="tolerancia de ISO 8041-1")
ax.plot(check.frequencies_hz, check.design, color="#1f77b4", lw=2.0,
        label="objetivo de diseño")
ax.plot(check.frequencies_hz[inside], check.measured[inside], "o",
        color="#2ca02c", label="dentro de tolerancia")
ax.plot(check.frequencies_hz[~inside], check.measured[~inside], "X",
        color="#d62728", markersize=9, label="fuera de tolerancia")
ax.set(xscale="log", yscale="log", xlabel="Frecuencia [Hz]",
       ylabel="Factor de ponderación")
ax.grid(True, which="both", alpha=0.3)
ax.legend()
plt.show()
```

</details>

## 3. El `−100 %` es la ausencia de un límite inferior, no uno ancho

La celda de la Tabla 5 que más se presta a leerse mal es el `−100 %` de sus
filas primera y última. Parece una tolerancia extremadamente generosa. No es
ninguna tolerancia: un factor un 100 % por debajo del objetivo de diseño es
cero, y ningún factor de ponderación puede ser negativo, así que ese límite
admite todas las respuestas que existen. Por debajo de $f_\mathrm{t1}$ y por
encima de $f_\mathrm{t4}$ la norma restringe la respuesta por arriba y deja de
restringirla por abajo del todo. Un instrumento puede caer fuera del rango de
trabajo tan abruptamente como quiera quien lo diseñe, y uno que ahí fuera no lea
nada en absoluto es conforme:

```python
from phonometry import vibration

# El objetivo de diseño a 0.1259 Hz, por debajo de ft1 = 0.2512 Hz para Wk.
print(vibration.weighting_factors("Wk", [0.1259]).round(5))   # [0.04932]

# Un canal que ahí no lee nada en absoluto sigue siendo conforme.
dead = vibration.verify_weighting("Wk", [0.1259], [0.0])
print(dead.passes, dead.deviation_percent.round(1))   # True [-100.]

# El límite superior es la mitad de la celda que sí puede fallar: +26 %,
# sea cola o no.
high = vibration.verify_weighting("Wk", [0.1259], [0.0626])
print(high.passes, high.deviation_percent.round(1))   # False [26.9]
```

No pierdas de vista la asimetría, porque es el sentido de esas dos filas. Lo que
la norma impide ahí fuera es un instrumento que **responda a vibración que
debería estar ignorando**, nunca uno que la ignore demasiado bien. El valor se
publica como `UNCONSTRAINED_BELOW` para que un informe pueda nombrarlo en vez de
escribir un número pelado, y la verificación lo compara como un límite
cualquiera: las filas de cola no necesitan ningún caso especial, ya que todo
factor no negativo las satisface por construcción.
## 4. La incertidumbre del laboratorio mueve la medición, no la banda

Dos frases de la norma hablan de incertidumbre expandida y es fácil leerlas
como una sola. No lo son, y un veredicto calculado con la que no toca se
equivoca en la dirección que deja pasar un instrumento.

La primera es la frase del 5.6.6 citada al final de la sección 1: los límites
de tolerancia de la Tabla 5 *incluyen* las **máximas** incertidumbres
expandidas de medida aplicables. Eso es una afirmación sobre cómo se trazó la
tabla. Es la razón de que `weighting_tolerance_percent` devuelva +12 % y
−11 % y nunca nada más ancho: la holgura que se le concede a un banco
cuidadoso ya está dentro de esos números, y sumarles algo sería gastarla dos
veces.

La segunda está en el 13.1 y en el 14.1, palabra por palabra en los dos: la
conformidad queda demostrada cuando la desviación medida respecto de un
objetivo de diseño, **extendida con la incertidumbre expandida de medida real
del laboratorio de ensayo**, no supera los límites de tolerancia
especificados. Eso es una afirmación sobre un laboratorio en un día concreto.
Mueve la desviación, no la banda, así que la comparación pasa a ser
`deviation + U <= upper` y `deviation - U >= lower`, y el número `U` es el del
propio laboratorio, calculado con el factor de cobertura `k = 2` que imprimen
los dos apartados.

Las dos son coherentes porque hablan de números distintos. El 12.1 acota la
`U` del laboratorio: un laboratorio de ensayo no puede siquiera realizar un
ensayo si su incertidumbre expandida real supera el máximo que ese apartado
permite, y son esos máximos los que el 5.6.6 dice que ya están dentro de los
límites impresos. La biblioteca publica los dos lados, indexados por número de
apartado, para que un informe pueda nombrar la cifra que usó:

```python
from phonometry import vibration

# Lo máximo que el 12.11.2 deja llevar a un laboratorio a un ensayo mecánico
# de respuesta en frecuencia, y el factor de cobertura con el que se expande.
print(vibration.MAX_EXPANDED_UNCERTAINTY_PERCENT["12.11.2"])   # 4.5
print(vibration.ISO8041_COVERAGE_FACTOR)                       # 2.0
```

Esto es lo que la diferencia le hace a un veredicto. Una banda de un barrido
de `Wk` lee un 9 % por encima del objetivo de diseño a 6,31 Hz, que está
dentro del +12 % de la región central con tres puntos de sobra:

```python
frequency = [10 ** 0.8]
measured = vibration.weighting_factors("Wk", frequency) * 1.09

bare = vibration.verify_weighting("Wk", frequency, measured)
print(bare.passes, bare.deviation_percent.round(1))    # True [9.]
```

Ahora el laboratorio declara el 4,5 % que le permite el 12.11.2. Nada del
instrumento ha cambiado, y la desviación informada tampoco cambia:

```python
declared = vibration.verify_weighting(
    "Wk", frequency, measured, expanded_uncertainty_percent=4.5
)
print(declared.passes, declared.deviation_percent.round(1))   # False [9.]
print(declared.expanded_uncertainty_percent)                  # 4.5
```

El instrumento se rechaza porque 9 % + 4,5 % es más que 12 %, y la norma
pregunta si la desviación *ampliada* se mantiene dentro del límite. Leído al
revés, un laboratorio que carga con un 4,5 % solo puede certificar
desviaciones de hasta el 7,5 % en la región central, y un banco que mide con
más cuidado certifica más instrumentos. Ese es todo el sentido del apartado:
la incertidumbre no es una holgura gratuita, es un coste.

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

```python

from phonometry import vibration

# El barrido de banco al que la figura pone nota: centros de tercio de octava de
# la Fórmula (B.1), y una respuesta que está dentro de la banda impresa en
# todos y cada uno de ellos.
sweep_bands = np.arange(-8, 25)
sweep_hz = 10.0 ** (sweep_bands / 10.0)

# Cuatro de esos centros SON frecuencias de transición de Wk, y los dos lados
# de esa comparación son una potencia cuyo último bit decide cada plataforma.
# Se ajustan al valor de la propia tabla: un centro que cae a un bit de una
# frecuencia de transición se califica contra la región vecina, y dos de
# estos cuatro imprimirían entonces un veredicto distinto más abajo.
corners = np.array(vibration.TRANSITION_FREQUENCIES_HZ["Wk"])
for corner in corners:
    sweep_hz[np.isclose(sweep_hz, corner, rtol=1e-9, atol=0.0)] = corner

sweep_deviations = np.array([
    -27.0, -24.0, -21.0, -13.0, -9.0, -6.0, -4.0, -2.0, -0.5, 1.0, 2.0, 2.5,
    3.0, 3.5, 4.5, 6.5, 9.0, 6.0, 4.0, 2.5, 1.5, 0.5, -0.5, -1.5, -3.0, -4.5,
    -6.0, -9.0, -13.0, -17.5, -22.0, -25.0, -28.0,
])
sweep_measured = (vibration.weighting_factors("Wk", sweep_hz)
                  * (1 + sweep_deviations / 100))

u = vibration.MAX_EXPANDED_UNCERTAINTY_PERCENT["12.11.2"]
print(vibration.verify_weighting("Wk", sweep_hz, sweep_measured).passes)   # True
graded = vibration.verify_weighting(
    "Wk", sweep_hz, sweep_measured, expanded_uncertainty_percent=u
)
print(graded.passes)                              # False
print(graded.failing_frequencies_hz.round(2))     # [  6.31 125.89]

# En una línea: el renderizador dibuja la banda impresa y, dentro de ella, la
# banda más estrecha que deja la incertidumbre declarada.
graded.plot(language="es")
plt.show()

# A mano, el mismo veredicto leído como desviaciones: la banda se queda donde
# la imprime la Tabla 5 y a la medición le crece una barra. Los límites son
# constantes entre las cuatro frecuencias de transición, así que un par de
# puntos a cada lado de cada una dibuja la escalera exactamente.
edges = np.sort(np.concatenate((corners * (1 - 1e-9), corners * (1 + 1e-9),
                                [0.1, 400.0])))
band_upper, band_lower = vibration.weighting_tolerance_percent("Wk", edges)

# En las dos colas el límite inferior es -100 %, al que verify_weighting no le
# resta nada, así que allí la barra tiene un solo brazo.
_ceiling, floor = vibration.weighting_tolerance_percent("Wk", sweep_hz)
arms = np.vstack((np.where(floor <= vibration.UNCONSTRAINED_BELOW, 0.0, u),
                  np.full(sweep_hz.shape, u)))
kept = graded.within_tolerance

fig, ax = plt.subplots()
ax.fill_between(edges, band_lower, band_upper, color="#1f77b4", alpha=0.15,
                label="tolerancia de ISO 8041-1")
ax.errorbar(sweep_hz[kept], graded.deviation_percent[kept],
            yerr=arms[:, kept], color="#2ca02c", marker="o", ls="none",
            capsize=2.5, label="desviación extendida conforme")
ax.errorbar(sweep_hz[~kept], graded.deviation_percent[~kept],
            yerr=arms[:, ~kept], color="#d62728", marker="X", markersize=9,
            ls="none", capsize=2.5, label="desviación extendida rechazada")
ax.set(xscale="log", xlim=(0.1, 400.0), ylim=(-33.0, 31.0),
       xlabel="Frecuencia [Hz]", ylabel="Desviación respecto al objetivo de diseño [%]")
ax.grid(True, which="both", alpha=0.3)
ax.legend()
plt.show()
```

</details>

El valor por defecto es `None`, que compara la desviación sin extender y es la
lectura que solo es correcta cuando se ha demostrado que la incertidumbre de
medida es despreciable. Una cifra negativa o infinita se rechaza en lugar de
ignorarse en silencio, porque ignorarla devolvería exactamente el veredicto
que el 13.1 dice que no basta.

Hay un sitio deliberadamente exento. El `−100 %` de las dos colas es la
ausencia de límite inferior, no un límite ancho, como lo plantea la sección 3,
así que no se le resta nada. Un canal que no lee absolutamente nada por debajo
de $f_\mathrm{t1}$ cumple por muy cuidadosamente que se haya medido, y sería
una regla extraña la que lo rechazara por el cuidado:

```python
dead = vibration.verify_weighting(
    "Wk", [0.1259], [0.0], expanded_uncertainty_percent=4.5
)
print(dead.passes, dead.deviation_percent.round(1))   # True [-100.]
```

## 5. Las condiciones de referencia, donde las ponderaciones no valen 1

La Tabla 1 fija el punto en el que se calibra un vibrómetro y se comprueba su
indicación. Da, por aplicación, una frecuencia de referencia impresa primero
en radianes por segundo (100 rad/s para la vibración de cuerpo entero,
500 rad/s para la vibración transmitida a la mano y 2,5 rad/s para la
vibración de cuerpo entero de baja frecuencia) con los hercios entre
paréntesis, una aceleración eficaz de referencia (1 m/s², 10 m/s² y 0,1 m/s²
respectivamente) y el rango de frecuencias nominal de la aplicación
(`NOMINAL_FREQUENCY_RANGE_HZ`, los números redondos de la columna impresa y no
centros de banda). Las condiciones ambientales de referencia están en otro
sitio, en el apartado 4: temperatura del aire 23 °C y humedad relativa 50 %.
La biblioteca deriva las frecuencias de los radianes por segundo en vez de
transcribir los hercios redondeados que van a su lado.

Luego viene la parte que sorprende a la gente en el banco. **Las
ponderaciones no valen la unidad en su frecuencia de referencia.** `Wk` a
15,915 Hz vale 0,7718, `Wh` a 79,58 Hz vale 0,2020 y `Wf` a 0,3979 Hz vale
0,3888. Un vibrómetro conforme al que se le aplique la vibración de referencia
no muestra, por tanto, la aceleración de referencia; muestra el producto de
las dos, que es la última columna de la Tabla 1 y lo que devuelve
`reference_indication`:

```python
from phonometry import vibration

for name in ("Wk", "Wh", "Wf"):
    print(
        name,
        round(vibration.REFERENCE_FREQUENCY_HZ[name], 4),      # Hz
        vibration.REFERENCE_ACCELERATION_M_S2[name],           # m/s^2
        round(vibration.reference_indication(name), 5),        # m/s^2
        vibration.indication_tolerance_percent(name),          # %
    )
# Wk 15.9155 1.0 0.77182 4.0
# Wh 79.5775 10.0 2.02019 4.0
# Wf 0.3979 0.1 0.03888 5.0
```

La última columna es la Tabla 2, la tolerancia de indicación en la frecuencia
de referencia en condiciones ambientales de referencia: ±4 % para la
vibración transmitida a la mano y la de cuerpo entero, ±5 % para la vibración
de cuerpo entero de baja frecuencia, que es el caso de `Wf` y el único que
difiere. Juntas dan la ventana en la que tiene que caer un canal `Wk` cuando
se le aplica 1 m/s² a 15,915 Hz:

```python
indication = vibration.reference_indication("Wk")
tolerance = vibration.indication_tolerance_percent("Wk")
print(round(indication * (1 - tolerance / 100), 4),
      round(indication * (1 + tolerance / 100), 4))
# 0.7409 0.8027
```

La biblioteca publica esa ventana; no puede comprobarla. Comprobarla significa
aplicar una vibración sinusoidal a la base del transductor con el instrumento
en su rango de medida de referencia y leer la pantalla, que es el apartado 5.5
y es una medición de laboratorio. Para lo que sirven los dos números es para
el informe: una indicación de 0,75 m/s² está dentro de la ventana y una
indicación de 0,80 m/s² también lo está, mientras que el 1,00 m/s² que un
lector podría esperar no lo está, y saber cuál de esas tres muestra el
vibrómetro es la diferencia entre una calibración y un malentendido.
## 6. La ponderación de limitación de banda, calificada por su cuenta

La cascada de la Fórmula (5) tiene cuatro etapas, y las dos primeras tienen
vida propia. $H_\mathrm{h}(s)\,H_\mathrm{l}(s)$, el par Butterworth de segundo
orden, paso alto y paso bajo, con las esquinas `f1` y `f2` de la Tabla 3, es la
**ponderación de limitación de banda**, y la norma la trata como una magnitud
que el instrumento indica, no como un resultado intermedio. El apartado 5.1
enumera el valor de banda limitada promediado en el tiempo entre lo que un
instrumento tiene que poder mostrar; el 5.6.6 dice que los límites de la
Tabla 5 se aplican a las ponderaciones «incluidas las ponderaciones de
limitación de banda correspondientes»; el Anexo B le da tres columnas propias
en cada una de las Tablas B.1 a B.9; y los ensayos de tipo de 12.7, 12.10,
12.11 y 12.13 ponen todos el vibrómetro en el ajuste de limitación de banda
antes de que ocurra nada más.

Entre las nueve ponderaciones solo hay cuatro pares de esquinas distintos, así
que seis de las nueve comparten una misma respuesta de limitación de banda, y
aun así se pide por el nombre de la ponderación, porque es como la cita la
norma. `band_limiting_factors` devuelve la magnitud, que es la columna
«Factor de limitación de banda» del Anexo B, y `band_limiting_response`
devuelve la respuesta compleja entera, que expone un `.plot()`:

```python

from phonometry import vibration

centres = 10.0 ** (np.array([-2, 8, 18, 20]) / 10.0)
print(centres.round(4))
# [  0.631    6.3096  63.0957 100.    ]

print(vibration.band_limiting_factors("Wk", centres).round(4))
# [0.9279 1.     0.9291 0.7071]
print(vibration.weighting_factors("Wk", centres).round(4))
# [0.4588 1.0544 0.1857 0.0887]

# Wm es una de las tres que no comparten la esquina de 0,4 Hz.
print(vibration.band_limiting_factors("Wm", centres).round(4))
# [0.5336 0.9999 0.9291 0.7071]
```

Ahí se ven dos cosas. La respuesta de limitación de banda es plana en el centro
y cae a $1/\sqrt{2}$ a 100 Hz, que es lo que hace una esquina Butterworth; y la
ponderación global tiene una forma completamente distinta, porque las etapas de
transición y de escalón de la cascada son las que hacen que una `Wk` sea una
`Wk`. La fila de limitación de banda no es una versión más débil de la fila de
la ponderación, es la otra mitad del mismo producto.

**La fila de la Tabla 2 que califica el par.** La Tabla 2 tiene tres filas, y
la sección 5 solo usó la primera. La segunda admite un 3 % entre el valor
indicado de una magnitud ponderada en frecuencia y el valor indicado de la
medida de limitación de banda correspondiente multiplicado por el factor de
ponderación apropiado, para una sinusoide estacionaria a la frecuencia de
referencia y con el valor de vibración de referencia. `apply_band_limiting`
hace pasar una señal por el camino de limitación de banda igual que
`apply_weighting` la hace pasar por el completo, así que la fila se puede
ejercitar de extremo a extremo:

```python
def rms(x):
    return float(np.sqrt(np.mean(x**2)))

fs = 2000.0
t = np.arange(int(60 * fs)) / fs
a = np.sqrt(2.0) * np.sin(2 * np.pi * vibration.REFERENCE_FREQUENCY_HZ["Wk"] * t)

band_limited = rms(vibration.apply_band_limiting(a, fs, name="Wk"))
weighted = rms(vibration.apply_weighting(a, fs, name="Wk"))

print(round(band_limited, 4), round(weighted, 4))   # 0.9997 0.7718
print(round(weighted / band_limited, 6))            # 0.772019
print(round(vibration.band_limited_weighting_factor("Wk"), 6))   # 0.772066
print(vibration.WEIGHTING_CONSISTENCY_TOLERANCE_PERCENT)         # 3.0
```

**Cuál es «el factor de ponderación apropiado».** La fila no define la
expresión, y el 12.7 apunta a la Tabla 1, cuya columna de factor de ponderación
dice 0,7718 para `Wk`.
El cociente de las dos respuestas a la frecuencia de referencia es 0,772066,
así que para `Wk` la elección no supone ninguna diferencia medible: su
ponderación de limitación de banda vale ahí 0,9997, y las dos lecturas
coinciden hasta tres partes en diez mil frente a una tolerancia del 3 %. Ocho
de las nueve ponderaciones se comportan así.

`Wf` no, y la razón es geométrica y no numérica. Su frecuencia de referencia es
2,5 rad/s, o sea 0,3979 Hz, y sus propias esquinas de limitación de banda están
en 0,08 Hz y 0,63 Hz, así que la frecuencia de referencia cae dentro de su
propia falda:

```python
f_ref = vibration.REFERENCE_FREQUENCY_HZ["Wf"]
skirt = float(vibration.band_limiting_factors("Wf", [f_ref])[0])
ratio = vibration.band_limited_weighting_factor("Wf")
print(round(skirt, 6), round(ratio, 6))     # 0.928078 0.418982

# La Tabla 1 imprime 0,3888 para Wf. Leído como el factor de la fila, un
# vibrómetro conforme incumple la fila por:
print(round((ratio / 0.3888 - 1) * 100, 2))   # 7.76
```

Un canal `Wf` conforme incumple la fila por más del doble de su tolerancia si
se usa el número de la Tabla 1, y la cumple por construcción si se usa el
cociente. `band_limited_weighting_factor` devuelve el cociente, que es la única
lectura con la que la fila se puede cumplir, y la ambigüedad queda registrada
como errata en lugar de resolverse en silencio.

## 7. La banda de fase, y el instrumento al que se aplica

La Tabla 5 tiene una tercera columna, y su nota al pie *a* la mantiene apartada
de la mayoría de los instrumentos: las tolerancias de la desviación
característica de fase **solo se aplican a los instrumentos que proporcionan
parámetros de medida que no están basados en valores eficaces**. Un valor
eficaz es insensible a la fase de lo que promedia; un pico, un MTVV o un VDV no
lo son, y el Anexo H nombra esos tres. Así que los límites de fase no son una
versión más estricta de los límites de magnitud, son un requisito sobre otro
conjunto de instrumentos, y por eso la biblioteca los devuelve desde una
función propia y no como un tercer array junto a la banda de magnitud. A un
vibrómetro que solo da valores eficaces nunca se le entrega un veredicto de
fase al que no está sujeto.

```python
from phonometry import vibration

print(vibration.phase_tolerance_degrees("Wk", [0.2, 0.5, 16.0, 100.0, 200.0]))
# [inf 12.  6. 12. inf]
```

El `inf` de las colas es la misma construcción que el `−100 %` de la sección 3:
una celda que se lee como un límite y es la ausencia de límite, impresa en la
Tabla 5 como ±∞.

La magnitud que se limita tampoco es la que parece a primera vista. El apartado
5.6.6 es explícito: los errores que causa una desviación de fase dependen de la
**velocidad de variación** del error de fase con la frecuencia y no de su valor
absoluto, así que la norma define una **desviación característica de fase**
$\Delta\varphi_0$ a partir de los errores de fase en dos centros de tercio de
octava contiguos (Fórmula (6)), y los límites de ±6° y ±12° los pone sobre
ella. El Anexo H da la razón: un retardo de grupo constante es una desviación
de fase proporcional a la frecuencia, y no afecta ni a los parámetros medidos
ni a $\Delta\varphi_0$, mientras que unas tolerancias escritas sobre el error de
fase en bruto tendrían que ser extremadamente estrechas para comprar la misma
exactitud de medida.

`phase_tolerance_degrees` devuelve esa banda y nada más: el límite que se
aplica a cada frecuencia, sin opinión alguna sobre qué se compara con él.
Calcular un $\Delta\varphi_0$ a partir de una respuesta de fase medida y
calificarlo frente a la banda es la sección siguiente.
## 8. Calificar una respuesta de fase: la Fórmula (6) y lo que ignora

La Fórmula (6) convierte dos errores de fase contiguos en un solo número:

$$
\Delta\varphi_0 = \left\lvert
\frac{f_n \, \Delta\varphi_{n+1} - f_{n+1} \, \Delta\varphi_n}
     {f_{n+1} - f_n} \right\rvert
$$

Es una pendiente escrita como ordenada en el origen. Lee los dos errores de fase
como dos puntos de una recta frente a la frecuencia: la cantidad que va dentro
de las barras es donde esa recta cruza $f = 0$. Así que un error de fase que
pasa recto por el origen se califica con un cero redondo, y un error de fase
desplazado del origen se califica con el tamaño del desplazamiento. La Fórmula
(H.3) del Anexo H normativo imprime la misma cantidad con los dos productos
intercambiados, que es el mismo número dentro de las barras, y zanja dónde va la
respuesta: `N` frecuencias dan `N − 1` valores, cada uno atribuido a la
frecuencia **inferior** de su par. Eso es lo que decide qué región de la Tabla 5
califica un par que queda a caballo de una frecuencia de transición.

Las dos invariancias merecen verse en lugar de leerse, porque son toda la
justificación de un criterio que parece tan indirecto:

```python

from phonometry import vibration

bands = np.arange(-10, 27)
frequencies = 10.0 ** (bands / 10.0)

# Un error de fase constante se califica por su valor.
constant = vibration.characteristic_phase_deviation(
    frequencies, np.full(frequencies.shape, 4.0)
)
print(round(float(constant.min()), 6), round(float(constant.max()), 6))
# 4.0 4.0

# Un error de fase proporcional a la frecuencia es un retardo de grupo
# constante, y se califica como cero por grande que llegue a ser. Este
# es de 2 ms.
delay_deg = -360.0 * frequencies * 2e-3
print(round(float(delay_deg.min()), 1), round(float(delay_deg.max()), 1))
# -286.6 -0.1
ramp = vibration.characteristic_phase_deviation(frequencies, delay_deg)
print(float(np.max(ramp)) < 1e-10)   # True
```

Un error de fase de hasta 287 grados, calificado como cero. La NOTA 1 del
apartado H.2.1 dice exactamente eso de un retardo de grupo constante:
«probablemente superaría con mucho las tolerancias sobre la desviación de fase,
pero no influiría ni en los parámetros de vibración que se van a medir ni en los
valores de la desviación característica de fase». Un vibrómetro que lo retrasa
todo el mismo tiempo ha cambiado cuándo llega la forma de onda, no qué aspecto
tiene, y el pico, el MTVV y el VDV de una forma de onda retrasada son el pico,
el MTVV y el VDV. Unas tolerancias escritas sobre el error de fase en bruto
tendrían que ser brutalmente estrechas para dejar sitio a un retardo que tiene
cualquier instrumento real.

**El oráculo.** El Anexo B imprime una columna de fase para la ponderación
global en todas y cada una de las Tablas B.1 a B.9, calculada a partir de la
Fórmula (H.1), que es el argumento del mismo $H(s)$ del que salen las
magnitudes. Esas columnas recorren una sola rama continua, desde cerca de
+180 grados en la parte baja de cada tabla hasta bastante más allá de −180 en la
parte alta, y el objetivo de diseño se sigue a lo largo de esa rama en lugar de
plegarse en la media vuelta a cada lado del cero. Cinco filas de la Tabla B.8,
calculadas en vez de transcritas:

```python
# frequencies es la malla de tercios de octava del bloque anterior.
design = vibration.verify_phase_response(
    "Wk", frequencies, np.zeros_like(frequencies)
).design_phase_deg

for band in (-10, 0, 8, 18, 26):
    index = band + 10
    print(band, round(float(frequencies[index]), 4),
          round(float(design[index]), 4))
# -10 0.1 159.7661
# 0 1.0 40.0607
# 8 6.3096 -6.8409
# 18 63.0957 -137.5858
# 26 398.1072 -247.9414
```

La Tabla B.8 imprime 159,8; 40,06; −6,841; −137,6 y −247,9 en esas filas. El
último es la clave: −247,9 grados no es una fase que muestre el instrumento de
nadie, es adonde ha llegado la rama, y es también donde tiene que llegar la
medición. Plegar cualquiera de los dos lados dentro de $(-180°, +180°]$ destruye
la invariancia frente al retardo, que es lo único para lo que existe el
criterio. El apartado H.2.3.4 g) a m) es la receta que da la propia norma para
reconstruir la curva continua a partir de las lecturas enrolladas de un medidor
de fase, y su sitio está antes de la llamada, no dentro: en una malla de tercios
de octava un enrollado y una rampa de retardo son el mismo salto, así que nada
aguas abajo podría distinguirlos.

**Un veredicto.** El instrumento de abajo tiene dos defectos. Uno es un retardo
de grupo de 2 ms, al que el criterio es ciego. El otro es un polo de más en
100 Hz, un filtro antialias colocado donde el objetivo de diseño ya tiene
su esquina de limitación de banda, y a eso el criterio no es ciego en absoluto.
La malla es el rango de frecuencias nominal de un vibrómetro de cuerpo entero,
sobre los centros exactos de la Fórmula (B.1):

```python
bands = np.arange(-3, 20)
frequencies = 10.0 ** (bands / 10.0)
print(round(float(frequencies[0]), 4), round(float(frequencies[-1]), 4))
# 0.5012 79.4328

design = vibration.verify_phase_response(
    "Wk", frequencies, np.zeros_like(frequencies)
).design_phase_deg
delay = -360.0 * frequencies * 2e-3
spare_pole = -np.degrees(np.arctan(frequencies / 100.0))

check = vibration.verify_phase_response(
    "Wk", frequencies, design + delay + spare_pole
)
print(check.passes)                                                  # False
print(check.failing_frequencies_hz.round(2))                         # [63.1]
print(round(float(check.characteristic_deviation_deg.max()), 2))     # 8.26
print(round(check.peak_deviation_percent, 1))                        # 6.9

check.plot(language="es")   # la desviación característica en su banda (requiere matplotlib)
```

Quita el polo y el retardo por sí solo es un error de fase de hasta 57 grados
que el criterio califica como cero:

```python
delayed = vibration.verify_phase_response("Wk", frequencies, design + delay)
print(round(float(delayed.deviation_deg.min()), 1),
      round(float(delayed.deviation_deg.max()), 1))
# -57.2 -0.4
print(delayed.passes)   # True
print(float(delayed.characteristic_deviation_deg.max()) < 1e-10)   # True
```

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

```python

# frequencies, design, delay, spare_pole y check vienen de los bloques
# anteriores.

# Una línea, para la respuesta que califica esta sección:
check.plot(language="es")
plt.show()

# Los dos paneles que comparten eje de frecuencia, desde los campos de los
# resultados: el error de fase que la Tabla 5 nunca califica, y la desviación
# característica que sí.
errors = {
    "una constante de +4 grados": np.full(frequencies.shape, 4.0),
    "2 ms de retardo de grupo por sí solo": delay,
    "el mismo retardo con un polo de más en 100 Hz": delay + spare_pole,
}
attributed = frequencies[:-1]
limit = vibration.phase_tolerance_degrees("Wk", attributed)

fig, (ax_error, ax_graded) = plt.subplots(2, 1, sharex=True, figsize=(9, 7))
for label, error in errors.items():
    graded = vibration.verify_phase_response("Wk", frequencies, design + error)
    ax_error.semilogx(frequencies, graded.deviation_deg, marker="o", label=label)
    ax_graded.semilogx(attributed, graded.characteristic_deviation_deg, marker="o")
ax_graded.plot(attributed, limit, color="#1f77b4", ls="--", drawstyle="steps-post",
               label="el límite de la Tabla 5")
ax_error.set_ylabel("Error de fase [grados]")
ax_error.legend(fontsize="small")
ax_graded.set(xlabel="Frecuencia [Hz]",
              ylabel="Desviación característica de fase [grados]")
ax_graded.legend(fontsize="small")
for ax in (ax_error, ax_graded):
    ax.grid(True, which="both", alpha=0.3)
plt.show()
```

</details>

**Lo que un error de fase le cuesta a una lectura de pico.** El Anexo H es
normativo, y la Fórmula (H.4) es el único número calculado de todo el
razonamiento sobre la fase:
$\Delta P_{\max} \approx \pm\max\{0.48 \sin \Delta\varphi_0\} \times 100\ \%$,
seguida de la frase de que para las desviaciones características de fase máximas
de 12 grados la desviación máxima del valor de pico es aproximadamente del 10 %.
El máximo va dentro de la fórmula impresa, así que el resultado es un solo
número para toda una respuesta y no uno por frecuencia, y es lo que cuesta el
peor par:

```python
print(round(vibration.peak_deviation_percent([12.0]), 2))   # 9.98
print(round(vibration.peak_deviation_percent([6.0]), 2))    # 5.02
```

De ahí salen los ±6 grados y los ±12 grados de la Tabla 5: una región central
sujeta al 5 % en una lectura de pico y unas faldas sujetas al 10 %. Es también
el 6,9 % que se le cobró por sus 8,26 grados al vibrómetro que falla más arriba,
y que `PhaseVerification.peak_deviation_percent` calcula a partir del peor par.
La NOTA 2 del apartado H.2.1 acota la aproximación dos veces, y las dos cotas
conviene conocerlas. Se aplica a valores por debajo de 30 grados, así que uno
mayor se deja pasar con un aviso; y es un peor caso que combina dos componentes
de la forma más desfavorable, así que la desviación efectiva del valor de pico
de una forma de onda real normalmente es menor.

**La malla.** `verify_phase_response` rechaza una malla más gruesa que el tercio
de octava, y cita el apartado 12.11.1, que pide un ensayo de respuesta en
frecuencia «en pasos no mayores de un tercio de octava». La razón es que la fase
de diseño se reconstruye sobre la malla que se le da: la rama se sigue de
frecuencia en frecuencia, y en una malla gruesa un paso de más de media vuelta
es indistinguible de la rama siguiente. El diseño entero caería a 360 grados de
distancia, y la Fórmula (6) convertiría ese desplazamiento, en un par muy
separado, en un puñado de grados, que puede quedarse cómodamente dentro de la
tolerancia. El fallo es silencioso y puede ir en cualquiera de los dos sentidos,
así que se rechaza en lugar de avisar de él:

```python
octaves = 2.0 ** np.arange(0.0, 7.0)
try:
    vibration.verify_phase_response("Wk", octaves, np.zeros_like(octaves))
except ValueError as error:
    print(error)
# verify_phase_response: 'frequencies_hz' steps by a ratio of up to 2, and
# ISO 8041-1:2017 12.11.1 asks for steps of not more than one third of an
# octave (1.259). The design-goal phase is rebuilt on the grid it is given,
# and on a coarser one it can land a whole turn away without the verdict
# noticing.
```

Conviene conocer un último caso, porque el veredicto es correcto y el
diagnóstico no. Una medición que está a media vuelta del objetivo de diseño en
todas las frecuencias es una señal invertida, y la Fórmula (6) califica un
desplazamiento constante por su valor, así que falla por 180 grados y falla a
gritos. El apartado H.2.3.4 k) dice que el criterio «no es aplicable a la
inversión de señal» y que la polaridad tiene su propio procedimiento de ensayo,
así que el veredicto viene con un aviso que lo dice: el número es real, y el
defecto al que apunta es un ensayo que esta función no realiza.
## 9. Cuánto tarda en olvidar el valor eficaz móvil

El apartado 5.13 es la ponderación temporal, y su ensayo es un cronómetro. Una
sinusoide estable a la frecuencia de referencia se mantiene el tiempo suficiente
para llenar el promedio, al menos 5 constantes de tiempo para el lineal y 20
para el exponencial; entonces se corta, y se toma el tiempo desde el corte hasta
el instante en que el valor indicado baja del 10 % del que tenía. Las Tablas 10
y 11 imprimen ese tiempo para tres constantes de tiempo, con la tolerancia al
lado:

```python
from phonometry import vibration

print(vibration.RUNNING_RMS_DECAY_TIME_S["linear"])
# ((0.125, 0.124, 0.005), (1.0, 0.99, 0.05), (8.0, 7.92, 0.2))
print(vibration.RUNNING_RMS_DECAY_TIME_S["exponential"])
# ((0.125, 0.58, 0.03), (1.0, 4.61, 0.25), (8.0, 36.8, 2.0))
```

Los dos promediados tienen forma cerrada, y ninguno es una constante ajustada. El
promediado lineal conserva los últimos $\tau$ segundos del registro, así que $t$
segundos después del corte su ventana todavía guarda $(\tau - t)/\tau$ del
valor cuadrático medio original y la indicación cae como $\sqrt{(\tau - t)/\tau}$,
hasta llegar a la décima parte en $t = 0{,}99\,\tau$. El promediado exponencial
decae en potencia como $e^{-t/\tau}$, así que la indicación cae como
$e^{-t/2\tau}$ y llega a la décima parte en $t = 2\tau\ln 10 = 4{,}6052\,\tau$.
`running_rms_decay_time` son esas dos expresiones, y caen sobre los números
impresos:

```python
for method in ("linear", "exponential"):
    print(method, [round(vibration.running_rms_decay_time(tau, method=method), 4)
                   for tau in (0.125, 1.0, 8.0)])
# linear [0.1237, 0.99, 7.92]
# exponential [0.5756, 4.6052, 36.8414]
```

Ejecutar el ensayo sobre una señal da la misma respuesta, que es para lo que
sirve tener la forma cerrada. La señal de abajo ya está ponderada, porque la
ponderación temporal va después de la ponderación frecuencial en la cadena:

```python

fs = 2000.0
cut_s = 10.0
t = np.arange(int(20 * fs)) / fs
a = np.sqrt(2.0) * np.sin(2 * np.pi * vibration.REFERENCE_FREQUENCY_HZ["Wk"] * t)
a[t >= cut_s] = 0.0

for method in ("linear", "exponential"):
    trace = vibration.running_rms(a, fs, integration_time=1.0, method=method)
    initial = float(trace[int(cut_s * fs) - 1])
    crossed = np.flatnonzero((t >= cut_s) & (trace < 0.1 * initial))
    decay_s = float(t[crossed[0]] - cut_s)
    verdict = vibration.verify_running_rms_decay(
        decay_s, integration_time_s=1.0, method=method)
    print(method, round(decay_s, 3), verdict.passes,
          round(verdict.lower_time_s, 3), round(verdict.upper_time_s, 3))
# linear 0.98 True 0.94 1.04
# exponential 4.605 True 4.36 4.86
```

La lectura lineal sale a 0,98 s en vez de los 0,99 s de la forma cerrada, y eso es
el ensayo comportándose como un ensayo y no como aritmética. En el instante del
cruce, la ventana deslizante solo guarda unas pocas muestras finales de una
sinusoide, y su valor cuadrático medio depende del punto del ciclo en el que se cortó
la señal. La banda impresa es 0,99 ± 0,05 s, lo bastante ancha para absorberlo,
y por eso el veredicto se escribe contra la banda y no contra la forma cerrada.
El veredicto conserva esa fila: `measured_time_s`, `printed_time_s` y
`tolerance_s` junto a `passes`, el intervalo como `lower_time_s` y
`upper_time_s`, y `.plot()` dibuja la lectura sobre la línea del 10 % dentro de
él.

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

```python

tau = 1.0
cut = int(cut_s * fs)
since_cut = np.arange(t.size - cut) / fs
# El 10 % del apartado, leído a partir de la forma cerrada en lugar de
# tecleado: el promediado exponencial cae como exp(-t / 2 tau), así que la
# fracción es lo que vale esa expresión en el instante que devuelve
# running_rms_decay_time.
fraction = np.exp(-vibration.running_rms_decay_time(tau, method="exponential") / (2 * tau))

fig, ax = plt.subplots()
for method, colour in (("linear", "#1f77b4"), ("exponential", "#2ca02c")):
    trace = np.asarray(vibration.running_rms(a, fs, integration_time=tau, method=method))
    relative = trace[cut:] / trace[cut - 1]
    # El promediado lineal se vacía una constante de tiempo después del corte, y
    # el nivel no está definido donde el valor cuadrático medio de la ventana es
    # exactamente cero.
    level_db = np.full(relative.shape, np.nan)
    level_db[relative > 0.0] = 20.0 * np.log10(relative[relative > 0.0])
    ax.plot(since_cut, level_db, color=colour, lw=1.8, label=f"promediado {method}")

    # La banda impresa en la que tiene que caer el cruce, de la Tabla 10 o la
    # Tabla 11.
    printed, tolerance = {
        row[0]: row[1:] for row in vibration.RUNNING_RMS_DECAY_TIME_S[method]
    }[tau]
    ax.axvspan(printed - tolerance, printed + tolerance, color=colour, alpha=0.12)

ax.axhline(20.0 * np.log10(fraction), color="0.4", lw=1.0)
ax.set(xlim=(0.0, 6.2), ylim=(-34.0, 2.0),
       xlabel="Tiempo desde el corte de la señal [s]",
       ylabel="Indicación, relativa a su valor inicial [dB]")
ax.grid(True, alpha=0.3)
ax.legend()
plt.show()
```

</details>

`verify_running_rms_decay` califica una fila impresa, y solo las tres constantes
de tiempo que imprimen las dos tablas. Cualquier otra cosa se rechaza en lugar de
juzgarse contra una banda que la norma no da:

```python
try:
    vibration.verify_running_rms_decay(
        2.0, integration_time_s=2.0, method="linear"
    )
except ValueError as error:
    print(error)
# 'integration_time_s' must be one of the time constants Tables 10 and 11
# print (0.125, 1, 8 s); 2 s has no printed decay band.
```

**Por qué la columna del tiempo y no la de la velocidad.** La Tabla 11 imprime
una segunda manera de decir lo mismo, una velocidad de caída equivalente en
decibelios por segundo, y deliberadamente no es el criterio:

```python
print(vibration.RUNNING_RMS_DECAY_RATE_DB_PER_S)
# ((0.125, 31.0, 40.0), (1.0, 3.8, 4.9), (8.0, 0.48, 0.62))
print(round(20 * np.log10(np.e) / 2.0, 4))   # 4.3429
```

La velocidad en forma cerrada de un promediado exponencial es
$20\lg(e)/(2\tau) = 4{,}3429/\tau$ decibelios por segundo, que para $\tau = 1$ s
vale 4,3429 y queda en el centro del intervalo impreso de 3,8 a 4,9. Pero ese intervalo va de
0,875 a 1,128 veces la forma cerrada, mientras que el tiempo impreso de la misma
fila, 4,61 ± 0,25 s, va de 0,947 a 1,055 veces $2\tau\ln 10$: aproximadamente la
mitad de ancho, y las otras dos filas se dividen de la misma manera. Las dos columnas no son
recíprocas la una de la otra: la columna del tiempo es la vinculante y la de la
velocidad es la afirmación más laxa de la misma caída, así que el veredicto se
escribe sobre la más estrecha.

Aquí entra también la tercera fila de la Tabla 2. Admite un 2 % entre la
indicación del valor eficaz móvil y el valor eficaz promediado linealmente en el
tiempo, ambos limitados en banda, para cualquier tiempo de medición, y se
publica como `RUNNING_RMS_CONSISTENCY_TOLERANCE_PERCENT`. Para una sinusoide
estable, el valor eficaz móvil oscila alrededor del promedio temporal con un
rizado de un 0,3 % aproximadamente, holgadamente dentro de ese margen.
## 10. La ráfaga en diente de sierra, y los 228 números que tiene que reproducir

El apartado 5.9 es el único sitio de todo el documento donde la ISO 8041-1
imprime un oráculo en vez de un requisito. Define una señal de ensayo en la
Tabla 6 y luego imprime en las Tablas 7, 8 y 9 las indicaciones que un
vibrómetro conforme tiene que mostrar cuando se le aplica esa señal, cada una
con la tolerancia contra la que se la juzga: 228 celdas en total. La NOTA 1
dice de dónde salen, y es la frase sin la cual esta sección no sería posible en
absoluto: «La respuesta a la ráfaga de señal en diente de sierra se determina
por simulación digital de las características del filtro». Son aritmética, así
que una biblioteca que tenga las ponderaciones y las cuatro magnitudes de
indicación puede reproducirlas.

**La señal.** La Figura 3 dibuja un diente de sierra bipolar de amplitud
1 m/s²: una rampa lineal ascendente y una caída vertical, y toda ráfaga empieza
en un paso por cero ascendente y termina en otro. Esa geometría no es un
adorno, pesa: una ráfaga empezada en el pico lee un 28 % por encima en la fila
de un solo ciclo de la Tabla 8, casi tres veces su tolerancia del 10 %. La Tabla 6 aporta
lo demás para cada aplicación, y `SAWTOOTH_BURST_TESTS` es esa tabla:

```python

from phonometry import vibration

test = vibration.SAWTOOTH_BURST_TESTS["whole-body"]
print(test.weightings)
# ('Wb', 'Wc', 'Wd', 'We', 'Wj', 'Wk', 'Wm')
print(round(test.frequency_hz, 4), test.start_time_s, test.repeat_time_s,
      test.duration_s, test.burst_count)
# 15.9155 1.0 10.0 60.0 6
print(test.cycle_counts, test.recommended_sampling_rate_hz)
# (1, 2, 4, 8, 16) 20000.0

record = vibration.sawtooth_burst("whole-body", 2)
print(record.size, np.count_nonzero(record))            # 1200000 15078
print(round(float(record.max()), 4), round(float(record.min()), 4))
# 0.9995 -0.9999
```

Seis ráfagas de dos ciclos cada una, en un minuto de registro por lo demás en
silencio. La frecuencia de muestreo recomendada es una elección de la propia
biblioteca, no una cifra normativa: la norma no prescribe ninguna, y es la
frecuencia a la que las celdas impresas salen con unas pocas décimas de por
ciento de diferencia.

**Reproducir una fila.** `signal_burst_indications` recorre la cadena que
describe la norma y devuelve las columnas impresas de la tabla de esa
aplicación:

```python
got = vibration.signal_burst_indications("whole-body", "Wk", 4)
printed = vibration.SIGNAL_BURST_RESPONSE["whole-body", "Wk", 4]
for column, cell in printed.items():
    print(column, cell, round(got[column], 5))
# rms 0.0577 0.05775
# vdv 0.455 0.45597
# mtvv_linear 0.182 0.18261
# mtvv_exponential 0.171 0.17123
```

Cuatro columnas porque la Tabla 8 imprime cuatro. La Tabla 7 imprime una, un
valor eficaz, y la Tabla 9 imprime dos, un valor eficaz y un valor de dosis de
mareo; el juego de columnas lo fija la aplicación, no quien llama. Dos de las
columnas de la Tabla 8 son el mismo MTVV calculado dos veces, y de ahí que
`mtvv` tenga un `method`: el promediado lineal de la ec. (2) de la ISO 2631-1 y
el promediado exponencial de la ec. (3) dan respuestas distintas, y la norma
califica los dos.

`verify_signal_burst_response` compara un juego de indicaciones medidas con
las celdas impresas, fila a fila y columna a columna, cada una contra la
tolerancia impresa a su lado:

```python
rows = {
    cycles: vibration.signal_burst_indications("whole-body", "Wk", cycles)
    for cycles in (1, 2, 4, 8, 16, None)
}
check = vibration.verify_signal_burst_response("whole-body", "Wk", rows)
print(check.quantities)
# ('rms', 'vdv', 'mtvv_linear', 'mtvv_exponential')
print(check.tolerance_percent)          # [10. 12. 10. 10.]
print(check.passes, round(check.worst_deviation_percent, 2))   # True 0.34
```

`None` es la fila continua, la que las tablas imprimen sin longitud de ráfaga.
El valor de dosis de vibración es la única columna a la que se le admite un
12 % en vez de un 10 %, en las 48 celdas que tiene.

Aquí hay un vibrómetro que no cumple, y no cumple de forma instructiva.
Calcula su MTVV con un promediado exponencial y lo informa en la columna
lineal:

```python
swapped = {
    cycles: {**row, "mtvv_linear": row["mtvv_exponential"]}
    for cycles, row in rows.items()
}
verdict = vibration.verify_signal_burst_response("whole-body", "Wk", swapped)
print(verdict.passes, round(verdict.worst_deviation_percent, 1))   # False -20.4
print(verdict.deviation_percent[:, 2].round(1))
# [ -2.3  -3.6  -5.9 -11.3 -20.4  -0.2]
print(verdict.cycle_counts)     # (1, 2, 4, 8, 16, None)

verdict.plot(language="es")   # las desviaciones frente a la banda impresa (requiere matplotlib)
```

Las filas de 1, 2 y 4 ciclos cumplen, la fila continua cumple porque los dos
promediados coinciden en una señal que no para nunca, y las filas de 8 y 16
ciclos son donde se ve la confusión. Una batería de ensayos que solo hubiera
pasado ráfagas cortas habría dado por bueno el instrumento.

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

```python

# En una línea, a partir del veredicto de arriba:
verdict.plot(language="es")
plt.show()

# A mano, a partir de los campos del resultado: una serie por cada columna
# impresa de la Tabla 8, dentro de la banda que esa misma tabla admite, con la
# tolerancia más ancha del valor de dosis de vibración dibujada como un par de
# bordes y no como una segunda banda bajo todas las columnas. La fila continua
# queda al otro lado de una línea de puntos y sin ninguna línea trazada hasta
# ella, igual que en la figura: la Tabla 6 no le da longitud de ráfaga, así
# que unirla al punto de 16 ciclos dibujaría una tendencia sobre un hueco que
# no existe.
positions = np.arange(len(verdict.cycle_counts))
inner = float(np.min(verdict.tolerance_percent))
outer = float(np.max(verdict.tolerance_percent))

fig, ax = plt.subplots(figsize=(9.0, 4.5))
ax.axhspan(-inner, inner, color="#9e9e9e", alpha=0.25,
           label=f"±{inner:.0f} % en todas las columnas menos una")
# El par más ancho es solo del valor de dosis de vibración, así que se dibuja
# como un tramo corto en el borde y no de lado a lado del panel, donde una
# línea en -12 % pasaría por la celda de 8 ciclos marcada con un círculo, de
# una columna a la que no se aplica.
for edge in (-outer, outer):
    ax.plot([positions[0] - 0.4, positions[0] + 0.4], [edge, edge],
            color="#9e9e9e", ls="--", lw=1.0)
ax.axhline(0.0, color="black", lw=0.8, alpha=0.4)
ax.axvline(positions[-1] - 0.5, color="#9e9e9e", ls=":", lw=1.0)
for index, quantity in enumerate(verdict.quantities):
    deviations = verdict.deviation_percent[:, index]
    burst_rows, = ax.plot(positions[:-1], deviations[:-1], marker="o",
                          label=quantity)
    ax.plot(positions[-1:], deviations[-1:], marker="o", ls="none",
            color=burst_rows.get_color())
outside = ~verdict.within_tolerance
ax.plot(positions[np.nonzero(outside)[0]], verdict.deviation_percent[outside],
        "o", markersize=14, markerfacecolor="none", markeredgecolor="#d62728",
        ls="none", label="las celdas en las que este vibrómetro no cumple")
ax.set_xticks(positions)
ax.set_xticklabels(["1", "2", "4", "8", "16", "continua"])
ax.set(xlabel="Ciclos de diente de sierra por ráfaga",
       ylabel="Desviación respecto a la celda impresa [%]")
ax.grid(True, axis="x", alpha=0.3)
ax.legend(fontsize="small")
plt.show()
```

</details>

**Dos convenciones que las tablas no imprimen.** Las celdas impresas son la
salida de una simulación que nadie publicó, así que dos lecturas del mismo
apartado dan dos juegos de números distintos, y esta rama eligió midiendo qué
lectura reproduce la página. Las dos son decisiones y no deducciones, y las dos
conviene declararlas sin rodeos.

*La fila continua empieza en t = 0* y ocupa la duración impresa. No empieza en
el instante de inicio de la Tabla 6, que es el de las ráfagas. Leída desde
cero, la celda continua de limitación de banda de la Tabla 7 sale 0,5649 frente
al 0,565 impreso; leída desde el instante de inicio sale 0,5602:

```python
test = vibration.SAWTOOTH_BURST_TESTS["hand-arm"]
fs = test.recommended_sampling_rate_hz
printed = vibration.SIGNAL_BURST_RESPONSE[
    "hand-arm", vibration.BAND_LIMITING, None
]["rms"]
from_zero = vibration.signal_burst_indications(
    "hand-arm", vibration.BAND_LIMITING, None
)["rms"]
print(printed, round(from_zero, 4), round((from_zero / printed - 1) * 100, 2))
# 0.565 0.5649 -0.02

# La lectura que la rama descartó: el mismo diente de sierra empezado tarde.
samples = round(test.duration_s * fs)
t = np.arange(samples) / fs
elapsed = test.frequency_hz * (t - test.start_time_s)
saw = 2.0 * np.mod(elapsed + 0.5, 1.0) - 1.0
late = np.where(t >= test.start_time_s, saw, 0.0)
padded = np.concatenate([late, np.zeros(samples)])
weighted = vibration.apply_band_limiting(
    padded, fs, name=test.band_limiting_weighting
)
from_start = float(np.sqrt(np.mean(weighted[:samples] ** 2)))
print(round(from_start, 4), round((from_start / printed - 1) * 100, 2))
# 0.5602 -0.86
```

Fíjate en que las dos lecturas cumplen, porque la tolerancia es del 10 % y la
peor de las dos se desvía un 0,86 %. Justo por eso la cuestión hubo que
zanjarla por cuál de las dos reproduce los dígitos impresos: la tolerancia es,
con diferencia, demasiado ancha para decidirlo.

*El filtrado parte de estado nulo.* `apply_weighting` multiplica en el dominio
de la frecuencia sin relleno de ceros, que es una convolución circular, y su
propia documentación lo dice. Sobre un registro de ráfagas eso apenas importa.
Sobre la fila continua enrolla la cola del registro sobre su principio y borra
el transitorio de arranque, que es justo lo que el MTVV lineal de esa fila está
hecho para captar. La verificación de ráfagas rellena antes el registro con
ceros y se queda con el principio, que es un filtro que se enciende en `t = 0`
sin nada guardado dentro:

```python
fs = vibration.SAWTOOTH_BURST_TESTS["whole-body"].recommended_sampling_rate_hz
record = vibration.sawtooth_burst("whole-body", None)

for name in ("Wc", "Wm", "Wd", "We"):
    cell = vibration.SIGNAL_BURST_RESPONSE["whole-body", name, None]
    printed = cell["mtvv_linear"]
    wrapped = vibration.apply_weighting(record, fs, name=name)
    circular = vibration.mtvv(wrapped, fs)
    from_rest = vibration.signal_burst_indications(
        "whole-body", name, None
    )["mtvv_linear"]
    print(name,
          round((circular / printed - 1) * 100, 2),
          round((from_rest / printed - 1) * 100, 2))
# Wc -0.81 -0.17
# Wm -1.1 -0.31
# Wd -3.24 -0.36
# We -5.19 -0.52
```

Hasta un 5,2 % en cuatro celdas, por una elección sobre lo que el filtro tenía
dentro antes de que empezara el registro. El comportamiento por defecto
de `apply_weighting` se deja a propósito como está: el relleno de ceros es de
este ensayo, no de toda señal ponderada, y quien lo necesite en otro sitio
rellena antes el registro con ceros y quita el relleno después, que es lo que
hace el fragmento anterior.

Lo que vale la reproducción, en las tres aplicaciones y en las 228 celdas
impresas, es un 2,3 % en el peor caso frente a tolerancias impresas del 10 % y
del 12 %. Y lo que significa un cumple sigue siendo estrecho: la respuesta
temporal de una cadena de ponderación coincide con la tabla impresa el día en
que se midió.

## 11. El medidor personal de la ISO 8041-2

Todo lo anterior es la ISO 8041-1, el vibrómetro de uso general que un técnico
lleva a una máquina o a un asiento. La ISO 8041-2:2021 especifica el otro
instrumento de una campaña de vibración en humanos, el **medidor personal de
exposición a vibraciones** (PVEM): el que se deja sin atender registrando la
exposición de un trabajador durante una jornada completa, al menos 12 h sin
que nadie lo toque (5.1 y 5.12), con el transductor fijado al trabajador, al
asiento o a la máquina o herramienta eléctrica (5.1.2 y 5.1.3). Mide las
mismas magnitudes a través de las mismas ponderaciones, y la parte 2 no le
escribe un segundo juego de tablas: vuelve a imprimir las de la parte 1 allí
donde puede. La pregunta de esta sección es, por tanto, a cuáles de los
números anteriores está sujeto un PVEM y cuáles son suyos.

**La misma ráfaga, dígito a dígito.** El apartado 5.9 de la parte 2 repite la
ráfaga en diente de sierra de la sección 10. Su Tabla 6 define la misma señal
de ensayo, y sus Tablas 7, 8 y 9 imprimen 228 indicaciones con una tolerancia
al lado de cada una. Leídas en las páginas de la parte 2 y puestas junto a
`SIGNAL_BURST_RESPONSE`, cada una de las 228 indicaciones y cada una de las 228
tolerancias es el número de la parte 1, y el 12.13 de la parte 2 las juzga con
la misma frase y la misma incertidumbre máxima del 3 %. Así que una sola
implementación sirve a las dos partes: los fragmentos de la sección 10 son el
ensayo de la parte 2 tal como están escritos, y el informe de conformidad
califica la biblioteca frente a la página de la parte 2 en una sección propia,
que además contrasta cada celda de la parte 2 con su gemela de la parte 1.

```python
from phonometry import vibration

# La tabla que reproduce la sección 10 es también la de la parte 2: 72 líneas
# impresas y 228 celdas, entre ellas la fila Wk de la Tabla 8.
cells = vibration.SIGNAL_BURST_RESPONSE
print(len(cells), sum(len(row) for row in cells.values()))   # 72 228
print(dict(cells["whole-body", "Wk", 4]))
# {'rms': 0.0577, 'vdv': 0.455, 'mtvv_linear': 0.182, 'mtvv_exponential': 0.171}
```

**La Tabla 2 pierde una fila.** Las tolerancias de indicación de la parte 2
son las dos primeras filas de la tabla de la parte 1, número por número: un
4 % para la indicación a la frecuencia de referencia, un 5 % para la vibración
de cuerpo entero de baja frecuencia, y un 3 % entre una indicación ponderada en
frecuencia y la limitada en banda multiplicada por el factor de ponderación.
La tercera fila, el 2 % entre el valor eficaz móvil y el promedio lineal, ha
desaparecido, porque el apartado 5.13 de la parte 2 dice entero «Not
applicable for PVEM». Tampoco imprime la parte 2 una tabla de tiempos de
decaimiento, así que la sección 9 no tiene equivalente en ella. Eso no saca
del todo el valor eficaz móvil del instrumento: el 5.1.2 sigue dejando que un
PVEM de cuerpo entero dé el MTVV, el mayor valor que alcanza su valor eficaz
móvil, y la Tabla 8 califica ese MTVV en la ráfaga igual que la sección 10.
`PVEM_INDICATION_TOLERANCES_PERCENT` es esa tabla,
de modo que una comprobación que la recorra califica un PVEM con lo que
imprime la parte 2 y con nada más:

```python
from phonometry import vibration

print(dict(vibration.PVEM_INDICATION_TOLERANCES_PERCENT))
# {'indication': 4.0, 'low-frequency indication': 5.0, 'weighting consistency': 3.0}

# La fila que la parte 2 no imprime se queda donde la puso la parte 1.
print(vibration.RUNNING_RMS_CONSISTENCY_TOLERANCE_PERCENT)   # 2.0
```

Dos párrafos del 12.7 de la parte 2 llegaron sin cambios desde la parte 1, y
ninguno encaja con el medidor que ahora describen. El ensayo de coherencia de
la ponderación sigue apuntando a «the appropriate weighting factor (see
Table 1)», y la Tabla 1 de la parte 2 sigue imprimiendo 0,388 8 para `Wf`, así
que la advertencia de la sección 6 vale para un PVEM palabra por palabra:
`band_limited_weighting_factor` es el factor con el que la fila se puede
cumplir. Y el párrafo siguiente sigue juzgando «each time weighting» frente a
«the tolerance limits of Table 2», cuya fila de ponderación temporal la parte 2
ya no imprime. Los dos están en el
[registro de erratas](/phonometry/es/reference/errata/).

**Sus propias incertidumbres.** La parte 2 imprime la incertidumbre expandida
máxima que cada uno de sus apartados de ensayo le permite a un laboratorio, y
en el apartado 12, el ensayo de tipo, cada cifra es la que imprime la parte 1
con el mismo número: un 4,5 % para la respuesta en frecuencia mecánica del
12.11.2, un 3 % para la eléctrica del 12.11.3, un 5 % para la respuesta global
del 12.11.4 y un 3 % para la ráfaga del 12.13. Es en el apartado 13 donde los
dos documentos se separan. La parte 2 no tiene validación de un instrumento de
ejemplar único, que es el apartado 13 de la parte 1, y su verificación
periódica es el apartado 13 y no el 14: el 13.9 de la parte 2 es el 5 % de una
verificación periódica, el equivalente del 14.9 de la parte 1, mientras que el
13.9 de la parte 1 es el 2 % de otro ensayo. Un mismo número de apartado nombra
un ensayo distinto en cada documento, y por eso las dos tablas van por
separado:

```python
from phonometry import vibration

pvem = vibration.PVEM_MAX_EXPANDED_UNCERTAINTY_PERCENT
general = vibration.MAX_EXPANDED_UNCERTAINTY_PERCENT
for clause in ("12.11.2", "12.11.3", "12.11.4", "12.13"):
    print(clause, pvem[clause], general[clause])
# 12.11.2 4.5 4.5
# 12.11.3 3.0 3.0
# 12.11.4 5.0 5.0
# 12.13 3.0 3.0
print(pvem["13.9"], general["13.9"], general["14.9"])   # 5.0 2.0 5.0
print(sorted(set(general) - set(pvem)))
# ['13.11', '13.14', '13.15', '14.9']
print(vibration.ISO8041_COVERAGE_FACTOR)                # 2.0
```

La regla de decisión de la sección 4 no cambia: los apartados 12.1 y 13.1 de
la parte 2 imprimen la frase y el factor de cobertura que imprime la parte 1,
así que `verify_weighting` con el `expanded_uncertainty_percent` del propio
laboratorio es también el veredicto de un PVEM, con la cifra de la parte 2
como techo de lo que el laboratorio puede declarar.

Lo que la parte 2 añade más allá de estas tablas no está aquí. La aritmética
de su 12.11, las Fórmulas (9) a (13), reparte un error de respuesta en
frecuencia entre el transductor y la parte eléctrica del instrumento y combina
el error aparente con la incertidumbre del laboratorio; el ensayo de registro
del 12.22 hace funcionar el medidor 12 h, con una pasada en el excitador al
principio y otra al final, y lee su fichero de registro muestra a muestra; y
el registro, la detección del operario, la detección de artefactos
transitorios (anexo A) y la fuerza de contacto (anexo B) son propiedades del
hardware.

## 12. La misma comprobación al otro lado de la frontera

Un sonómetro recibe exactamente este trato, de otro comité y en otra unidad.
La IEC 61672-1 imprime objetivos de diseño para las ponderaciones A, C y Z y
límites de aceptación a su alrededor, y
[`verify_weighting_class`](/phonometry/es/signals/levels/weighting/) convierte una
respuesta en un veredicto frente a ellos. Los dos verificadores son la misma
idea aplicada a uno y otro lado de la frontera entre acústica y vibración:

```python

from phonometry import filters, vibration

# Sonido: un filtro de ponderación que diseñó esta biblioteca, frente a la Tabla 3 de IEC 61672-1.
wf = filters.WeightingFilter(48000, "A")
print(filters.verify_weighting_class(wf).overall_class)   # 1

# Vibración: el barrido de banco de la sección 2, frente a las Tablas 4 y 5 de ISO 8041-1.
sweep = 10.0 ** (np.array([-3, 0, 3, 6, 9, 12, 15, 18, 19]) / 10.0)
read = np.array([0.4314, 0.4969, 0.5466, 0.9937, 1.068,
                 0.7897, 0.3427, 0.1894, 0.1366])
print(vibration.verify_weighting("Wk", sweep, read).passes)   # False
```

Conviene nombrar tres diferencias, porque son las que hacen tropezar al lector
que pasa de una página a la otra.

**No hay clases.** La IEC 61672-1 especifica dos categorías de prestaciones, y
el veredicto es cuál de ellas cumple una respuesta. La ISO 8041-1 no tiene
ninguna: imprime un solo juego de tolerancias, y el veredicto es un cumple o no
cumple frente a él.

**Los límites son porcentajes, no decibelios.** La ISO 8041-1 escribe sus
tolerancias de magnitud como porcentajes del factor de ponderación, y la
biblioteca las mantiene así. El Anexo B, informativo, imprime al lado los
equivalentes en decibelios, +1 dB / −1 dB en la región central y +2 dB / −2 dB
en las faldas, pero el requisito está escrito en porcentaje.

**Se califican frente a cosas distintas.** `verify_weighting_class` lee un
filtro digital que ha construido esta biblioteca e informa de si ese *diseño*
cabe en la máscara, así que toda medición hecha en software hereda el veredicto.
A `verify_weighting` se le entregan números de un banco, y su veredicto
pertenece a *esa medición de ese instrumento*, el día en que se hizo. Ninguno de
los dos es un ensayo de tipo, una verificación periódica ni una comprobación in
situ, y ninguno de los dos tiene un micrófono, un transductor ni un número de
serie.
[Conformidad y verificación](/phonometry/es/signals/metrology/compliance-verification/)
es el mapa de todos los verificadores de la biblioteca y de dónde termina la
afirmación de cada uno.

## Qué cubre esta guía

La **banda de tolerancia alrededor de una ponderación frecuencial**: las cuatro
frecuencias de transición de la Tabla 4 construidas a partir de sus exponentes
impresos, los tres pares de límites distintos que la Tabla 5 reparte entre
ellas, y el veredicto de `verify_weighting` sobre una respuesta medida, con la
incertidumbre expandida del laboratorio de ensayo ampliando la desviación como
exigen 13.1 y 14.1.

La **desviación característica de fase** de la Fórmula (6), calculada sobre la
malla que pide el 12.11.1 y calificada frente a la columna de fase de la
Tabla 5, con el coste en valor de pico de la Fórmula (H.4) al lado.

La **etapa de limitación de banda por separado**, los **tiempos de decaimiento
del valor eficaz móvil** de las Tablas 10 y 11 en forma cerrada, y las **228
indicaciones de la ráfaga en diente de sierra** de las Tablas 7 a 9 reproducidas
a partir de la señal que define la Tabla 6.

Las **condiciones de referencia** de la Tabla 1 y la **tolerancia de
indicación** de la Tabla 2, publicadas como la ventana en la que tiene que caer
una indicación. Se publican, no se comprueban: leer una pantalla es una medición
de banco.

El **medidor personal de exposición a vibraciones** de la ISO 8041-2:2021: sus
228 celdas de ráfaga de las Tablas 7 a 9, las de la parte 1 dígito a dígito,
calificadas en el informe de conformidad frente a la página de la parte 2; su
Tabla 2 de dos filas; y las incertidumbres expandidas máximas que imprimen sus
apartados 12 y 13.

**Ningún banco, en ninguna parte.** Todo criterio de aquí es un lado de una
comparación cuyo otro lado alguien tiene que medir sobre hardware. La
exactitud de indicación, la linealidad, el ruido del instrumento, la sobrecarga,
la diafonía, las características del transductor, el montaje y el apartado
ambiental y electromagnético entero no están implementados ni son implementables
aquí.

**Ningún veredicto de conformidad para un instrumento.** Cumplir en cualquier
apartado de esta página es una afirmación sobre ese apartado. El ensayo de tipo,
la verificación periódica y la comprobación in situ son procedimientos sobre un
vibrómetro físico, y aquí nada lleva un número de serie.

**El resto de la ISO 8041-2.** La aritmética de respuesta en frecuencia de su
12.11 (Fórmulas (9) a (13)), el ensayo de registro de 12 h del 12.22, y los
apartados de registro, detección del operario, detección de artefactos
(anexo A) y fuerza de contacto (anexo B) no están implementados.

## Véase también

- [Exposición humana a vibración (ISO 2631, ISO 5349)](/phonometry/es/vibration/human/human-vibration/): las
  ponderaciones frente a las que esta página califica un instrumento, y la
  cadena de exposición que las consume.
- [Conformidad y verificación](/phonometry/es/signals/metrology/compliance-verification/):
  los demás verificadores, y qué solo puede atestiguar un laboratorio.
- [Ponderación frecuencial (A, C, Z)](/phonometry/es/signals/levels/weighting/): las
  ponderaciones del sonómetro y los límites de aceptación de IEC 61672-1 de la
  sección 12.
- [Calibración y dBFS](/phonometry/es/signals/metrology/calibration/): la comprobación
  de antes y después sobre la que se construye una verificación in situ, y la
  trazabilidad con la que se informa un ensayo de tipo.
- Referencia de la API:
  [`vibration.human.instrumentation`](https://jmrplens.github.io/phonometry/reference/api/vibration/instrumentation/).
