Correct the framing and the guards of the perception and noise-control fiches (#355)
A review pass over the psychoacoustics, hearing, speech, environmental and
noise-control fiches. The numerics held up; what did not were the statements
printed around them, plus one wrong table lookup.
ISO 1999 validated domain. nipts()/htlan() applied Formula (2) wherever they
were asked to: L_EX,8h = 130 dB over 60 years at the 0,99 fractile returned a
357,9 dB threshold shift with nothing marking it as an extrapolation. Since the
formula is quadratic in (L_EX,8h - L0) that number is meaningless, not merely
uncertain. Both now warn (NoiseInducedHearingLossWarning) outside the stated
ranges while still computing: durations outside 1-40 years (clause 6.3.1
validates Formula (2) over 10-40 and Formula (3) over 1-10), fractiles in the
tails clause 6.3.2 says "should not be estimated" (Q below 5 % or above 95 %),
and levels above the 100 dB of Annex D that the Scope's NOTE 4 restricts
validity to. The fiches print the caveat when the conditions sit outside.
ISO 1999 Q. The fiches printed the library's fractile under ISO 1999's symbol,
inverting its meaning: in Formulae (4)/(5) Q is the percentage with worse
hearing, so the most-susceptible tenth is Q = 10 %, not the "Q = 0.9" the fiche
showed while citing 6.3.2. They now print ISO's Q as ISO defines it; the guides
note the difference from the fractile argument. Two further disclosures on the
same fiches: the age component H is evaluated from ISO 7029:2017 (the edition
ISO 1999 references undated in 6.2.2), which departs from the illustrative
Table A.3 selection by up to about 7 dB at the median, and the 2/3/4 kHz
average is the user's own choice, the Scope's NOTE 1 specifying no frequency
combination. The footer states a population scope rather than "the results
relate only to the tested specimen", which describes a laboratory specimen.
ISO 1999 Annex C is wired in as an independent oracle: its worked example (male
population aged 50, 90 dB for 30 years, 1/2/4 kHz at Q = 10 %) reproduces the
Table D.2 shifts it consumes (0, 9, 19 dB), the 13,3 dB left of the 4 kHz shift
after the Formula (1) compression (C.5) and the 31,1 dB combined threshold
(C.11). The composition it exercises is now exposed as combine_age_and_noise(),
which clause 6.2 wants available on its own: 6.2.3 recommends a database B
collected on a control population of the country under consideration, and this
applies Formula (1) to whichever database the user brings.
Verdict precision. The STI and SII fiches printed the requirement with one
decimal beside a measured value at full precision, so a verdict could contradict
itself: "STI = 0.50, required >= 0.5 -> FAIL" against a 0,52 requirement, and an
SII minimum of 0,75 printed as "0.8" (the committed example said so). Both now
print the requirement at the quantity's own precision. IEC 60268-16 Annex M
joins the conformance report as an end-to-end oracle: its printed MTF matrix,
speech spectrum and ambient noise give back its published MTI row and
STI = 0,76, exercising the whole A.5.3 to A.5.8 chain.
Noise-control prediction framing. The enclosure, silencer and HVAC fiches
compute design models but read as measurements: no prediction statement,
measurement headers, a footer scoped to a tested specimen, and committed
examples citing instrumentation that never existed ("Two-microphone
transfer-matrix bench"). They now follow the EN/ISO 12354 prediction exemplar
already in the repo, with a prediction-basis line, a statement naming what each
model does not represent, and a prediction footer. Their verdicts also decided
on the half-away-from-zero display rounding while printing Python's
round-half-to-even, so 0,25 printed 0.2 against a verdict taken on 0,3; both
now use the display rounding.
ISO/PAS 1996-3. With every onset rate at or below 10 dB/s the fiche withheld
the adjustment on the onset-rate gate (clauses 4.5/8) but justified it with "no
prominent impulse is present (governing P = 6.01 <= 5)", contradicting its own
boxed P. The note now states whichever gate governs. The assessment period is
read from the result instead of being hardcoded: 30 min is the Clause 5
*default*, now the default of the new assessment_period_min argument.
Smaller corrections:
- the HVAC elbow insertion loss took the wrong row of Bies Table 8.11 for a
W/lambda exactly on a bin edge; the rows read "a <= W/lambda < b", so an edge
opens its row (1 dB at 0,14, not 0 dB);
- the wind-turbine tonality fiche cited "subclauses 9.5.2-9.5.5" of
IEC 61400-11 for a chain running through 9.5.6 to 9.5.8 (Formulae 31-34);
- the ISO 1996-2 tonal fiche notes that Table J.1 keys on the mean audibility
of the J assessed spectra (ISO/PAS 20065 Clause 5.3.9), which a
single-spectrum assessment stands in for;
- the shared 10-90 % fractile band carried a hardcoded English legend in
Spanish figures, and the Spanish silencer and HVAC fiches printed the device
kind and duct-element label in English.
docs/ERRATA.md records two more source defects found on the way: ISO/PAS
1996-3:2022 Clause 5 swaps the 3.4/3.5 cross-references of the onset rate and
the level difference (its own units contradict the clause numbers printed with
them), and ISO 9613-2:1996 Table 2 prints 4,1 dB/km at 15 C / 80 % / 1 kHz
where ISO 9613-1 gives 4,1511, the neighbouring cells rounding correctly. The
library computes that coefficient from ISO 9613-1 directly, so it is unaffected.
Committed example fiches, the conformance report, the API reference and the
llms files are regenerated.
Fix ANP fixed-point profile identity and the Doc 29 bank-angle observer side (#271)
* fix(aircraft): key ANP fixed-point profiles on their Profile_ID
The fixed-point profile parser grouped rows by (aircraft, operation, stage
length) only, so aircraft shipping several profiles for the same operation
and stage length (CNA206/CNA20T departures carry DEFAULT and 3000LB weight
variants) had all their points merged and sorted by point number, producing
an interleaved, physically impossible trajectory that fed the Doc 29
single-event and contour chain.
Key the parse on the full ANP identity (ACFT_ID, Op Type, Profile_ID, Stage
Length) and add an optional profile_id= keyword to AnpDatabase.profile and
AnpAircraft.profile. Without it the DEFAULT profile is selected when
present, a single available profile is used, and an ambiguous request
raises listing the identifiers. Duplicate or non-consecutive point numbers
within a profile now raise instead of silently corrupting the path.
Tests: CNA206 D/1 loads its own 9 points with non-decreasing altitude (the
merge produced a sawtooth), a synthetic two-profile export selects DEFAULT,
and every bundled profile's point count equals its CSV row count.
* fix(aircraft): apply the Doc 29 bank-angle sign to the correct observer side
ECAC Doc 29 4th ed. Vol 2 section 4.5.2 defines the depression angle as
phi = beta + eps for observers to starboard (right of the flight
direction) and phi = beta - eps for observers to port, with the bank
angle eps measured counter-clockwise about the roll axis (positive in a
left turn, starboard wing up). The segment geometry computed the observer
side from the cross product with +1 on the port side and then added
side * eps, the exact inversion: on a banked segment the starboard
receiver got the port depression angle and vice versa, mirroring the
lateral-directivity (engine-installation) correction of every turning
flight. The directly-overhead branch subtracted eps unconditionally.
Flip the side to +1 = starboard in both the scalar and the vectorised
grid kernels, derive the overhead branch from the same cross product
(phi = +-90 deg exactly on the track), and state the convention in the
docstrings and the EN/ES guides.
Tests: the section 4.5.2 oracle (beta = 36.87 deg, eps = 20 deg gives
phi = 56.87 deg to starboard and 16.87 deg to port), an eps = 0
regression, and an integration check that a banked segment reads louder
on the starboard side for wing and fuselage mountings and stays
symmetric for propeller aircraft.
Fix ANP fixed-point profile identity and the Doc 29 bank-angle observer side (#271)
* fix(aircraft): key ANP fixed-point profiles on their Profile_ID
The fixed-point profile parser grouped rows by (aircraft, operation, stage
length) only, so aircraft shipping several profiles for the same operation
and stage length (CNA206/CNA20T departures carry DEFAULT and 3000LB weight
variants) had all their points merged and sorted by point number, producing
an interleaved, physically impossible trajectory that fed the Doc 29
single-event and contour chain.
Key the parse on the full ANP identity (ACFT_ID, Op Type, Profile_ID, Stage
Length) and add an optional profile_id= keyword to AnpDatabase.profile and
AnpAircraft.profile. Without it the DEFAULT profile is selected when
present, a single available profile is used, and an ambiguous request
raises listing the identifiers. Duplicate or non-consecutive point numbers
within a profile now raise instead of silently corrupting the path.
Tests: CNA206 D/1 loads its own 9 points with non-decreasing altitude (the
merge produced a sawtooth), a synthetic two-profile export selects DEFAULT,
and every bundled profile's point count equals its CSV row count.
* fix(aircraft): apply the Doc 29 bank-angle sign to the correct observer side
ECAC Doc 29 4th ed. Vol 2 section 4.5.2 defines the depression angle as
phi = beta + eps for observers to starboard (right of the flight
direction) and phi = beta - eps for observers to port, with the bank
angle eps measured counter-clockwise about the roll axis (positive in a
left turn, starboard wing up). The segment geometry computed the observer
side from the cross product with +1 on the port side and then added
side * eps, the exact inversion: on a banked segment the starboard
receiver got the port depression angle and vice versa, mirroring the
lateral-directivity (engine-installation) correction of every turning
flight. The directly-overhead branch subtracted eps unconditionally.
Flip the side to +1 = starboard in both the scalar and the vectorised
grid kernels, derive the overhead branch from the same cross product
(phi = +-90 deg exactly on the track), and state the convention in the
docstrings and the EN/ES guides.
Tests: the section 4.5.2 oracle (beta = 36.87 deg, eps = 20 deg gives
phi = 56.87 deg to starboard and 16.87 deg to port), an eps = 0
regression, and an integration check that a banked segment reads louder
on the starboard side for wing and fuselage mountings and stays
symmetric for propeller aircraft.
Correct the framing and the guards of the perception and noise-control fiches (#355)
A review pass over the psychoacoustics, hearing, speech, environmental and
noise-control fiches. The numerics held up; what did not were the statements
printed around them, plus one wrong table lookup.
ISO 1999 validated domain. nipts()/htlan() applied Formula (2) wherever they
were asked to: L_EX,8h = 130 dB over 60 years at the 0,99 fractile returned a
357,9 dB threshold shift with nothing marking it as an extrapolation. Since the
formula is quadratic in (L_EX,8h - L0) that number is meaningless, not merely
uncertain. Both now warn (NoiseInducedHearingLossWarning) outside the stated
ranges while still computing: durations outside 1-40 years (clause 6.3.1
validates Formula (2) over 10-40 and Formula (3) over 1-10), fractiles in the
tails clause 6.3.2 says "should not be estimated" (Q below 5 % or above 95 %),
and levels above the 100 dB of Annex D that the Scope's NOTE 4 restricts
validity to. The fiches print the caveat when the conditions sit outside.
ISO 1999 Q. The fiches printed the library's fractile under ISO 1999's symbol,
inverting its meaning: in Formulae (4)/(5) Q is the percentage with worse
hearing, so the most-susceptible tenth is Q = 10 %, not the "Q = 0.9" the fiche
showed while citing 6.3.2. They now print ISO's Q as ISO defines it; the guides
note the difference from the fractile argument. Two further disclosures on the
same fiches: the age component H is evaluated from ISO 7029:2017 (the edition
ISO 1999 references undated in 6.2.2), which departs from the illustrative
Table A.3 selection by up to about 7 dB at the median, and the 2/3/4 kHz
average is the user's own choice, the Scope's NOTE 1 specifying no frequency
combination. The footer states a population scope rather than "the results
relate only to the tested specimen", which describes a laboratory specimen.
ISO 1999 Annex C is wired in as an independent oracle: its worked example (male
population aged 50, 90 dB for 30 years, 1/2/4 kHz at Q = 10 %) reproduces the
Table D.2 shifts it consumes (0, 9, 19 dB), the 13,3 dB left of the 4 kHz shift
after the Formula (1) compression (C.5) and the 31,1 dB combined threshold
(C.11). The composition it exercises is now exposed as combine_age_and_noise(),
which clause 6.2 wants available on its own: 6.2.3 recommends a database B
collected on a control population of the country under consideration, and this
applies Formula (1) to whichever database the user brings.
Verdict precision. The STI and SII fiches printed the requirement with one
decimal beside a measured value at full precision, so a verdict could contradict
itself: "STI = 0.50, required >= 0.5 -> FAIL" against a 0,52 requirement, and an
SII minimum of 0,75 printed as "0.8" (the committed example said so). Both now
print the requirement at the quantity's own precision. IEC 60268-16 Annex M
joins the conformance report as an end-to-end oracle: its printed MTF matrix,
speech spectrum and ambient noise give back its published MTI row and
STI = 0,76, exercising the whole A.5.3 to A.5.8 chain.
Noise-control prediction framing. The enclosure, silencer and HVAC fiches
compute design models but read as measurements: no prediction statement,
measurement headers, a footer scoped to a tested specimen, and committed
examples citing instrumentation that never existed ("Two-microphone
transfer-matrix bench"). They now follow the EN/ISO 12354 prediction exemplar
already in the repo, with a prediction-basis line, a statement naming what each
model does not represent, and a prediction footer. Their verdicts also decided
on the half-away-from-zero display rounding while printing Python's
round-half-to-even, so 0,25 printed 0.2 against a verdict taken on 0,3; both
now use the display rounding.
ISO/PAS 1996-3. With every onset rate at or below 10 dB/s the fiche withheld
the adjustment on the onset-rate gate (clauses 4.5/8) but justified it with "no
prominent impulse is present (governing P = 6.01 <= 5)", contradicting its own
boxed P. The note now states whichever gate governs. The assessment period is
read from the result instead of being hardcoded: 30 min is the Clause 5
*default*, now the default of the new assessment_period_min argument.
Smaller corrections:
- the HVAC elbow insertion loss took the wrong row of Bies Table 8.11 for a
W/lambda exactly on a bin edge; the rows read "a <= W/lambda < b", so an edge
opens its row (1 dB at 0,14, not 0 dB);
- the wind-turbine tonality fiche cited "subclauses 9.5.2-9.5.5" of
IEC 61400-11 for a chain running through 9.5.6 to 9.5.8 (Formulae 31-34);
- the ISO 1996-2 tonal fiche notes that Table J.1 keys on the mean audibility
of the J assessed spectra (ISO/PAS 20065 Clause 5.3.9), which a
single-spectrum assessment stands in for;
- the shared 10-90 % fractile band carried a hardcoded English legend in
Spanish figures, and the Spanish silencer and HVAC fiches printed the device
kind and duct-element label in English.
docs/ERRATA.md records two more source defects found on the way: ISO/PAS
1996-3:2022 Clause 5 swaps the 3.4/3.5 cross-references of the onset rate and
the level difference (its own units contradict the clause numbers printed with
them), and ISO 9613-2:1996 Table 2 prints 4,1 dB/km at 15 C / 80 % / 1 kHz
where ISO 9613-1 gives 4,1511, the neighbouring cells rounding correctly. The
library computes that coefficient from ISO 9613-1 directly, so it is unaffected.
Committed example fiches, the conformance report, the API reference and the
llms files are regenerated.