<!-- canonical: https://docs.jmrp.io/phonometry/es/aircraft/anp-fleet/ -->
Source: https://docs.jmrp.io/phonometry/es/aircraft/anp-fleet/

[Ruido de aeropuertos (ECAC Doc 29)](/phonometry/es/aircraft/airport-noise/)
calcula un nivel de evento a partir de una tabla nivel-potencia-distancia y una
trayectoria. Esa guía aporta ambas a mano, que es lo que quieres mientras
aprendes el método y lo que no quieres nunca después: en un estudio real los
números salen de la base de datos **Aircraft Noise and Performance (ANP)** que
publican EASA y EUROCONTROL para los tipos de aeronave que vuelan de verdad.

Esa base se distribuye con phonometry. Esta guía es el puente entre ella y las
funciones de Doc 29: cómo abrirla, qué contiene el registro de una aeronave, y
cómo pasar de un identificador a un nivel de evento o un contorno sin escribir
tú ninguna tabla.

*Una aeronave, de su registro a un solo número. Un tipo que la base no tiene
entra por arriba, con un sustituto que recomienda la web de ANP y un ajuste que
aplicas tú. El A320-211 no trae ningún despegue de punto fijo, así que sus pasos
publicados se vuelan en un aeródromo a nivel del mar; el tercero de los diez
segmentos del perfil que resultan pasa a 612 m de un receptor situado 3 km traza
abajo y 500 m a un costado, lee las cuatro celdas de la tabla NPD que rodean
20 159 lb y 612 m, y con 88,0 dB aporta cerca de cuatro quintos de la energía
sonora del suceso de 89,0 dB.*

## 1. Abrir la base de datos

`load_anp_database()` sin argumentos lee la copia que viene con el paquete.
Apúntalo a un directorio para leer cualquier otra exportación CSV de ANP.

```python
from phonometry import aircraft

db = aircraft.load_anp_database()
print(len(db.aircraft_ids))          # 155 tipos de aeronave
ac = db.aircraft("747100")
print(ac.description)                # Boeing 747-100 / JT9DBD
print(ac.engine_type, ac.num_engines, ac.weight_class)
print(ac.power_parameter, ac.mounting)
```

Las guías hermanas importan el módulo como `aircraft` y llaman a
`aircraft.event_level(...)` sobre él; aquí `ac` es un **registro** de la base de
datos, y sus `event_level` y `noise_contour` son esas mismas funciones con las
tablas NPD y el perfil por defecto ya rellenados. Mantener los dos separados
importa si encadenas snippets de las dos páginas.

Un `AnpAircraft` se describe con el tipo y número de motores y la clase de
estela OACI, y lleva dos campos que usarás directamente.

El **parámetro de potencia** nombra la magnitud con la que está indexada la
tabla NPD. Importa porque no es una fuerza en newtons sino lo que tabuló el
fabricante, empuje neto corregido en libras para la mayoría de reactores, así
que la potencia que pases a `level` tiene que ir en esas unidades.

El **montaje** de los motores es el único campo del registro que lee la propia
cadena de Doc 29. Se deriva del identificador de directividad lateral de ANP y
vale `"wing"`, `"fuselage"` o `"propeller"`, que selecciona la corrección por
instalación de motores que la
[guía de ruido de aeropuertos](/phonometry/es/aircraft/airport-noise/) aplica a
mano. La elección no es cosmética: a ángulos de depresión pequeños el montaje
en ala y en fuselaje difieren en más de un decibelio, las hélices no reciben
esa corrección, y la flota distribuida se reparte 70 / 55 / 30 entre los tres.
Un identificador que la base no reconoce recae en `"wing"`.

### Encontrar tu aeronave

Los identificadores son los de la propia base ANP. Se parecen a un designador de
tipo de la OACI, pero no son lo mismo, porque un tipo aparece una vez por
variante de motor: `A320-232` es el A320 con motores IAE y `747100` el 747-100
con JT9D. Busca en las descripciones para encontrar la tuya en lugar de adivinar
la cadena:

```python
from phonometry import aircraft

db = aircraft.load_anp_database()
for aid in db.aircraft_ids:
    rec = db.aircraft(aid)
    if "A320" in rec.description:
        print(aid, "|", rec.description, "|", rec.engine_type, "|", rec.mounting)
# A320-211 | Airbus A320-211 / CFM56-5A1 | Jet | wing
# A320-232 | Airbus A320-232 / V2527-A5 | Jet | wing
```

Casa la variante de motor antes que ninguna otra cosa: cambia los niveles NPD más
que cualquiera de las correcciones por segmento.

### Cuando tu aeronave no está en la base

Toda lista real de movimientos contiene tipos que la base no tiene, y el remedio
aceptado es la **sustitución** por un tipo acústica y operativamente parecido, no
la invención. Casa primero el tipo y el número de motores, y después la clase de
peso y el montaje de motores, porque esos cambian la *forma* de la respuesta en
lugar de desplazarla; comprueba que el `power_parameter` del sustituto es la
misma magnitud que el del original, ya que una tabla indexada por empuje neto
corregido en libras no admite reglajes de potencia calculados para otra indexada
por cualquier otra cosa. Registra la sustitución junto con los resultados: es una
hipótesis de modelado, no un detalle. El mismo razonamiento vale un nivel más
abajo: un tipo cuyas curvas NPD están tabuladas pero cuya trayectoria no lo está
(véase la sección 3) suele modelarse mejor con una *trayectoria* sustituta y su
propia tabla NPD que sustituyendo la aeronave entera.

## 2. Las curvas nivel-potencia-distancia

`npd_curves` devuelve la superficie NPD tabulada para una operación (`"D"` de
despegue, `"A"` de aproximación) y una métrica (`"SEL"` o `"LAmax"`): un nivel
por cada combinación de reglaje de potencia y distancia oblicua. Entre los nodos
tabulados la interpolación de Doc 29 es logarítmica en distancia y lineal en
potencia, que es lo que dibujan las curvas de abajo.

*Los tres reglajes de empuje tabulados van casi paralelos: la potencia sobre todo
desplaza el nivel, mientras que la distancia fija la forma. La caída es cercana a
la del inverso del cuadrado a corta distancia y se empina a gran distancia a
medida que se acumula la absorción, y los marcadores son las únicas distancias
sobre las que la base afirma algo: todo lo que queda entre ellos es interpolación
de la Doc 29.*

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

```python

from phonometry import aircraft

ac = aircraft.load_anp_database().aircraft("747100")
curves = ac.npd_curves("D", "SEL")

fig, ax = plt.subplots(figsize=(10, 6))
curves.plot(ax=ax, language="es")
ax.set_title(f"Curvas NPD ANP - {ac.description} (SEL, despegue)")
ax.text(0.02, 0.06,
        f"parámetro de potencia: {ac.power_parameter}\n"
        "marcadores: nodos NPD tabulados",
        transform=ax.transAxes, va="bottom", fontsize=9)
plt.show()
```

</details>

```python
from phonometry import aircraft

aircraft.load_anp_database().aircraft("747100").npd_curves("D", "SEL").plot(language="es")
```

Para leer un valor suelto en vez de dibujar la familia, `level` interpola a
cualquier potencia y distancia:

```python
from phonometry import aircraft

curves = aircraft.load_anp_database().aircraft("A320-232").npd_curves("D", "SEL")
print(curves.powers)                       # [10000. 14000. 19000. 23000.] lb
print(curves.level(19000.0, [304.8, 1000.0, 3000.0]))
```

El `power_parameter` del registro nombra esas unidades: nunca supongas newtons.

Las distancias están en metros. La base las tabula en pies, en los diez nodos de
Doc 29 de 200 ft a 25000 ft, y este puente convierte al leer para que todo lo de
aguas abajo siga en SI.

## 3. La trayectoria por defecto

El registro de una aeronave lleva además trayectorias por defecto. `profile`
devuelve una como trayectoria de Doc 29: un array `(N, 5)` de posición sobre la
ruta, lateral y vertical más el reglaje de potencia y la velocidad verdadera,
con máscaras booleanas que marcan qué segmentos son el recorrido de despegue o
el de aterrizaje.

*Los primeros puntos están a altitud cero y son el recorrido de despegue. Lo que
sigue es el gradiente de subida, y es el gradiente, y no el nivel, lo que decide
el contorno,
porque fija la distancia oblicua en cada receptor; la misma aeronave con una
etapa más larga va más pesada y sube más despacio, así que su huella es más larga
y más ancha.*

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

```python

from phonometry import aircraft

ac = aircraft.load_anp_database().aircraft("747100")
profile = ac.profile("D", stage_length=1)

fig, ax = plt.subplots(figsize=(10, 6))
profile.plot(ax=ax, language="es")
ax.set_title(f"Perfil de despegue por defecto ANP - {ac.description}")
ax.text(0.98, 0.06,
        f"etapa {profile.stage_length}, "
        f"{profile.path.shape[0]} puntos fijos",
        transform=ax.transAxes, va="bottom", ha="right", fontsize=9)
plt.show()
```

</details>

```python
from phonometry import aircraft

aircraft.load_anp_database().aircraft("747100").profile("D", stage_length=1).plot(language="es")
```

La **longitud de etapa** selecciona el tramo de distancia de viaje: una etapa más
larga significa más combustible, más peso y una subida más tendida, así que la
misma aeronave tiene un perfil por tramo. El Apéndice G3.5 del Vol. 2 de la
Doc 29 define los tramos por longitud de viaje en millas náuticas: el 1 es 0-500,
el 2 es 500-1 000, el 3 es 1 000-1 500, el 4 es 1 500-2 500, el 5 es 2 500-3 500,
el 6 es 3 500-4 500, el 7 es 4 500-5 500, y así en pasos de 1 000 nmi hasta el 10
(7 500-8 500), con el 11 para cualquier cosa más larga y «M» para el alcance
máximo con la masa máxima de despegue. El peso de despegue de cada perfil se
calcula al alcance representativo del tramo, definido como el mínimo más el 70 %
de la horquilla, así que el tramo 1 se pesa a 350 nmi y el tramo 4 a 2 200 nmi.
No todas las aeronaves vuelan todos los tramos, y los perfiles de punto fijo que
se distribuyen cubren las etapas 1 a 7 para despegues y solo la 1 para llegadas.

Un perfil de **punto fijo** es una trayectoria lista para volar, y la mayoría de
las entradas ANP no traen ninguna: describen sus despegues como pasos de
procedimiento (sube a este régimen hasta tal altitud, acelera, repliega flaps),
que hay que volar a través de un modelo de mecánica del vuelo antes de que sean
una trayectoria. De las 155 aeronaves de la base distribuida solo 13 tienen
perfil de *despegue* de punto fijo y 20 perfil de *llegada* de punto fijo; la
sección 4 vuela el resto. Pedir un perfil de punto fijo que no existe lanza un
`KeyError` que nombra las etapas que sí, que es además la forma de descubrir los
tramos que una aeronave trae de verdad:

```python
from phonometry import aircraft

db = aircraft.load_anp_database()
for identifier, operation, stage in (("A320-232", "D", 1), ("747100", "D", 9)):
    try:
        db.profile(identifier, operation, stage)
    except KeyError as exc:
        print(exc)
# ... 'A320-232', operation 'D', stage length 1 (available stage lengths: [])
# ... '747100', operation 'D', stage length 9 (available: [1, 2, 3, 4, 5, 6])
```

Una lista vacía significa que el tipo no tiene ningún perfil de punto fijo y hay
que volarle una trayectoria; una no vacía significa que has pedido un tramo que
esa aeronave no vuela. Las curvas NPD, en cambio, están tabuladas para todas las
aeronaves de la base.

## 4. Volar un procedimiento publicado

Un procedimiento no es una trayectoria, y ahí está toda la dificultad. Sus pasos
dicen lo que hace el avión, no adónde va: sube a este régimen hasta tal altitud,
acelera hasta tal velocidad, cambia a empuje de ascenso. Dónde lo dejan esas
instrucciones sobre el terreno depende del campo, porque los mismos pasos
volados desde una pista caliente y muy sobre el nivel del mar alcanzan los
10 000 ft mucho más lejos que desde una fría junto a la costa. No hay nada que
tabular, y por eso la base distribuye los pasos y no los puntos.

`flight_profile` los vuela, con el modelo de actuaciones de vuelo del [Apéndice B
del Vol. 2 de ECAC Doc
29](/phonometry/es/reference/api/aeroacoustics/flight-performance/). Exige un
`aerodrome`, porque calcula la trayectoria y esta depende del campo, mientras
que `profile` devuelve un perfil de punto fijo ya tabulado y no necesita ese
argumento. Trabaja en las unidades de la propia norma: pies, nudos y libras.

```python
from phonometry import aircraft

sea_level = aircraft.Aerodrome(elevation_ft=0.0)
flown = aircraft.load_anp_database().flight_profile(
    "A320-211", "departure", aerodrome=sea_level, stage_length=1
)
print(len(flown.points), round(flown.distance_ft[-1]), flown.altitude_ft[-1])
# 11 79423 10000.0
flown.plot(language="es")
```

*El A320-211 no distribuye ningún perfil de despegue de punto fijo, así que esta
es la única forma de volarlo. La banda sombreada es la carrera de despegue; la
línea de puntos marca dónde el procedimiento pasa de empuje de despegue a empuje
de ascenso, una caída de 3 047 lb por motor que la curva de altura apenas acusa.
Eso es lo que da calcular el empuje frente a leer una trayectoria: nada en la
forma del ascenso dice que se redujeron los motores, y el ruido lo dice sin
lugar a dudas.*

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

```python

from phonometry import aircraft

db = aircraft.load_anp_database()
airframe = db.aircraft("A320-211")
profile = db.flight_profile(
    "A320-211", "D", aerodrome=aircraft.Aerodrome(elevation_ft=0.0), stage_length=1
)

fig, ax = plt.subplots(figsize=(10, 6))
profile.plot(ax=ax, language="es")
fig.axes[-1].set_ylim(0.0, 1.35 * float(profile.corrected_net_thrust_lb.max()))
ax.set_title(
    f"Perfil de despegue por procedimiento (Doc 29) - {airframe.description}", pad=12
)
plt.show()
```

</details>

`procedural_profile` cruza de vuelta a las unidades que habla la cadena de ruido
y devuelve el mismo `AnpProfile` que una consulta de punto fijo. `event_level` y
`noise_contour` aceptan un `aerodrome` por la misma razón, así que una aeronave
que solo publica pasos recorre entera la cadena de Doc 29 desde su
identificador. Son 309 de los 310 pares de aeronave y operación de la base,
frente a los 33 que tienen trayectoria tabulada.

```python
from phonometry import aircraft

hot_and_high = aircraft.Aerodrome(elevation_ft=5000.0, temperature_c=25.0)
level = aircraft.load_anp_database().event_level(
    "A320-211", [3000.0, 500.0, 0.0], "departure", aerodrome=hot_and_high
)
print(round(float(level.level), 1))    # 89.3 dB
```

Un aeródromo, una atmósfera: la temperatura y la presión del campo llegan al
ajuste de impedancia de Doc 29 igual que al modelo de actuaciones, de modo que
un perfil volado a 35 °C no queda corregido para 15 °C por omisión.
`temperature_c` y `atmospheric_pressure_kpa` siguen mandando cuando las dos
difieren de verdad.

## 5. Directo a un nivel de evento o un contorno

Con las dos mitades en el registro, la aeronave puede ejecutar ella misma la
cadena de Doc 29. `event_level` coloca un sobrevuelo en un receptor y
`noise_contour` lo barre sobre una malla de tierra, cableando cada uno las
curvas NPD y el perfil por defecto en las funciones que la guía de ruido de
aeropuertos construye a mano.

El observador es `(x, y, z)` en metros en el **sistema de la pista**, y el
origen de ese sistema no es el límite del aeropuerto: $x$ corre a lo largo del
eje de pista con $x = 0$ en el inicio del recorrido de despegue para una salida y en el umbral
de aterrizaje para una llegada, así que los perfiles de llegada llevan $x$
negativa en aproximación final. Los datos que se distribuyen lo dicen sin
rodeos: `db.profile("747100", "D", 1).path[0]` empieza en $x = 0$ (suelta de
frenos) y termina 39,5 km más allá, mientras que
`db.profile("707", "A", 1).path[0]` empieza en $x = -34,9$ km y acaba 1,5 km
pasado el umbral, de modo que los dos sistemas están a casi 35 km uno del otro.
$y$ es el desplazamiento lateral respecto al eje de pista prolongado, positivo
a estribor del sentido de la marcha; su signo es lo que elige la rama de ángulo
de depresión de la regla de segmento en viraje. $z$ es la altura del receptor
sobre el terreno local, dejada en 0 en estos ejemplos, donde Doc 29 mide a
1,2 m, normalmente una diferencia por debajo del decibelio.

Tres argumentos deciden el resto, y dos de ellos son silenciosos. La métrica
vale por defecto el nivel de exposición sonora, con `"LAmax"` disponible si se
pide; la longitud de etapa vale por defecto 1, el tramo de distancia de viaje
más corto y por tanto la subida más empinada y la huella más pequeña; y los
opcionales `temperature_c` y `atmospheric_pressure_kpa` vuelven a referir los
niveles tabulados desde la impedancia acústica específica de referencia al aire
del aeródromo, y valen por defecto los 15 °C y 101,325 kPa de la atmósfera
estándar. Ese último par es un término de contabilidad y no una corrección
meteorológica: en la atmósfera estándar vale +0,07 dB, y rara vez pasa de unas
décimas. Los niveles NPD siguen llevando dentro la absorción de la atmósfera a
la que se redujeron, así que un aeródromo caluroso y seco no se modela
pasándole solo su temperatura. Si se le pasa también su
`relative_humidity_percent`, el cableado de eventos y contornos recalcula las
dos tablas NPD para ese aire según el apéndice D del volumen 2 de ECAC Doc 29,
con la clase espectral de la aeronave; sin ella, las tablas se quedan en la
atmósfera AIR-1845 a la que se normalizaron.
[Datos NPD para el aire del aeropuerto](/phonometry/es/aircraft/npd-atmosphere/)
recorre ese recálculo.

```python
from phonometry import aircraft

ac = aircraft.load_anp_database().aircraft("747100")
flyover = ac.event_level([3000.0, 500.0, 0.0], "D")
print(round(float(flyover.level), 1))     # 100.4 dB
```

Ese es el nivel de exposición sonora de evento único de un despegue de 747-100 en
un receptor a 3 km traza abajo y 500 m a un costado de ella. Aparta el receptor
hasta 1 500 m de separación lateral y cuesta más que la distancia añadida sola,
porque la atenuación lateral se enciende a medida que el ángulo de elevación cae
por debajo de 50°.

```python

from phonometry import aircraft

ac = aircraft.load_anp_database().aircraft("747100")
contour = ac.noise_contour(
    "D",
    x=np.linspace(-2000.0, 12000.0, 40),
    y=np.linspace(-3000.0, 3000.0, 30),
)
print(contour.levels.shape)      # (30, 40): un SEL por punto de la malla
contour.plot(language="es")
```

La malla se indexa `(y, x)`, que es la razón por la que la forma es `(30, 40)` y
no al revés. La comprobación más barata de que la malla y la trayectoria están en
el mismo sistema es que el máximo del array coincida con una llamada a
`event_level` en el punto de malla donde ocurre.

*La huella real del 747-100, a partir de las propias tablas NPD y del perfil de
despegue por defecto de la base: cuatro líneas de código y nada escrito a mano.
Es más estrecha y mucho más alargada que el contorno didáctico de la guía de
ruido de aeropuertos, porque un perfil de subida real pone el avión arriba
enseguida y la parte ruidosa del suceso se queda cerca de la pista. El receptor
marcado es la llamada a `event_level` de arriba, así que las dos mitades de esta
sección son el mismo cálculo en un punto y en 1 200 de ellos.*

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

```python

from phonometry import aircraft

ac = aircraft.load_anp_database().aircraft("747100")
profile = ac.profile("D", stage_length=1)
x = np.linspace(-2000.0, 12000.0, 40)
y = np.linspace(-3000.0, 3000.0, 30)

fig, ax = plt.subplots(figsize=(10, 5.5))
ac.noise_contour("D", x=x, y=y).plot(ax=ax, language="es")   # la gráfica va en kilómetros
inside = profile.path[:, 0] <= x.max()
ax.plot(profile.path[inside, 0] / 1000.0, profile.path[inside, 1] / 1000.0,
        "k--", lw=1.4, label="traza en tierra por defecto")
ax.plot([3.0], [0.5], "o", ms=8,
        label=f"receptor de event_level: SEL {float(flyover.level):.1f} dB")
ax.set_xlim(x.min() / 1000.0, x.max() / 1000.0)
ax.set_ylim(y.min() / 1000.0, y.max() / 1000.0)
ax.legend(loc="lower left", fontsize=8)
plt.show()
```

</details>

Todo lo que devuelven estos dos es el mismo tipo de resultado que usa la guía de
ruido de aeropuertos, así que el dibujo, la extracción de contornos y el
desglose por segmentos funcionan igual.

## Qué cubre esta guía

Abrir la base ANP de EASA distribuida con el paquete (u otra exportación CSV
de ANP) con `load_anp_database`; qué contiene el registro de una aeronave,
incluidos el parámetro de potencia con el que se indexa su tabla NPD y el
montaje de motores que lee la cadena de Doc 29; leer e interpolar la
superficie NPD con `npd_curves` y `level`; las trayectorias de punto fijo por
defecto y sus tramos de etapa; y ejecutar el nivel de evento único y el
contorno en malla de Doc 29 desde un identificador de aeronave con
`event_level` y `noise_contour`.

Los perfiles de pasos de procedimiento, que es como describen su despegue la
mayoría de las entradas ANP, mediante el modelo de mecánica del vuelo del
Apéndice B del Vol. 2 de Doc 29: `flight_profile` vuela un procedimiento
publicado para un aeródromo y su meteorología, y `procedural_profile` entrega
el resultado a la cadena de Doc 29 como la misma trayectoria que produce un
perfil de punto fijo.

Nada del contenido de la propia base: solo se lee, nunca se escribe, y
phonometry distribuye la versión 2.3 y no la actualiza.

## Véase también

Páginas de otras áreas del sitio en las que se apoya esta sección:

- [Ruido de aeropuertos (ECAC Doc 29)](/phonometry/es/aircraft/airport-noise/):
  el método en sí, construido con una tabla NPD y una trayectoria escritas a
  mano.
- [Ruido de aeronaves: nivel efectivo de ruido percibido](/phonometry/es/aircraft/aircraft-noise/):
  la métrica de certificación, que se mide en vez de tabularse.
- Referencia de la API:
  [`aircraft.anp_fleet`](/phonometry/es/reference/api/aeroacoustics/anp-fleet/).
