The four printed tables, and the route the fiche was not taking (#722)
* Read the four tables, and the fiche's own reading of one of them
ISO 3382-1 prints four tables and a normative clause about what to write
down, and the library had none of it.
Table 1 says how far from omnidirectional a source may be before it starts
measuring itself rather than the hall, and 4.2.1 says how to find out:
gliding 30 degree arcs against a whole-turn energetic reference.
gliding_directivity_deviation runs that survey and source_directivity_limit
holds it to the six bands the table prints and to no others, because a
survey in the 63 Hz octave has no printed limit rather than the nearest one.
Table A.1 becomes data. Each of its seven rows carries the bands its single
number averages, and those are not the same set for every quantity: five
average two octaves and two average four, which is why A.5 prints G_m and
J_LFm side by side. It also carries the two exceptions a casual reading
loses. Only the late lateral level is energy averaged, through Equation
(A.17); only the early decay time's just-noticeable difference is relative;
and the late lateral level has none at all, printed as "Not known", which
perceptibly_different refuses to invent.
Table A.2's three rows lie exactly on a line in the logarithm of the seat
count, two positions per doubling, so a hall between them can be answered.
Not past them: A.4 asks for a minimum of between six and ten, and three rows
do not authorise thirteen positions for an arena.
Clause 9 is the normative part, and the fiche was not following it. 9.1
prints two routes to a single-number reverberation time, the two octave
bands or the six one-third-octave bands from 400 Hz to 1 250 Hz, and for a
one-third-octave analysis the fiche was averaging the two one-third-octave
bands called 500 Hz and 1 kHz, which is a sixth of the band the octave route
covers and neither printed route. It now takes the six and says so. 9.2's
fifteen lettered items are carried in order.
Two errata. The same limits are the maximum acceptable deviation in 4.2.1
and in Table 1's own caption, and "the minimum limits given in Table 1" in
A.4, which asks for extra measurements of a marginal source and so, read
literally, asks for them on the sources that need them least. And the
gliding average never says where its six points sit relative to the arc they
are reported against, which moves every deviation by up to half a window.
Five conformance rows, a guide in both editions, and a figure whose middle
panel shows one source clearing its 125 Hz limit and failing its 4 kHz one.
* Answer the first review of the reporting layer
The verdict on an accredited fiche took the octave route by omission, so a one-third-octave analysis was judged on the mean of the two bands called 500 Hz and 1 kHz while the box above it printed the six-band mean of 400 Hz to 1250 Hz that Clause 9.1 asks for. A profile that boxes 1.33 s has a two-band mean of 1.31 s, so a 1.32 s requirement came out PASS under a box that exceeded it. The default argument is gone with it.
Table A.1 prints the early lateral energy fraction as one row carrying two symbols, and only one of them was accepted, so the cosine-weighted variant the module itself computes could not be averaged or judged.
A NaN in the band axis made the missing-band check fall through and the lookup hand back the first band for every band asked for, which returns a real reading from the wrong place. A non-finite seat count did something similar.
The gliding-average errata entry said what it meant but invited a stronger reading: over a full turn the window phase relabels the same cyclic set of arcs, so it moves the bearing a deviation is reported against and not the deviation. The span reading and the combination law are the two silences that move the number.
* Name the aspect three of the seven Table A.1 rows share
* Say what fraction of the band the wrong two thirds actually are
Two one-third-octave bands are two thirds of an octave, and both printed routes cover two octaves, so the pair that a one-third-octave analysis must not average is a third of the band and not a sixth of it.
The unit goes in the name, where the caller writes the number (#752)
* The unit goes in the name, where the caller writes the number
A static pressure of 101 325 and a static pressure of 101.325 are both
legitimate values in this tree: the ISO 3740 family prints kilopascals,
IEC 61094-2 and ISO 15186-3 Annex A print pascals. Nothing separates them
by magnitude, because either reading is a real duty somewhere else, and
the result of the mix-up is still a float.
146 public parameters take their unit as a suffix. No value changes:
every function keeps the unit it already documented, so no oracle, no
printed figure and no conformance row moves.
temperature -> temperature_c across 39 callables, with temperature1_c,
temperature2_c, temperatures_c and temperature_celsius folded into the
same spelling; GasStream.inlet_temperature, which IEC 60534-8-3 states in
kelvin, becomes inlet_temperature_k. relative_humidity and the ISO 354
humidity both become relative_humidity_percent. The ambient pressure of
the propagation and aircraft chains becomes atmospheric_pressure_kpa, the
name air_density_astm and air_density_iso10534 already used; the ISO 3740
family takes static_pressure_kpa and the pascals of ISO 15186-3 Annex A,
ISO 9053-2 and ISO 7235 take static_pressure_pa, matching fluids.air.
Every other member of the family takes _pa.
Acoustic pressure keeps its bare name: a waveform is always in pascals
and a Signal carries its own calibration, so a suffix would restate the
type rather than resolve an ambiguity.
scripts/check_parameter_units.py holds the rule from here on. It walks
the imported package, not the source tree, because ReportMetadata is
published from the root and defined in a private module. Against main it
reports 154 offenders; here it reports none.
* Regenerate the API reference and the llms artifacts after the rewrap
* Pin the renamed argument in the four refusals nothing was reading
The same argument for the geometry that had two units on one name (#755)
* The same argument for the geometry that had two units on one name
#752 put the unit in the name where a pressure, a temperature or a
humidity could be read two ways. Measured over the imported API, four
geometric quantities were in the same state, and one of them was two
different dimensions.
diameter was metres in twenty public parameters and millimetres in one,
cnossos_rail.wheel_transfer, where CNOSSOS-EU Table G-3b tabulates 920,
840 and 680. angles was degrees in ten and radians in four while angle
was radians in eleven, so the plural and the singular of one word
disagreed. period was a lattice pitch in metres in the slit and
metadiffuser panels and a repetition time in seconds in the synchronous
average. gradient was a road slope in per cent in CNOSSOS-EU and a
vertical sound-speed gradient in s^-1 in refraction and sound speed.
They become diameter_m and diameter_mm, angle_rad, angles_rad and
angles_deg, period_m and period_s, road_slope_percent and gradient_per_s.
periods, a count of repetitions sitting beside a period that is a length,
becomes repetitions; the two places where it really means evaluation
periods keep the word and are in the guard's exemptions with the reason.
GaussianPulse.width is a half-width in seconds and the perfectly matched
layer of the same module measures its own width in cells. It says
half_width_s now.
No value changes: the conformance report is the same 995 checks with the
same numbers. The guard grows a second tuple, matched against the whole
name, and says in its own comment that the seventy-five compound names
are a second pass rather than an exemption: WestonRegimeBoundaries has
critical_angle in radians one screen above a function that takes it in
degrees. Against main the guard reports 71; here none.
* Re-render the three clips the renamed scenes drew
The unit goes in the name, where the caller writes the number (#752)
* The unit goes in the name, where the caller writes the number
A static pressure of 101 325 and a static pressure of 101.325 are both
legitimate values in this tree: the ISO 3740 family prints kilopascals,
IEC 61094-2 and ISO 15186-3 Annex A print pascals. Nothing separates them
by magnitude, because either reading is a real duty somewhere else, and
the result of the mix-up is still a float.
146 public parameters take their unit as a suffix. No value changes:
every function keeps the unit it already documented, so no oracle, no
printed figure and no conformance row moves.
temperature -> temperature_c across 39 callables, with temperature1_c,
temperature2_c, temperatures_c and temperature_celsius folded into the
same spelling; GasStream.inlet_temperature, which IEC 60534-8-3 states in
kelvin, becomes inlet_temperature_k. relative_humidity and the ISO 354
humidity both become relative_humidity_percent. The ambient pressure of
the propagation and aircraft chains becomes atmospheric_pressure_kpa, the
name air_density_astm and air_density_iso10534 already used; the ISO 3740
family takes static_pressure_kpa and the pascals of ISO 15186-3 Annex A,
ISO 9053-2 and ISO 7235 take static_pressure_pa, matching fluids.air.
Every other member of the family takes _pa.
Acoustic pressure keeps its bare name: a waveform is always in pascals
and a Signal carries its own calibration, so a suffix would restate the
type rather than resolve an ambiguity.
scripts/check_parameter_units.py holds the rule from here on. It walks
the imported package, not the source tree, because ReportMetadata is
published from the root and defined in a private module. Against main it
reports 154 offenders; here it reports none.
* Regenerate the API reference and the llms artifacts after the rewrap
* Pin the renamed argument in the four refusals nothing was reading
Every verdict reads its pass and fail flags, grades and classes from the values it holds (#949)
A result no longer stores a verdict beside the readings it came from. Sixty-two result classes used to keep the flag, grade or class their function had worked out (`passes`, `complies`, `qualified`, the `*_met` and `*_ok` flags, the advisories, the per-band classes of the IEC 61260-1, IEC 61672-1 and IEC 61043 verdicts, the ISO 9614-2 grade, the ISO/PAS 1996-3 category, the IEC TS 61400-11-2 block status and the rest), so a result built by hand or rewritten with `dataclasses.replace` could hold readings that fail and a flag that says they pass. Each of them is now a read-only property, read from the values the result keeps and the limit the standard prints, and so is any figure that only fed it, such as the rounded level of an RD 1367/2007 period or the acceptance region of a trend test.
Verdicts on a printed limit that read the decimal value, not its last bits (#914)
A quantity computed from decimal readings (a difference, a mean, a ratio, a spread) and judged against a limit a standard prints in decimal is now settled to nine decimal places before it meets that limit, and a half is rounded on the settled value, so 32,3 - 26,3 dB and 32,2 - 26,2 dB are the same 6 dB margin on every machine. One private helper does this for the whole library, and the six local copies of the same nine-decimal rule now go through it. The settled value only decides the verdict; every result keeps the value it computed. Two results change shape at a degenerate input: room.open_plan_metrics returns NaN for a distance when the STI does not fall with distance, and a hammer and floor that are critically damped in decimal get the critically damped pulse instead of NaN.
The unit goes in the name, where the caller writes the number (#752)
* The unit goes in the name, where the caller writes the number
A static pressure of 101 325 and a static pressure of 101.325 are both
legitimate values in this tree: the ISO 3740 family prints kilopascals,
IEC 61094-2 and ISO 15186-3 Annex A print pascals. Nothing separates them
by magnitude, because either reading is a real duty somewhere else, and
the result of the mix-up is still a float.
146 public parameters take their unit as a suffix. No value changes:
every function keeps the unit it already documented, so no oracle, no
printed figure and no conformance row moves.
temperature -> temperature_c across 39 callables, with temperature1_c,
temperature2_c, temperatures_c and temperature_celsius folded into the
same spelling; GasStream.inlet_temperature, which IEC 60534-8-3 states in
kelvin, becomes inlet_temperature_k. relative_humidity and the ISO 354
humidity both become relative_humidity_percent. The ambient pressure of
the propagation and aircraft chains becomes atmospheric_pressure_kpa, the
name air_density_astm and air_density_iso10534 already used; the ISO 3740
family takes static_pressure_kpa and the pascals of ISO 15186-3 Annex A,
ISO 9053-2 and ISO 7235 take static_pressure_pa, matching fluids.air.
Every other member of the family takes _pa.
Acoustic pressure keeps its bare name: a waveform is always in pascals
and a Signal carries its own calibration, so a suffix would restate the
type rather than resolve an ambiguity.
scripts/check_parameter_units.py holds the rule from here on. It walks
the imported package, not the source tree, because ReportMetadata is
published from the root and defined in a private module. Against main it
reports 154 offenders; here it reports none.
* Regenerate the API reference and the llms artifacts after the rewrap
* Pin the renamed argument in the four refusals nothing was reading
Every verdict reads its pass and fail flags, grades and classes from the values it holds (#949)
A result no longer stores a verdict beside the readings it came from. Sixty-two result classes used to keep the flag, grade or class their function had worked out (`passes`, `complies`, `qualified`, the `*_met` and `*_ok` flags, the advisories, the per-band classes of the IEC 61260-1, IEC 61672-1 and IEC 61043 verdicts, the ISO 9614-2 grade, the ISO/PAS 1996-3 category, the IEC TS 61400-11-2 block status and the rest), so a result built by hand or rewritten with `dataclasses.replace` could hold readings that fail and a flag that says they pass. Each of them is now a read-only property, read from the values the result keeps and the limit the standard prints, and so is any figure that only fed it, such as the rounded level of an RD 1367/2007 period or the acceptance region of a trend test.
The unit goes in the name, where the caller writes the number (#752)
* The unit goes in the name, where the caller writes the number
A static pressure of 101 325 and a static pressure of 101.325 are both
legitimate values in this tree: the ISO 3740 family prints kilopascals,
IEC 61094-2 and ISO 15186-3 Annex A print pascals. Nothing separates them
by magnitude, because either reading is a real duty somewhere else, and
the result of the mix-up is still a float.
146 public parameters take their unit as a suffix. No value changes:
every function keeps the unit it already documented, so no oracle, no
printed figure and no conformance row moves.
temperature -> temperature_c across 39 callables, with temperature1_c,
temperature2_c, temperatures_c and temperature_celsius folded into the
same spelling; GasStream.inlet_temperature, which IEC 60534-8-3 states in
kelvin, becomes inlet_temperature_k. relative_humidity and the ISO 354
humidity both become relative_humidity_percent. The ambient pressure of
the propagation and aircraft chains becomes atmospheric_pressure_kpa, the
name air_density_astm and air_density_iso10534 already used; the ISO 3740
family takes static_pressure_kpa and the pascals of ISO 15186-3 Annex A,
ISO 9053-2 and ISO 7235 take static_pressure_pa, matching fluids.air.
Every other member of the family takes _pa.
Acoustic pressure keeps its bare name: a waveform is always in pascals
and a Signal carries its own calibration, so a suffix would restate the
type rather than resolve an ambiguity.
scripts/check_parameter_units.py holds the rule from here on. It walks
the imported package, not the source tree, because ReportMetadata is
published from the root and defined in a private module. Against main it
reports 154 offenders; here it reports none.
* Regenerate the API reference and the llms artifacts after the rewrap
* Pin the renamed argument in the four refusals nothing was reading
Say the types in half the test suite (#628)
* Say the types in half the test suite
The library, its scripts and its gates are fully annotated; the suite
was the last corner where a parameter arrived nameless. This half
covers the building, materials, room, emission and psychoacoustics
trees: pytest's own plumbing typed with pytest's own types, every
parametrize argument typed from the values really in its list, and
every fixture and helper from what its body builds, read against the
library signature it calls rather than guessed.
Annotations cannot change what a test does, and the full suite agrees:
the same 9402 tests pass before and after.
* Let the language test say what it reads off a result
The factory was typed as returning object, which claims the test never
looks inside, and calling plot is the whole test. A three-line protocol
says exactly as much as the test needs, no more: the shared plot seam
with its language keyword. A union of the six concrete types would have
repeated the parametrize list.
Six places where the clause and the code had parted, from a microphone standing under its own clearance to an area that is not one number (ISO 10847, ISO 11820, ISO 11821, EN 16487) (#785)
* Six places where the clause and the code had parted, from a microphone standing under its own clearance to an area that is not one number (ISO 10847, ISO 11820, ISO 11821, EN 16487)
The reference microphone of ISO 10847 could stand lower than 7.2.2 allows.
The clause puts it at least 1,5 m above the top edge of the barrier with
"shall", and its NOTE lets a close source raise it until it looks 10 degrees
over the top; the height returned was the NOTE's alone whenever the source was
nearer than 15 m, which for a 3 m barrier 5 m away is 4,34 m against the 4,5 m
the clause asks for, and past 80 degrees a negative height. It is the higher of
the two now, and where no height reaches the 10 degrees the clearance holds and
a warning says why. The test and the conformance row had both pinned the short
geometry as correct.
ISO 11820 caps its energy subtraction at 3 dB, and Table 1 prints what that
3 dB is: the correction at a 3 dB margin, which the subtraction writes
unrounded as 3,0206 dB. The cap is judged on the margin of the two energy means
now, so the two routes the clause offers agree at the boundary they share and a
printed 3,0 dB pair is no longer decided by floating point. The window that
keeps such a pair out of the cap is the one the module declares and nothing
wider: the comparison names a relative tolerance of zero, as every other
closeness test in the package does, so the constant sets the tolerance it
documents instead of three times it. ISO 11821 7.4 c) reports the attenuation
of a screen to the nearest whole decibel, which the result now gives with
rounded() and rounded_a_weighted() as the barrier, enclosure and cabin results
already did.
The two loss functions of ISO 11820 took their areas as single numbers, where
the area of a diffuse room is a quarter of its absorption and moves with the
reverberation time band by band. They take each area and the field correction
as one value or one per band, and the two fields of the result are arrays of
one value per band even when single values went in. The thesis oracle that had
to be driven one band at a time is one call per table.
check_ceiling_specimen judged three of the limits clause 4 of EN 16487 prints
and published the rest as constants nothing applied. It judges the support
units of 4.1.1.2.3.6 and, given one value per measurement, the 50 % of 4.2.2;
the verdict carries both, and a type E depth other than 200 mm passes with a
warning that no longer calls the arrangement outside the test code. And
room_to_room_transmission gains receiver_distance_m, the direct field the
partition radiates into the receiving room, from Equations (7-71) and (7-72) of
Barron (2003), whose Example 7-6 a new conformance row holds; Norton's Equation
(4.101) is its far limit and stays the default.
The unit guard then read the new humidity_ok as a humidity without its unit: a
parameter typed bool holds a verdict and no number of the quantity it names, so
it is outside the rule. The printed tables the tests and the conformance rows
of these standards both read were transcribed twice, once on each side; they
are transcribed once now, in tests/reference_data, with the document, the folio
and the PDF page of each, and the report regenerates value for value.
The guides say all of it in both languages, with the mirrors, the curated API
table and the errata entry for the 6,2 dB of ISO 14257 Equation (4), which
stays as printed and is now stated where it is spent.
* Two receiver-correction rows a single band could satisfy, and a denominator with two spellings (ISO 10847, ISO 11820)
Both ISO 10847 receiver-correction rows read the largest shift across the three bands, so a correction that reached one band and left the other two alone would still have printed the 6 dB of the pressure doubling and passed. They now read the largest absolute departure from 6 dB, which is a statement about every band, and the 6 dB is written into the expected column as prose so the row still says what it is checking.
The Ver and Beranek absorption row said it was checking a quarter of the printed Sabine absorption area. It multiplies the quarter back up and compares the full printed 10,7 m2, so the row described a different quantity from the one it evaluates.
`receiving_absorption` is the denominator of the reverberant term, and the two books write that term over two different quantities: Norton over S2 alpha2 and Barron over the room constant R2. The module prose, the function docstring and the guide all say so, but the parameter line said only the first, and the parameter tables of the reference pages print that line on its own, away from the paragraph that explains it. It now names both, with the link to `room_constant` beside the one to `equivalent_absorption_area`.
The normalisation cell of the API table printed `spectrum_distribution_value(values, PINK_NOISE_WEIGHTS_DB values)`, two arguments juxtaposed with no accessor between them. The second argument is a sequence of the six weights, so it is `list(PINK_NOISE_WEIGHTS_DB.values())`.
* The background of Annex B case A goes with the label that carries it, not with the coordinates beside it (ISO 11690-3)
Table B.5 prints the 50 dB of background against the workstation it calls W1, and the entry already registered that the labels of that table are the half it gets right: Figure B.1 puts W1 beside machine M2, and that is where the levels of Table B.6 come back. The background was being heard in the far corner instead, which is where the other label belongs.
It is worth 0,004 dB, both readings round to the tenth Table B.6 prints, and no verdict moves. What changes is the second decimal of the two recomputed levels the entry quotes, 82,09 dB and 80,27 dB becoming 82,10 dB and 80,26 dB, and the entry now says where the background sits and what the other reading would cost.
The two counts in the Annex B check labels were written out by hand while the cells they describe were counted in the code beside them, so a row added or removed would have left the prose saying six and twelve. They come from the cells now.
* The Eq. (4) offset row judges every claim it prints, not only the first (ISO 14257)
The row publishes three findings about the fourteen Annex C values: the sum of the Table 1 weights puts none of them outside their rounding, the printed 6,2 dB puts nine outside, and every departure the printed constant gives is high. Its verdict only counted the first. The other two were computed and printed beside it and never judged, so the row would have gone on passing the day the printed constant agreed with the annex, while still saying it does not.
All three are judged now, with a fourth the description also claims, that none of the high cells reaches a second unit of the tenth. The nine is recorded as the finding it is rather than derived, and the fourteen comes from the cells. Made to fail both ways before committing: with the recorded count set as if the constant agreed with the annex, and with the printed departures pushed low.
In the release note, "both use one the angle governs now" becomes "both now use the height the angle governs".
* The two Annex B distances in the ISO 11690-3 entry are the ones the coordinates give
The entry said the position Table B.5 calls W2 is one metre from machine M2 and the one it calls W1 eleven metres from the nearer machine. From the printed coordinates they are 1,17 m and 11,42 m: W2 stands a metre away in plan but 0,6 m higher than the machine. Both now read 1,2 m and 11,4 m, in English and in Spanish. The argument does not change, since the near position is still the quieter one the table claims.
* The generated artefacts are regenerated on top of the measurement diagrams
Moving the layer onto main kept llms-full.txt, the materials absorbers bundle and the conformance artefact as this layer had written them, which dropped what the diagram stack added to the suspended ceilings guide and the ISO 4866 re-citation. Regenerated from the tree, they carry both.