Room-noise rating reports via .report() (ANSI/ASA S12.2-2019) (#330)
* Room-noise rating reports via .report() (ANSI/ASA S12.2-2019)
Add a one-page PDF room-noise assessment fiche to both room-noise rating
result types of ANSI/ASA S12.2-2019:
- NCResult.report(): the Noise Criteria rating by the tangency method
(Table 1). The box states NC-nn with the governing octave band.
- RCResult.report(): the Room Criteria Mark II rating (Annex D). The box
states RC-nn(tag) with the mid-frequency average LMF and the
neutral/rumble/hiss spectral quality.
Both fiches share one renderer built on the accredited-report engine: a
standard-basis line, an optional metadata header, the measured octave-band
levels beside the measured spectrum plotted against the NC/RC curve family
(the result's own plot), the boxed rating and a footer disclaimer. A target
rating on the metadata requirement adds a PASS/FAIL verdict, where a lower
rating passes. With verbose=True the table gains the per-band NC contour
value read by the tangency method, or the reference RC Mark II curve and the
measured deviation from it. English and Spanish both render.
Register one example per fiche in the report generator (an NC-40 office
spectrum governed by the 250 Hz band and an RC-35(R) rumble spectrum, both
built from the tabulated curves so the ratings are exact), document the
method on the room-noise guide, and cover the reports with structural,
number-presence, one-page and EN/ES tests. Regenerate the API reference and
the conformance report.
* Factor out the shared room-noise table builder
Extract the common frequency/level columns and the caption-plus-table
assembly shared by the NC and RC left cells into helpers, so the two
renderers only add their own evaluation columns.
* Drop the unused table-language parameter and hoist the raise setup
_value_table never used its language argument (its cells arrive already
formatted), so remove it and its call site. Build the result before the
engine and language rejection assertions so only the reporting call sits
inside pytest.raises.
Room-noise rating reports via .report() (ANSI/ASA S12.2-2019) (#330)
* Room-noise rating reports via .report() (ANSI/ASA S12.2-2019)
Add a one-page PDF room-noise assessment fiche to both room-noise rating
result types of ANSI/ASA S12.2-2019:
- NCResult.report(): the Noise Criteria rating by the tangency method
(Table 1). The box states NC-nn with the governing octave band.
- RCResult.report(): the Room Criteria Mark II rating (Annex D). The box
states RC-nn(tag) with the mid-frequency average LMF and the
neutral/rumble/hiss spectral quality.
Both fiches share one renderer built on the accredited-report engine: a
standard-basis line, an optional metadata header, the measured octave-band
levels beside the measured spectrum plotted against the NC/RC curve family
(the result's own plot), the boxed rating and a footer disclaimer. A target
rating on the metadata requirement adds a PASS/FAIL verdict, where a lower
rating passes. With verbose=True the table gains the per-band NC contour
value read by the tangency method, or the reference RC Mark II curve and the
measured deviation from it. English and Spanish both render.
Register one example per fiche in the report generator (an NC-40 office
spectrum governed by the 250 Hz band and an RC-35(R) rumble spectrum, both
built from the tabulated curves so the ratings are exact), document the
method on the room-noise guide, and cover the reports with structural,
number-presence, one-page and EN/ES tests. Regenerate the API reference and
the conformance report.
* Factor out the shared room-noise table builder
Extract the common frequency/level columns and the caption-plus-table
assembly shared by the NC and RC left cells into helpers, so the two
renderers only add their own evaluation columns.
* Drop the unused table-language parameter and hoist the raise setup
_value_table never used its language argument (its cells arrive already
formatted), so remove it and its call site. Build the result before the
engine and language rejection assertions so only the reporting call sits
inside pytest.raises.
Room-noise rating reports via .report() (ANSI/ASA S12.2-2019) (#330)
* Room-noise rating reports via .report() (ANSI/ASA S12.2-2019)
Add a one-page PDF room-noise assessment fiche to both room-noise rating
result types of ANSI/ASA S12.2-2019:
- NCResult.report(): the Noise Criteria rating by the tangency method
(Table 1). The box states NC-nn with the governing octave band.
- RCResult.report(): the Room Criteria Mark II rating (Annex D). The box
states RC-nn(tag) with the mid-frequency average LMF and the
neutral/rumble/hiss spectral quality.
Both fiches share one renderer built on the accredited-report engine: a
standard-basis line, an optional metadata header, the measured octave-band
levels beside the measured spectrum plotted against the NC/RC curve family
(the result's own plot), the boxed rating and a footer disclaimer. A target
rating on the metadata requirement adds a PASS/FAIL verdict, where a lower
rating passes. With verbose=True the table gains the per-band NC contour
value read by the tangency method, or the reference RC Mark II curve and the
measured deviation from it. English and Spanish both render.
Register one example per fiche in the report generator (an NC-40 office
spectrum governed by the 250 Hz band and an RC-35(R) rumble spectrum, both
built from the tabulated curves so the ratings are exact), document the
method on the room-noise guide, and cover the reports with structural,
number-presence, one-page and EN/ES tests. Regenerate the API reference and
the conformance report.
* Factor out the shared room-noise table builder
Extract the common frequency/level columns and the caption-plus-table
assembly shared by the NC and RC left cells into helpers, so the two
renderers only add their own evaluation columns.
* Drop the unused table-language parameter and hoist the raise setup
_value_table never used its language argument (its cells arrive already
formatted), so remove it and its call site. Build the result before the
engine and language rejection assertions so only the reporting call sits
inside pytest.raises.
Room-noise rating reports via .report() (ANSI/ASA S12.2-2019) (#330)
* Room-noise rating reports via .report() (ANSI/ASA S12.2-2019)
Add a one-page PDF room-noise assessment fiche to both room-noise rating
result types of ANSI/ASA S12.2-2019:
- NCResult.report(): the Noise Criteria rating by the tangency method
(Table 1). The box states NC-nn with the governing octave band.
- RCResult.report(): the Room Criteria Mark II rating (Annex D). The box
states RC-nn(tag) with the mid-frequency average LMF and the
neutral/rumble/hiss spectral quality.
Both fiches share one renderer built on the accredited-report engine: a
standard-basis line, an optional metadata header, the measured octave-band
levels beside the measured spectrum plotted against the NC/RC curve family
(the result's own plot), the boxed rating and a footer disclaimer. A target
rating on the metadata requirement adds a PASS/FAIL verdict, where a lower
rating passes. With verbose=True the table gains the per-band NC contour
value read by the tangency method, or the reference RC Mark II curve and the
measured deviation from it. English and Spanish both render.
Register one example per fiche in the report generator (an NC-40 office
spectrum governed by the 250 Hz band and an RC-35(R) rumble spectrum, both
built from the tabulated curves so the ratings are exact), document the
method on the room-noise guide, and cover the reports with structural,
number-presence, one-page and EN/ES tests. Regenerate the API reference and
the conformance report.
* Factor out the shared room-noise table builder
Extract the common frequency/level columns and the caption-plus-table
assembly shared by the NC and RC left cells into helpers, so the two
renderers only add their own evaluation columns.
* Drop the unused table-language parameter and hoist the raise setup
_value_table never used its language argument (its cells arrive already
formatted), so remove it and its call site. Build the result before the
engine and language rejection assertions so only the reporting call sits
inside pytest.raises.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Structure-borne sound power and installed prediction reports via .report() (#327)
* Structure-borne sound power characterization and installed prediction reports via .report()
Add one-page PDF .report() fiches to the two structure-borne building
result types, closing the EN 15657 -> EN 12354-5 chain from source
characterization to installed prediction.
StructureBornePowerResult.report() renders an EN 15657:2018 reception-plate
structure-borne sound power characterization: the per-band spatial mean plate
velocity level Lv and the injected power level L_Ws (Formula 14), the L_Ws(f)
spectrum, and the boxed band-summed total L_Ws (dB re 1 pW) with the plate
mass per area m and area S. verbose=True adds the plate loss factor eta
column; the basis strip states Formula 14 and the conversion to the
plate-independent source quantities required before EN 12354-5.
InstalledSourceResult.report() renders an EN 12354-5:2009 installed
structure-borne sound prediction, clearly labelled a prediction and not a
measurement: the per-band installed power level L_Ws,inst, each transmission
path's normalised SPL L_n,s,ij and the combined total L_n,s, the per-path and
total L_n,s(f) spectra, and the boxed band-summed total L_n,s. verbose=True
adds one column per transmission path; the basis strip states Formulae 18a/17
and the prediction disclaimer.
Both fiches reuse the shared sound-power report engine (per-band table,
spectrum, boxed result and flow assembly), extended with a caller-supplied
verdict so the structure-borne quantity symbols are stated consistently, and
render in English and Spanish. Register one example per fiche, add structural
and number-presence tests, document the reports in the guides, and record the
additions in the changelog.
* Address review: per-path column [dB] units and Spanish accent
Add the [dB] unit to the installed-prediction table's per-path column headers
so they match the installed-power and total columns, and correct the accent in
the Spanish structure-borne power guide (acelerometro -> acelerometro with the
acute accent).
Structure-borne sound power and installed prediction reports via .report() (#327)
* Structure-borne sound power characterization and installed prediction reports via .report()
Add one-page PDF .report() fiches to the two structure-borne building
result types, closing the EN 15657 -> EN 12354-5 chain from source
characterization to installed prediction.
StructureBornePowerResult.report() renders an EN 15657:2018 reception-plate
structure-borne sound power characterization: the per-band spatial mean plate
velocity level Lv and the injected power level L_Ws (Formula 14), the L_Ws(f)
spectrum, and the boxed band-summed total L_Ws (dB re 1 pW) with the plate
mass per area m and area S. verbose=True adds the plate loss factor eta
column; the basis strip states Formula 14 and the conversion to the
plate-independent source quantities required before EN 12354-5.
InstalledSourceResult.report() renders an EN 12354-5:2009 installed
structure-borne sound prediction, clearly labelled a prediction and not a
measurement: the per-band installed power level L_Ws,inst, each transmission
path's normalised SPL L_n,s,ij and the combined total L_n,s, the per-path and
total L_n,s(f) spectra, and the boxed band-summed total L_n,s. verbose=True
adds one column per transmission path; the basis strip states Formulae 18a/17
and the prediction disclaimer.
Both fiches reuse the shared sound-power report engine (per-band table,
spectrum, boxed result and flow assembly), extended with a caller-supplied
verdict so the structure-borne quantity symbols are stated consistently, and
render in English and Spanish. Register one example per fiche, add structural
and number-presence tests, document the reports in the guides, and record the
additions in the changelog.
* Address review: per-path column [dB] units and Spanish accent
Add the [dB] unit to the installed-prediction table's per-path column headers
so they match the installed-power and total columns, and correct the accent in
the Spanish structure-borne power guide (acelerometro -> acelerometro with the
acute accent).
Structure-borne sound power and installed prediction reports via .report() (#327)
* Structure-borne sound power characterization and installed prediction reports via .report()
Add one-page PDF .report() fiches to the two structure-borne building
result types, closing the EN 15657 -> EN 12354-5 chain from source
characterization to installed prediction.
StructureBornePowerResult.report() renders an EN 15657:2018 reception-plate
structure-borne sound power characterization: the per-band spatial mean plate
velocity level Lv and the injected power level L_Ws (Formula 14), the L_Ws(f)
spectrum, and the boxed band-summed total L_Ws (dB re 1 pW) with the plate
mass per area m and area S. verbose=True adds the plate loss factor eta
column; the basis strip states Formula 14 and the conversion to the
plate-independent source quantities required before EN 12354-5.
InstalledSourceResult.report() renders an EN 12354-5:2009 installed
structure-borne sound prediction, clearly labelled a prediction and not a
measurement: the per-band installed power level L_Ws,inst, each transmission
path's normalised SPL L_n,s,ij and the combined total L_n,s, the per-path and
total L_n,s(f) spectra, and the boxed band-summed total L_n,s. verbose=True
adds one column per transmission path; the basis strip states Formulae 18a/17
and the prediction disclaimer.
Both fiches reuse the shared sound-power report engine (per-band table,
spectrum, boxed result and flow assembly), extended with a caller-supplied
verdict so the structure-borne quantity symbols are stated consistently, and
render in English and Spanish. Register one example per fiche, add structural
and number-presence tests, document the reports in the guides, and record the
additions in the changelog.
* Address review: per-path column [dB] units and Spanish accent
Add the [dB] unit to the installed-prediction table's per-path column headers
so they match the installed-power and total columns, and correct the accent in
the Spanish structure-borne power guide (acelerometro -> acelerometro with the
acute accent).
Structure-borne sound power and installed prediction reports via .report() (#327)
* Structure-borne sound power characterization and installed prediction reports via .report()
Add one-page PDF .report() fiches to the two structure-borne building
result types, closing the EN 15657 -> EN 12354-5 chain from source
characterization to installed prediction.
StructureBornePowerResult.report() renders an EN 15657:2018 reception-plate
structure-borne sound power characterization: the per-band spatial mean plate
velocity level Lv and the injected power level L_Ws (Formula 14), the L_Ws(f)
spectrum, and the boxed band-summed total L_Ws (dB re 1 pW) with the plate
mass per area m and area S. verbose=True adds the plate loss factor eta
column; the basis strip states Formula 14 and the conversion to the
plate-independent source quantities required before EN 12354-5.
InstalledSourceResult.report() renders an EN 12354-5:2009 installed
structure-borne sound prediction, clearly labelled a prediction and not a
measurement: the per-band installed power level L_Ws,inst, each transmission
path's normalised SPL L_n,s,ij and the combined total L_n,s, the per-path and
total L_n,s(f) spectra, and the boxed band-summed total L_n,s. verbose=True
adds one column per transmission path; the basis strip states Formulae 18a/17
and the prediction disclaimer.
Both fiches reuse the shared sound-power report engine (per-band table,
spectrum, boxed result and flow assembly), extended with a caller-supplied
verdict so the structure-borne quantity symbols are stated consistently, and
render in English and Spanish. Register one example per fiche, add structural
and number-presence tests, document the reports in the guides, and record the
additions in the changelog.
* Address review: per-path column [dB] units and Spanish accent
Add the [dB] unit to the installed-prediction table's per-path column headers
so they match the installed-power and total columns, and correct the accent in
the Spanish structure-borne power guide (acelerometro -> acelerometro with the
acute accent).
Add reverberation-time report fiches via .report() (#336)
Add a one-page PDF .report() to the two reverberation result types.
ReverberationModelResult.report() renders a design-stage prediction of the
reverberation time by the five classical statistical-acoustics models (Sabine,
Eyring, Millington-Sette, Fitzroy and Arau-Puchades): a per-band table with one
reverberation-time column per model beside the model comparison plot, and a
boxed mid-frequency reverberation time from Arau-Puchades with the per-model
spread alongside. It is labelled a prediction, not a measurement: the five
models bracket the reverberation time likely to occur, so no PASS/FAIL verdict
is emitted; a target reverberation time is printed as a reference line only.
ReverberationResult.report() renders an enclosed-space characterisation
(EN 12354-6:2003): a per-band table of the equivalent sound absorption area A
and the reverberation time T beside the reverberation-time plot, the room
volume and object fraction in the header, and a boxed mid-frequency
reverberation time with the mid-frequency absorption area alongside. A target
reverberation time is likewise printed as a reference line without a verdict,
since a room reverberation time is a target range rather than a strictly
higher/lower-is-better quantity.
Both renderers live in a shared _report/reverberation.py module (shared
mid-frequency descriptor, time formatting, octave-band table and header grid
helpers). Add the English and Spanish fixed strings, one committed example
fiche per result under .github/reports/, structural and value-presence tests
in English and Spanish, and the guide sections in both languages. Regenerate
the API reference.
Add reverberation-time report fiches via .report() (#336)
Add a one-page PDF .report() to the two reverberation result types.
ReverberationModelResult.report() renders a design-stage prediction of the
reverberation time by the five classical statistical-acoustics models (Sabine,
Eyring, Millington-Sette, Fitzroy and Arau-Puchades): a per-band table with one
reverberation-time column per model beside the model comparison plot, and a
boxed mid-frequency reverberation time from Arau-Puchades with the per-model
spread alongside. It is labelled a prediction, not a measurement: the five
models bracket the reverberation time likely to occur, so no PASS/FAIL verdict
is emitted; a target reverberation time is printed as a reference line only.
ReverberationResult.report() renders an enclosed-space characterisation
(EN 12354-6:2003): a per-band table of the equivalent sound absorption area A
and the reverberation time T beside the reverberation-time plot, the room
volume and object fraction in the header, and a boxed mid-frequency
reverberation time with the mid-frequency absorption area alongside. A target
reverberation time is likewise printed as a reference line without a verdict,
since a room reverberation time is a target range rather than a strictly
higher/lower-is-better quantity.
Both renderers live in a shared _report/reverberation.py module (shared
mid-frequency descriptor, time formatting, octave-band table and header grid
helpers). Add the English and Spanish fixed strings, one committed example
fiche per result under .github/reports/, structural and value-presence tests
in English and Spanish, and the guide sections in both languages. Regenerate
the API reference.
Noise-control performance reports via .report() (#331)
* Add noise-control performance reports via .report()
Add a one-page PDF .report() fiche to the three noise_control result
types, each laid out with a per-band table beside the result's own plot,
a boxed single-number performance figure and an optional PASS/FAIL
verdict:
- EnclosureResult: machine-enclosure insertion loss (Bies, Hansen &
Howard, section 7.4.2). The table lists the supplied panel transmission
loss R, the interior build-up correction C and the net insertion loss
IL = R - C; the boxed figure is the mean insertion loss with the
external and internal surface areas. verbose=True adds the interior
room constant column. A declared minimum passes when the mean meets it.
- ReactiveSilencerResult: reactive-silencer transmission loss (Munjal
Eq. (3.27); Bies sections 8.8-8.9). The table lists the transmission
loss TL and, when end impedances were given, the insertion loss IL; the
boxed figure is the mean transmission loss with the peak and the device
kind. A declared minimum passes when the mean meets it.
- HvacSpectrumResult: HVAC duct-noise spectrum (Bies Chapter 8; VDI
2081-1). A regenerated-noise spectrum boxes the A-weighted sound power
level with the overall total (lower is better); an attenuation spectrum
boxes the mean attenuation (more is better). verbose=True adds the
A-weighting correction and A-weighted band-level columns.
The three renderers share a two-panel skeleton in
_report/_noise_control_fiche.py and reuse the sound-power table builder,
band labels and header grid. Each accepts an optional metadata header,
states its method basis and renders in English or Spanish.
Register one committed example per fiche under .github/reports/, add
structural and clean-room number-presence tests (EN and ES), and update
the CHANGELOG and the regenerated API reference.
* Address SonarCloud findings on the noise-control renderers
Reduce render_noise_control_fiche below the parameter-count threshold by
fixing the two-panel split widths internally (the three renderers never
overrode them), and lift the HVAC verdict symbol/unit selection out of a
nested conditional into an explicit if/elif/else. No change to rendered
output; the committed example fiches are unaffected.
* Round the requirement to display precision and fit the verbose table
Compare the declared requirement at the same one-decimal precision as the
measured value in the noise-control verdict, so the printed comparison can
never contradict the verdict at the boundary. Also trim the verbose
enclosure table columns to sum to the 64 mm left panel width.
Noise-control performance reports via .report() (#331)
* Add noise-control performance reports via .report()
Add a one-page PDF .report() fiche to the three noise_control result
types, each laid out with a per-band table beside the result's own plot,
a boxed single-number performance figure and an optional PASS/FAIL
verdict:
- EnclosureResult: machine-enclosure insertion loss (Bies, Hansen &
Howard, section 7.4.2). The table lists the supplied panel transmission
loss R, the interior build-up correction C and the net insertion loss
IL = R - C; the boxed figure is the mean insertion loss with the
external and internal surface areas. verbose=True adds the interior
room constant column. A declared minimum passes when the mean meets it.
- ReactiveSilencerResult: reactive-silencer transmission loss (Munjal
Eq. (3.27); Bies sections 8.8-8.9). The table lists the transmission
loss TL and, when end impedances were given, the insertion loss IL; the
boxed figure is the mean transmission loss with the peak and the device
kind. A declared minimum passes when the mean meets it.
- HvacSpectrumResult: HVAC duct-noise spectrum (Bies Chapter 8; VDI
2081-1). A regenerated-noise spectrum boxes the A-weighted sound power
level with the overall total (lower is better); an attenuation spectrum
boxes the mean attenuation (more is better). verbose=True adds the
A-weighting correction and A-weighted band-level columns.
The three renderers share a two-panel skeleton in
_report/_noise_control_fiche.py and reuse the sound-power table builder,
band labels and header grid. Each accepts an optional metadata header,
states its method basis and renders in English or Spanish.
Register one committed example per fiche under .github/reports/, add
structural and clean-room number-presence tests (EN and ES), and update
the CHANGELOG and the regenerated API reference.
* Address SonarCloud findings on the noise-control renderers
Reduce render_noise_control_fiche below the parameter-count threshold by
fixing the two-panel split widths internally (the three renderers never
overrode them), and lift the HVAC verdict symbol/unit selection out of a
nested conditional into an explicit if/elif/else. No change to rendered
output; the committed example fiches are unaffected.
* Round the requirement to display precision and fit the verbose table
Compare the declared requirement at the same one-decimal precision as the
measured value in the noise-control verdict, so the printed comparison can
never contradict the verdict at the boundary. Also trim the verbose
enclosure table columns to sum to the 64 mm left panel width.
Noise-control performance reports via .report() (#331)
* Add noise-control performance reports via .report()
Add a one-page PDF .report() fiche to the three noise_control result
types, each laid out with a per-band table beside the result's own plot,
a boxed single-number performance figure and an optional PASS/FAIL
verdict:
- EnclosureResult: machine-enclosure insertion loss (Bies, Hansen &
Howard, section 7.4.2). The table lists the supplied panel transmission
loss R, the interior build-up correction C and the net insertion loss
IL = R - C; the boxed figure is the mean insertion loss with the
external and internal surface areas. verbose=True adds the interior
room constant column. A declared minimum passes when the mean meets it.
- ReactiveSilencerResult: reactive-silencer transmission loss (Munjal
Eq. (3.27); Bies sections 8.8-8.9). The table lists the transmission
loss TL and, when end impedances were given, the insertion loss IL; the
boxed figure is the mean transmission loss with the peak and the device
kind. A declared minimum passes when the mean meets it.
- HvacSpectrumResult: HVAC duct-noise spectrum (Bies Chapter 8; VDI
2081-1). A regenerated-noise spectrum boxes the A-weighted sound power
level with the overall total (lower is better); an attenuation spectrum
boxes the mean attenuation (more is better). verbose=True adds the
A-weighting correction and A-weighted band-level columns.
The three renderers share a two-panel skeleton in
_report/_noise_control_fiche.py and reuse the sound-power table builder,
band labels and header grid. Each accepts an optional metadata header,
states its method basis and renders in English or Spanish.
Register one committed example per fiche under .github/reports/, add
structural and clean-room number-presence tests (EN and ES), and update
the CHANGELOG and the regenerated API reference.
* Address SonarCloud findings on the noise-control renderers
Reduce render_noise_control_fiche below the parameter-count threshold by
fixing the two-panel split widths internally (the three renderers never
overrode them), and lift the HVAC verdict symbol/unit selection out of a
nested conditional into an explicit if/elif/else. No change to rendered
output; the committed example fiches are unaffected.
* Round the requirement to display precision and fit the verbose table
Compare the declared requirement at the same one-decimal precision as the
measured value in the noise-control verdict, so the printed comparison can
never contradict the verdict at the boundary. Also trim the verbose
enclosure table columns to sum to the 64 mm left panel width.
Noise-control performance reports via .report() (#331)
* Add noise-control performance reports via .report()
Add a one-page PDF .report() fiche to the three noise_control result
types, each laid out with a per-band table beside the result's own plot,
a boxed single-number performance figure and an optional PASS/FAIL
verdict:
- EnclosureResult: machine-enclosure insertion loss (Bies, Hansen &
Howard, section 7.4.2). The table lists the supplied panel transmission
loss R, the interior build-up correction C and the net insertion loss
IL = R - C; the boxed figure is the mean insertion loss with the
external and internal surface areas. verbose=True adds the interior
room constant column. A declared minimum passes when the mean meets it.
- ReactiveSilencerResult: reactive-silencer transmission loss (Munjal
Eq. (3.27); Bies sections 8.8-8.9). The table lists the transmission
loss TL and, when end impedances were given, the insertion loss IL; the
boxed figure is the mean transmission loss with the peak and the device
kind. A declared minimum passes when the mean meets it.
- HvacSpectrumResult: HVAC duct-noise spectrum (Bies Chapter 8; VDI
2081-1). A regenerated-noise spectrum boxes the A-weighted sound power
level with the overall total (lower is better); an attenuation spectrum
boxes the mean attenuation (more is better). verbose=True adds the
A-weighting correction and A-weighted band-level columns.
The three renderers share a two-panel skeleton in
_report/_noise_control_fiche.py and reuse the sound-power table builder,
band labels and header grid. Each accepts an optional metadata header,
states its method basis and renders in English or Spanish.
Register one committed example per fiche under .github/reports/, add
structural and clean-room number-presence tests (EN and ES), and update
the CHANGELOG and the regenerated API reference.
* Address SonarCloud findings on the noise-control renderers
Reduce render_noise_control_fiche below the parameter-count threshold by
fixing the two-panel split widths internally (the three renderers never
overrode them), and lift the HVAC verdict symbol/unit selection out of a
nested conditional into an explicit if/elif/else. No change to rendered
output; the committed example fiches are unaffected.
* Round the requirement to display precision and fit the verbose table
Compare the declared requirement at the same one-decimal precision as the
measured value in the noise-control verdict, so the printed comparison can
never contradict the verdict at the boundary. Also trim the verbose
enclosure table columns to sum to the 64 mm left panel width.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Add wind-turbine tonal audibility report via .report() (#337)
* Add wind-turbine tonal audibility report via .report()
Add WindTurbineTonalityResult.report() rendering a one-page PDF
wind-turbine tonality-assessment fiche (IEC 61400-11:2012+A1:2018,
subclauses 9.5.2-9.5.5).
The sheet carries a standard-basis line, an optional metadata header
(source/situation, client, measurement position, instrumentation, date),
a two-panel body with the critical-band and masking analysis in a metrics
table (tone frequency, critical bandwidth, tone level L_pt, masking-noise
level L_pn, tonality dL_tn, audibility criterion L_a and tonal audibility
dL_a) beside the narrowband-spectrum plot with the critical band, masking
level and tone marked, and a boxed decisive tonal audibility dL_a with the
tone frequency and the audibility decision (a tone is audible when dL_a
exceeds 0 dB). A maximum acceptable tonal audibility supplied via the
metadata requirement adds a PASS/FAIL verdict (a lower audibility is
better). English and Spanish both render.
Register the example fiche, add structural and i18n tests, and regenerate
the committed example PDF, WebP preview and API reference.
* Base the audibility decision on the displayed rounded tonal audibility
The boxed result, verdict and decision text all commit to the tonal
audibility rounded as displayed, but the decision phrase and note branched
on the raw is_audible flag. A raw dL_a just above 0 dB that rounds to a
displayed 0.0 dB could therefore print a self-contradicting "0.0 dB > 0".
Derive the audibility decision from the same rounded value through a shared
helper, and add a boundary regression test.
Add wind-turbine tonal audibility report via .report() (#337)
* Add wind-turbine tonal audibility report via .report()
Add WindTurbineTonalityResult.report() rendering a one-page PDF
wind-turbine tonality-assessment fiche (IEC 61400-11:2012+A1:2018,
subclauses 9.5.2-9.5.5).
The sheet carries a standard-basis line, an optional metadata header
(source/situation, client, measurement position, instrumentation, date),
a two-panel body with the critical-band and masking analysis in a metrics
table (tone frequency, critical bandwidth, tone level L_pt, masking-noise
level L_pn, tonality dL_tn, audibility criterion L_a and tonal audibility
dL_a) beside the narrowband-spectrum plot with the critical band, masking
level and tone marked, and a boxed decisive tonal audibility dL_a with the
tone frequency and the audibility decision (a tone is audible when dL_a
exceeds 0 dB). A maximum acceptable tonal audibility supplied via the
metadata requirement adds a PASS/FAIL verdict (a lower audibility is
better). English and Spanish both render.
Register the example fiche, add structural and i18n tests, and regenerate
the committed example PDF, WebP preview and API reference.
* Base the audibility decision on the displayed rounded tonal audibility
The boxed result, verdict and decision text all commit to the tonal
audibility rounded as displayed, but the decision phrase and note branched
on the raw is_audible flag. A raw dL_a just above 0 dB that rounds to a
displayed 0.0 dB could therefore print a self-contradicting "0.0 dB > 0".
Derive the audibility decision from the same rounded value through a shared
helper, and add a boundary regression test.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846) (#334)
* Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846)
Add a one-page PDF .report() fiche to the two structural-vibration
frequency-response result types.
MobilityResult.report() renders a mechanical-mobility measurement fiche
(ISO 7626-1:2011 frequency-response-function definitions; measurement per
ISO 7626-2:2015). Mechanical mobility is a continuous frequency-response
function, not an octave-band quantity, so the sheet presents it honestly as the
mobility magnitude spectrum |Y(f)| plus a compact table of the FRF's
characteristic points (the FRF type, driving-point or transfer, the frequency
range, the peak frequency, the peak mobility magnitude and the phase there),
with a boxed peak mobility |Y| at the frequency it occurs at. It is a
characterisation, so there is no pass/fail verdict.
TransferStiffnessResult.report() renders a dynamic-transfer-stiffness
characterisation fiche for a resilient element (ISO 10846-1:2008 definition;
determined by the direct method, ISO 10846-2:2008, or the indirect
blocking-mass method, ISO 10846-3:2002). The transfer stiffness is a continuous
frequency-response function, so the sheet presents it as the transfer-stiffness
level spectrum Lk(f) plus a compact table of characteristic points (the
determination method, the blocking mass for the indirect method, the frequency
range, and the low-frequency stiffness plateau |k2,1|, its level Lk and the loss
factor there), with a boxed low-frequency Lk. It too is a characterisation, with
no verdict.
Both fiches share a common FRF body (_report/_frf_fiche.py): the title and
basis line, the optional metadata header, the two-panel body with the
characteristic-point table beside the result's own spectrum plot, the boxed
representative value and the footer. English and Spanish both render; example
inputs reuse the modules' oracle-validated closed forms.
* Reuse the result loss_factor in the transfer-stiffness fiche
Share the single ISO 10846-1 (3.8) loss-factor definition by reading the
result's own loss_factor property at the low-frequency index, instead of
recomputing eta = Im/Re in the renderer.
* Drop the unused low-frequency frequency in the stiffness table
The characteristic-point table only needs the magnitude, level and loss
factor at the low-frequency plateau, not its frequency.
Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846) (#334)
* Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846)
Add a one-page PDF .report() fiche to the two structural-vibration
frequency-response result types.
MobilityResult.report() renders a mechanical-mobility measurement fiche
(ISO 7626-1:2011 frequency-response-function definitions; measurement per
ISO 7626-2:2015). Mechanical mobility is a continuous frequency-response
function, not an octave-band quantity, so the sheet presents it honestly as the
mobility magnitude spectrum |Y(f)| plus a compact table of the FRF's
characteristic points (the FRF type, driving-point or transfer, the frequency
range, the peak frequency, the peak mobility magnitude and the phase there),
with a boxed peak mobility |Y| at the frequency it occurs at. It is a
characterisation, so there is no pass/fail verdict.
TransferStiffnessResult.report() renders a dynamic-transfer-stiffness
characterisation fiche for a resilient element (ISO 10846-1:2008 definition;
determined by the direct method, ISO 10846-2:2008, or the indirect
blocking-mass method, ISO 10846-3:2002). The transfer stiffness is a continuous
frequency-response function, so the sheet presents it as the transfer-stiffness
level spectrum Lk(f) plus a compact table of characteristic points (the
determination method, the blocking mass for the indirect method, the frequency
range, and the low-frequency stiffness plateau |k2,1|, its level Lk and the loss
factor there), with a boxed low-frequency Lk. It too is a characterisation, with
no verdict.
Both fiches share a common FRF body (_report/_frf_fiche.py): the title and
basis line, the optional metadata header, the two-panel body with the
characteristic-point table beside the result's own spectrum plot, the boxed
representative value and the footer. English and Spanish both render; example
inputs reuse the modules' oracle-validated closed forms.
* Reuse the result loss_factor in the transfer-stiffness fiche
Share the single ISO 10846-1 (3.8) loss-factor definition by reading the
result's own loss_factor property at the low-frequency index, instead of
recomputing eta = Im/Re in the renderer.
* Drop the unused low-frequency frequency in the stiffness table
The characteristic-point table only needs the magnitude, level and loss
factor at the low-frequency plateau, not its frequency.
Laboratory flanking-transmission reports via .report() (ISO 10848) (#328)
* Laboratory flanking-transmission reports via .report() (ISO 10848)
Add a one-page PDF fiche to each of the three ISO 10848 laboratory
flanking-transmission results.
VibrationReductionResult.report() writes a junction-characterization
report of the vibration reduction index Kij (ISO 10848-1:2006): the
standard-basis line, an optional metadata header, the per-band Kij table
beside the Kij(f) curve and a boxed single-number mean Kij over the
Annex A band range (200 Hz to 1250 Hz for one-third-octave bands, 125 Hz
to 1000 Hz for octave bands) with the count of averaged and bracketed
bands. Bands bracketed for poor modal overlap (M < 0,25,
ISO 10848-4:2010 Clause 9) print their value in brackets and are excluded
from the mean; verbose=True adds a column stating whether each band
enters the mean.
FlankingLevelDifferenceResult.report() and
FlankingImpactLevelResult.report() write measurement reports of the
overall descriptors Dn,f (airborne) and Ln,f (impact, tapping machine,
ISO 10848-2:2006), reusing the shared two-panel insulation report
skeleton: the per-band quantity beside the measured-versus-shifted
ISO 717 reference curve and the boxed single number Dn,f,w (C; Ctr)
(ISO 717-1) or Ln,f,w (CI) (ISO 717-2). verbose=True annexes the ISO 717
evaluation per band (the value, the shifted reference and the
unfavourable deviation). A requirement on the metadata adds a PASS/FAIL
verdict (higher is better for Dn,f,w, lower for Ln,f,w), and
language="es" renders every fiche in Spanish.
Register one example fiche per report kind in the generator with its
committed PDF and WebP preview, document the reports in the EN and ES
laboratory-insulation guides and the docs mirror, add the Spanish
strings, and regenerate the API reference and llms-full.txt.
* Fix the Kij single-number membership shown in the verbose fiche
The verbose Kij table marked a band as entering the single number from its
bracket flag alone, so a non-bracketed band outside the Annex A range (for
instance above 1250 Hz in the one-third-octave case) was labelled as counted
while the boxed "bands averaged" total correctly left it out. Share one
membership mask (inside the Annex A range and not bracketed) between the table
column and the result box so the two always agree, and lock it with a unit
test on the range exclusion. Hoist the fiche construction out of the
engine-rejection pytest.raises blocks.
Laboratory flanking-transmission reports via .report() (ISO 10848) (#328)
* Laboratory flanking-transmission reports via .report() (ISO 10848)
Add a one-page PDF fiche to each of the three ISO 10848 laboratory
flanking-transmission results.
VibrationReductionResult.report() writes a junction-characterization
report of the vibration reduction index Kij (ISO 10848-1:2006): the
standard-basis line, an optional metadata header, the per-band Kij table
beside the Kij(f) curve and a boxed single-number mean Kij over the
Annex A band range (200 Hz to 1250 Hz for one-third-octave bands, 125 Hz
to 1000 Hz for octave bands) with the count of averaged and bracketed
bands. Bands bracketed for poor modal overlap (M < 0,25,
ISO 10848-4:2010 Clause 9) print their value in brackets and are excluded
from the mean; verbose=True adds a column stating whether each band
enters the mean.
FlankingLevelDifferenceResult.report() and
FlankingImpactLevelResult.report() write measurement reports of the
overall descriptors Dn,f (airborne) and Ln,f (impact, tapping machine,
ISO 10848-2:2006), reusing the shared two-panel insulation report
skeleton: the per-band quantity beside the measured-versus-shifted
ISO 717 reference curve and the boxed single number Dn,f,w (C; Ctr)
(ISO 717-1) or Ln,f,w (CI) (ISO 717-2). verbose=True annexes the ISO 717
evaluation per band (the value, the shifted reference and the
unfavourable deviation). A requirement on the metadata adds a PASS/FAIL
verdict (higher is better for Dn,f,w, lower for Ln,f,w), and
language="es" renders every fiche in Spanish.
Register one example fiche per report kind in the generator with its
committed PDF and WebP preview, document the reports in the EN and ES
laboratory-insulation guides and the docs mirror, add the Spanish
strings, and regenerate the API reference and llms-full.txt.
* Fix the Kij single-number membership shown in the verbose fiche
The verbose Kij table marked a band as entering the single number from its
bracket flag alone, so a non-bracketed band outside the Annex A range (for
instance above 1250 Hz in the one-third-octave case) was labelled as counted
while the boxed "bands averaged" total correctly left it out. Share one
membership mask (inside the Annex A range and not bracketed) between the table
column and the result box so the two always agree, and lock it with a unit
test on the range exclusion. Hoist the fiche construction out of the
engine-rejection pytest.raises blocks.
Laboratory flanking-transmission reports via .report() (ISO 10848) (#328)
* Laboratory flanking-transmission reports via .report() (ISO 10848)
Add a one-page PDF fiche to each of the three ISO 10848 laboratory
flanking-transmission results.
VibrationReductionResult.report() writes a junction-characterization
report of the vibration reduction index Kij (ISO 10848-1:2006): the
standard-basis line, an optional metadata header, the per-band Kij table
beside the Kij(f) curve and a boxed single-number mean Kij over the
Annex A band range (200 Hz to 1250 Hz for one-third-octave bands, 125 Hz
to 1000 Hz for octave bands) with the count of averaged and bracketed
bands. Bands bracketed for poor modal overlap (M < 0,25,
ISO 10848-4:2010 Clause 9) print their value in brackets and are excluded
from the mean; verbose=True adds a column stating whether each band
enters the mean.
FlankingLevelDifferenceResult.report() and
FlankingImpactLevelResult.report() write measurement reports of the
overall descriptors Dn,f (airborne) and Ln,f (impact, tapping machine,
ISO 10848-2:2006), reusing the shared two-panel insulation report
skeleton: the per-band quantity beside the measured-versus-shifted
ISO 717 reference curve and the boxed single number Dn,f,w (C; Ctr)
(ISO 717-1) or Ln,f,w (CI) (ISO 717-2). verbose=True annexes the ISO 717
evaluation per band (the value, the shifted reference and the
unfavourable deviation). A requirement on the metadata adds a PASS/FAIL
verdict (higher is better for Dn,f,w, lower for Ln,f,w), and
language="es" renders every fiche in Spanish.
Register one example fiche per report kind in the generator with its
committed PDF and WebP preview, document the reports in the EN and ES
laboratory-insulation guides and the docs mirror, add the Spanish
strings, and regenerate the API reference and llms-full.txt.
* Fix the Kij single-number membership shown in the verbose fiche
The verbose Kij table marked a band as entering the single number from its
bracket flag alone, so a non-bracketed band outside the Annex A range (for
instance above 1250 Hz in the one-third-octave case) was labelled as counted
while the boxed "bands averaged" total correctly left it out. Share one
membership mask (inside the Annex A range and not bracketed) between the table
column and the result box so the two always agree, and lock it with a unit
test on the range exclusion. Hoist the fiche construction out of the
engine-rejection pytest.raises blocks.
Laboratory flanking-transmission reports via .report() (ISO 10848) (#328)
* Laboratory flanking-transmission reports via .report() (ISO 10848)
Add a one-page PDF fiche to each of the three ISO 10848 laboratory
flanking-transmission results.
VibrationReductionResult.report() writes a junction-characterization
report of the vibration reduction index Kij (ISO 10848-1:2006): the
standard-basis line, an optional metadata header, the per-band Kij table
beside the Kij(f) curve and a boxed single-number mean Kij over the
Annex A band range (200 Hz to 1250 Hz for one-third-octave bands, 125 Hz
to 1000 Hz for octave bands) with the count of averaged and bracketed
bands. Bands bracketed for poor modal overlap (M < 0,25,
ISO 10848-4:2010 Clause 9) print their value in brackets and are excluded
from the mean; verbose=True adds a column stating whether each band
enters the mean.
FlankingLevelDifferenceResult.report() and
FlankingImpactLevelResult.report() write measurement reports of the
overall descriptors Dn,f (airborne) and Ln,f (impact, tapping machine,
ISO 10848-2:2006), reusing the shared two-panel insulation report
skeleton: the per-band quantity beside the measured-versus-shifted
ISO 717 reference curve and the boxed single number Dn,f,w (C; Ctr)
(ISO 717-1) or Ln,f,w (CI) (ISO 717-2). verbose=True annexes the ISO 717
evaluation per band (the value, the shifted reference and the
unfavourable deviation). A requirement on the metadata adds a PASS/FAIL
verdict (higher is better for Dn,f,w, lower for Ln,f,w), and
language="es" renders every fiche in Spanish.
Register one example fiche per report kind in the generator with its
committed PDF and WebP preview, document the reports in the EN and ES
laboratory-insulation guides and the docs mirror, add the Spanish
strings, and regenerate the API reference and llms-full.txt.
* Fix the Kij single-number membership shown in the verbose fiche
The verbose Kij table marked a band as entering the single number from its
bracket flag alone, so a non-bracketed band outside the Annex A range (for
instance above 1250 Hz in the one-third-octave case) was labelled as counted
while the boxed "bands averaged" total correctly left it out. Share one
membership mask (inside the Annex A range and not bracketed) between the table
column and the result box so the two always agree, and lock it with a unit
test on the range exclusion. Hoist the fiche construction out of the
engine-rejection pytest.raises blocks.
Laboratory flanking-transmission reports via .report() (ISO 10848) (#328)
* Laboratory flanking-transmission reports via .report() (ISO 10848)
Add a one-page PDF fiche to each of the three ISO 10848 laboratory
flanking-transmission results.
VibrationReductionResult.report() writes a junction-characterization
report of the vibration reduction index Kij (ISO 10848-1:2006): the
standard-basis line, an optional metadata header, the per-band Kij table
beside the Kij(f) curve and a boxed single-number mean Kij over the
Annex A band range (200 Hz to 1250 Hz for one-third-octave bands, 125 Hz
to 1000 Hz for octave bands) with the count of averaged and bracketed
bands. Bands bracketed for poor modal overlap (M < 0,25,
ISO 10848-4:2010 Clause 9) print their value in brackets and are excluded
from the mean; verbose=True adds a column stating whether each band
enters the mean.
FlankingLevelDifferenceResult.report() and
FlankingImpactLevelResult.report() write measurement reports of the
overall descriptors Dn,f (airborne) and Ln,f (impact, tapping machine,
ISO 10848-2:2006), reusing the shared two-panel insulation report
skeleton: the per-band quantity beside the measured-versus-shifted
ISO 717 reference curve and the boxed single number Dn,f,w (C; Ctr)
(ISO 717-1) or Ln,f,w (CI) (ISO 717-2). verbose=True annexes the ISO 717
evaluation per band (the value, the shifted reference and the
unfavourable deviation). A requirement on the metadata adds a PASS/FAIL
verdict (higher is better for Dn,f,w, lower for Ln,f,w), and
language="es" renders every fiche in Spanish.
Register one example fiche per report kind in the generator with its
committed PDF and WebP preview, document the reports in the EN and ES
laboratory-insulation guides and the docs mirror, add the Spanish
strings, and regenerate the API reference and llms-full.txt.
* Fix the Kij single-number membership shown in the verbose fiche
The verbose Kij table marked a band as entering the single number from its
bracket flag alone, so a non-bracketed band outside the Annex A range (for
instance above 1250 Hz in the one-third-octave case) was labelled as counted
while the boxed "bands averaged" total correctly left it out. Share one
membership mask (inside the Annex A range and not bracketed) between the table
column and the result box so the two always agree, and lock it with a unit
test on the range exclusion. Hoist the fiche construction out of the
engine-rejection pytest.raises blocks.
Laboratory flanking-transmission reports via .report() (ISO 10848) (#328)
* Laboratory flanking-transmission reports via .report() (ISO 10848)
Add a one-page PDF fiche to each of the three ISO 10848 laboratory
flanking-transmission results.
VibrationReductionResult.report() writes a junction-characterization
report of the vibration reduction index Kij (ISO 10848-1:2006): the
standard-basis line, an optional metadata header, the per-band Kij table
beside the Kij(f) curve and a boxed single-number mean Kij over the
Annex A band range (200 Hz to 1250 Hz for one-third-octave bands, 125 Hz
to 1000 Hz for octave bands) with the count of averaged and bracketed
bands. Bands bracketed for poor modal overlap (M < 0,25,
ISO 10848-4:2010 Clause 9) print their value in brackets and are excluded
from the mean; verbose=True adds a column stating whether each band
enters the mean.
FlankingLevelDifferenceResult.report() and
FlankingImpactLevelResult.report() write measurement reports of the
overall descriptors Dn,f (airborne) and Ln,f (impact, tapping machine,
ISO 10848-2:2006), reusing the shared two-panel insulation report
skeleton: the per-band quantity beside the measured-versus-shifted
ISO 717 reference curve and the boxed single number Dn,f,w (C; Ctr)
(ISO 717-1) or Ln,f,w (CI) (ISO 717-2). verbose=True annexes the ISO 717
evaluation per band (the value, the shifted reference and the
unfavourable deviation). A requirement on the metadata adds a PASS/FAIL
verdict (higher is better for Dn,f,w, lower for Ln,f,w), and
language="es" renders every fiche in Spanish.
Register one example fiche per report kind in the generator with its
committed PDF and WebP preview, document the reports in the EN and ES
laboratory-insulation guides and the docs mirror, add the Spanish
strings, and regenerate the API reference and llms-full.txt.
* Fix the Kij single-number membership shown in the verbose fiche
The verbose Kij table marked a band as entering the single number from its
bracket flag alone, so a non-bracketed band outside the Annex A range (for
instance above 1250 Hz in the one-third-octave case) was labelled as counted
while the boxed "bands averaged" total correctly left it out. Share one
membership mask (inside the Annex A range and not bracketed) between the table
column and the result box so the two always agree, and lock it with a unit
test on the range exclusion. Hoist the fiche construction out of the
engine-rejection pytest.raises blocks.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Predicted facade sound insulation report via .report() (EN 12354-3) (#326)
* Add FacadePredictionResult.report() for predicted facade insulation (EN 12354-3)
Render a one-page prediction fiche for the predicted standardized level
difference of a facade D2m,nT (EN/ISO 12354-3, Formula 13), reusing the
shared EN/ISO 12354 prediction report body: the facade-element table
(each element's weighted partial index Rp,w, with an optional transmitted
energy share) beside the result's own per-element / R' / D2m,nT plot, the
boxed predicted D2m,nT,w and the prediction statement. Clearly labelled a
prediction from element data, never a measurement.
* Test the predicted facade insulation fiche against EN 12354-3 Annex F
Pin the facade fiche to the Annex F worked example (D2m,nT,w = 33 dB) run
through the tested prediction code: pypdf assertions on the boxed single
number, the prediction / not-a-measurement wording, the model terms, the
per-element partial indices, the verbose energy share, the requirement
verdict, the Spanish fiche and the missing-rating guard.
* Add the EN 12354-3 facade prediction example fiche and regenerate artifacts
Add the Annex F facade prediction example to generate_reports.py with its
committed PDF and WebP preview, and regenerate the generated API reference
and llms bundle for the new report() method.
* Document the predicted facade insulation report (EN+ES)
Add the facade prediction report subsection to the EN and ES prediction
guides (with a ReportPreview of the committed example fiche) and a
CHANGELOG entry.
* Show the apparent-index values on the facade fiche and unify R'tr,s,w notation
State the computed apparent traffic-referenced index and spectrum term as
values on the predicted facade fiche (R'tr,s,w = 31 dB, Ctr = -3 dB in the
Annex F example), not just their symbols, by filling the basis line with the
result's own numbers. Use the primed apparent-index notation R'tr,s,w
consistently across the fiche, the guides and the example comments.
Predicted facade sound insulation report via .report() (EN 12354-3) (#326)
* Add FacadePredictionResult.report() for predicted facade insulation (EN 12354-3)
Render a one-page prediction fiche for the predicted standardized level
difference of a facade D2m,nT (EN/ISO 12354-3, Formula 13), reusing the
shared EN/ISO 12354 prediction report body: the facade-element table
(each element's weighted partial index Rp,w, with an optional transmitted
energy share) beside the result's own per-element / R' / D2m,nT plot, the
boxed predicted D2m,nT,w and the prediction statement. Clearly labelled a
prediction from element data, never a measurement.
* Test the predicted facade insulation fiche against EN 12354-3 Annex F
Pin the facade fiche to the Annex F worked example (D2m,nT,w = 33 dB) run
through the tested prediction code: pypdf assertions on the boxed single
number, the prediction / not-a-measurement wording, the model terms, the
per-element partial indices, the verbose energy share, the requirement
verdict, the Spanish fiche and the missing-rating guard.
* Add the EN 12354-3 facade prediction example fiche and regenerate artifacts
Add the Annex F facade prediction example to generate_reports.py with its
committed PDF and WebP preview, and regenerate the generated API reference
and llms bundle for the new report() method.
* Document the predicted facade insulation report (EN+ES)
Add the facade prediction report subsection to the EN and ES prediction
guides (with a ReportPreview of the committed example fiche) and a
CHANGELOG entry.
* Show the apparent-index values on the facade fiche and unify R'tr,s,w notation
State the computed apparent traffic-referenced index and spectrum term as
values on the predicted facade fiche (R'tr,s,w = 31 dB, Ctr = -3 dB in the
Annex F example), not just their symbols, by filling the basis line with the
result's own numbers. Use the primed apparent-index notation R'tr,s,w
consistently across the fiche, the guides and the example comments.
Add element-normalized intensity insulation report via .report() (#338)
* Add element-normalized intensity insulation report via .report()
Add IntensityElementNormalizedResult.report(): a one-page PDF fiche for
the element-normalized level difference DI,n,e of a small building element
measured with sound intensity (ISO 15186-1:2000, Clause 3.9, Formula (8)).
DI,n,e is a level difference rated by the ISO 717-1 airborne machinery, the
same as the sibling intensity sound reduction index RI, so the fiche is
driven through the shared insulation skeleton (render_insulation_fiche) with
the shared iso717_columns_builder. It lives in the existing iso15186.py
renderer beside the RI fiche, so no second near-identical renderer is added.
The sheet carries the standard-basis line, an optional metadata header, the
per-band table (16 one-third-octave or 5 octave bands) beside the
measured-versus-shifted-reference curve, the boxed rating DI,n,e,w (C; Ctr)
and the intensity-method statement. verbose=True shows the ISO 717 evaluation
per band; a metadata requirement adds a PASS/FAIL verdict (the element
insulation passes at or above the target); language="es" renders the Spanish
fiche.
The example is anchored to the ISO 717-1:2020 Annex C worked-example curve
read as a documented DI,n,e spectrum, pinning the rating to the published
30 (-2; -3) dB through the intensity path without a new numeric oracle. It is
registered in the report generator with its committed PDF and WebP preview,
and the guides and API reference are updated.
* Share the intensity-report request validation helper
Extract the engine, language, rating-presence and band-count guards the two
ISO 15186-1 intensity report methods share into a single
_validate_intensity_report helper, mirroring the flanking-transmission module.
It returns the validated non-None rating so each report method hands it
straight to the renderer, removing the duplicated guard block.
* Regenerate API reference after rebase
Add element-normalized intensity insulation report via .report() (#338)
* Add element-normalized intensity insulation report via .report()
Add IntensityElementNormalizedResult.report(): a one-page PDF fiche for
the element-normalized level difference DI,n,e of a small building element
measured with sound intensity (ISO 15186-1:2000, Clause 3.9, Formula (8)).
DI,n,e is a level difference rated by the ISO 717-1 airborne machinery, the
same as the sibling intensity sound reduction index RI, so the fiche is
driven through the shared insulation skeleton (render_insulation_fiche) with
the shared iso717_columns_builder. It lives in the existing iso15186.py
renderer beside the RI fiche, so no second near-identical renderer is added.
The sheet carries the standard-basis line, an optional metadata header, the
per-band table (16 one-third-octave or 5 octave bands) beside the
measured-versus-shifted-reference curve, the boxed rating DI,n,e,w (C; Ctr)
and the intensity-method statement. verbose=True shows the ISO 717 evaluation
per band; a metadata requirement adds a PASS/FAIL verdict (the element
insulation passes at or above the target); language="es" renders the Spanish
fiche.
The example is anchored to the ISO 717-1:2020 Annex C worked-example curve
read as a documented DI,n,e spectrum, pinning the rating to the published
30 (-2; -3) dB through the intensity path without a new numeric oracle. It is
registered in the report generator with its committed PDF and WebP preview,
and the guides and API reference are updated.
* Share the intensity-report request validation helper
Extract the engine, language, rating-presence and band-count guards the two
ISO 15186-1 intensity report methods share into a single
_validate_intensity_report helper, mirroring the flanking-transmission module.
It returns the validated non-None rating so each report method hands it
straight to the renderer, removing the duplicated guard block.
* Regenerate API reference after rebase
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Add field and survey building-insulation reports via .report() (#335)
* Add field and survey building-insulation reports via .report()
Give the field and survey building-insulation results a one-page PDF field
test report, reusing the shared ISO 717 insulation skeleton so each is a
per-band curve rated against a shifted reference:
- SurveyAirborneResult, SurveyImpactResult and SurveyFacadeResult (ISO
10052:2021 survey/control method, octave bands) report DnT (or R'), L'nT and
D2m,nT with their ISO 717 weighted single number and the survey-method
statement.
- FacadeInsulationResult (ISO 16283-3:2016 field facade, one-third-octave
bands) reports D2m,nT (default), D2m,n or R'45 with the D2m,nT,w (C; Ctr)
rating and the engineering-method statement.
Each sheet carries the standard-basis line, an optional metadata header, the
per-band table beside the measured-versus-shifted-reference curve, the boxed
single number, an optional requirement verdict (level differences and
reduction indices pass at or above the target, the impact level at or below
it) and a footer; verbose=True annexes the ISO 717 evaluation per band, and
both English and Spanish render.
The shared ISO 717 default/verbose columns builder is hoisted into the
insulation-fiche helper so the survey, field-facade and flanking renderers
drive a single implementation. Registers one committed example per report,
extends the field-insulation guide (EN and ES), and updates the changelog.
* Share the field engineering-method statement across the ISO 16283 specs
* Caption the survey table by its band set and state the facade rating per quantity
The ISO 10052 survey report hard-coded the octave-band table caption, so a
one-third-octave survey report (16 bands, which the survey API accepts) was
mislabelled; derive the caption from the reported curve length and cover it
with a one-third-octave regression test. Correct the facade report
description: it boxes the ISO 717 weighted rating of the reported quantity
(D2m,nT,w, D2m,n,w or R'45,w), not always D2m,nT,w.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
ISO 4871 noise-emission declaration with a .report() fiche (#263)
* feat: ISO 4871 noise-emission declaration with a .report() fiche
Add the ISO 4871:1996 declaration of noise emission values of machinery and
equipment: the standardised noise-emission declaration a manufacturer states in
technical documents.
NoiseEmissionDeclaration and OperatingModeDeclaration model the declared
quantities per operating mode: the measured A-weighted sound power level L_WA
and its uncertainty K_WA (the dual-number form, clause 3.16), optionally the
A-weighted emission sound pressure level L_pA at a work station, and the derived
single-number value L_WAd = L_WA + K_WA (clause 3.15), an upper bound. The
single-machine verification verdict of clause 6.2 (verified when L_1 <= L_WAd)
is exposed per mode. SoundPowerResult.declare() builds a declaration straight
from a measured sound power, defaulting K_WA to the expanded uncertainty.
The .report() method renders a one-page ISO 4871 declaration fiche reproducing
the Annex B format: the machine identification and operating conditions, the
declared dual- or single-number table across the operating-mode columns, the
noise-test-code and basic-standards footnote, and a verification verdict table.
Localised in English and Spanish.
Verified against ISO 4871 Annex B: L_WA = 88, K_WA = 2 gives L_WAd = 90 (and
95/2 gives 97); L_pA = 78/86 with K_pA = 2 gives L_pAd = 80/88; verification
passes at the boundary L_1 = L_WAd and fails just above it. Registered as two
conformance rows.
Adds the committed example fiche, tests, the sound-power guide section (EN/ES)
with the fiche preview and the ISO 4871 bibliography entry.
* docs: map the new emission.declaration module in the API taxonomy
generate_api_docs.py fails loudly on any module missing from the taxonomy, so
the new phonometry.emission.declaration module needs a home; add it under the
sound-power/intensity section and regenerate the API reference pages.
* review: drop the assert, align fiche rounding, tighten declare() typing
- Replace the pairing assert in NoiseEmissionDeclaration with an explicit None
guard so bandit no longer flags B101 (the codebase avoids asserts in src).
- Round the fiche's displayed levels with the model's halves-up _round_db rather
than Python's round-half-to-even, so the printed value matches the declared
quantity exactly.
- Annotate SoundPowerResult.declare() with str | Sequence[str] and
DeclarationForm, dropping the now-unnecessary type: ignore.
* docs: regenerate the sound-power API page for the tightened declare() signature
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Correct fiche verdict rules and mandatory report items across the .report() layer (#281)
* fix(report): apply the current R 128 tolerance rules and the standards' mandatory report items across the fiches
The EBU R 128 programme-loudness fiche passed its verdict on a blanket
+/-0.5 LU about the target, the June 2014 (V3) rule that R 128 dropped in
its August 2020 revision. ProgramLoudnessResult.report() now selects the
tolerance explicitly: tolerance="qc" (default) applies the +/-0.2 LU
measurement-error allowance of item i) for loudness workflows such as
Quality Control, tolerance="live" applies the +/-1.0 LU tolerance of
item h) for programmes where the Target Level is not achievable
practically; the fiche prints the applied rule and its R 128 item, and the
verdict is evaluated on the loudness rounded to the displayed 0.1 LU
(Tech 3341 display precision), so the printed numbers can never contradict
it at the boundary. The committed example signal is trimmed 0.4 dB onto
the -23.0 LUFS target so it passes the QC rule it demonstrates.
Also fixed across the fiche layer:
- language="es" now reaches the embedded chart: the fiche language is
forwarded to the result's own plot(), so Spanish fiches embed Spanish
axis labels and legends instead of English ones.
- ISO 532-1: the fiche states the clause 7 mandatory items: the method
used (stationary, clause 5, or time-varying, clause 6), the sound field
(ZwickerLoudness gains a field attribute set by the constructors), the
loudness-versus-time function N(t) for time-varying sounds and the
"Maximum loudness Nmax" labelling of the reported maximum.
- ICAO Annex 16: effective_perceived_noise_level() gains
procedure="aeroplane"|"helicopter", plumbing the App. 2 4.3.1 Step 1
tone-correction start band (50 Hz for helicopters and tilt-rotors)
through the public chain; the verdict determines the EPNL once to one
decimal place, as the Annex states it, before the level, margin and
status are derived; the reference-conditions strip cites Part II
3.6.1.5 in full (25 C i.e. ISA + 10 C, 70 % RH, 1013.25 hPa, zero wind).
- ISO 717: the caption declares the band set actually rated (an
octave-band rating was captioned one-third-octave, against the clause
4.4 statement requirement); report() gains symbol= so field quantities
(DnT,w, L'nT,w, ...) are not mislabelled with the laboratory Rw / Ln,w
descriptor; adaptation terms print a sign only when negative, the style
of the standard's own examples.
- IEC 61260-1: verify_filter_class() reports range_limited (and per-band
checked_to_omega) when the stop-band mask extends beyond a band's
processing Nyquist, and the fiche qualifies its COMPLIES statement
accordingly; bands are labelled with nominal mid-band frequencies; the
1995 fiche cites that edition's relative-attenuation definition (3.13
Note); a required_class absent from the verified edition is rejected.
- ISO 11654: the shape indicator is written in the clause 5.3 style
(0.60(M), no space) and the 5.3 NOTE recommendation is printed when an
indicator applies.
- Header grids reprint client-supplied metadata verbatim (1.23 m2 no
longer becomes 1.2), values that round to zero never print -0.0, and
the remaining English fragments on the Spanish IEC 61260 fiche are
localised.
Every fiche gains at least one pypdf content test pinning the exact
displayed values, plus boundary tests for the display-rounded verdicts
and the helicopter start band.
* chore: regenerate example fiches, API reference pages and llms files
The example fiches pick up the corrected verdict rules and report items
(the programme-loudness example now demonstrates the default +/-0.2 LU QC
rule on target), and the generated API pages and llms files pick up the
new report keywords and result attributes.
* fix(report): integrate the fiche corrections with the field-report engine
The rebase onto the ISO 16283 fiches left two seams: the verdict strings were
added by both branches (duplicate i18n keys) and the new field renderer's
embedded-plot closure did not accept the language argument the layout now
forwards. Dedupe the table, accept the keyword, and re-verify the rendered
examples.
* fix(report): draw the LRA band as a pale opaque tint so the curves stay visible
The report pipeline renders through svglib, which drops alpha, so the
translucent LRA span came out as saturated orange and hid the momentary
trace. Use the 15 percent composite of the accent over white as an opaque
fill below the curves, matching the other fiches' band treatment.
* fix(report): keep fiche charts full width and legends tidy
Cap the relocated legend at three columns: a single four-entry row (the
impact fiches add the 500 Hz read marker) grew wider than the axes and
tight_layout shrank the chart, leaving the impact fiche visibly narrower
than its airborne sibling. Also compact the field-fiche y-axis labels to
the quantity symbol (the full name already heads the page and the table),
regenerate the affected examples, and drop the now-unused secondary color
import.
* review: remove float equality, reduce complexity and hoist raise-block setup
Sonar flagged the signed-zero normalisation in format_number and the
display rounding's zero check as float equality: normalise the sign by
inspecting the formatted text and compare the non-negative magnitude with
an order relation instead. Extract the per-band evaluation of
verify_filter_class and the loudness fiche's basis line into helpers to
bring both functions under the complexity threshold. Hoist the setup calls
out of four pytest.raises blocks, print the live tolerance through
format_number so it keeps one decimal, and round the loudness metrics row
with the same display rule as the boxed statement.
Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846) (#334)
* Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846)
Add a one-page PDF .report() fiche to the two structural-vibration
frequency-response result types.
MobilityResult.report() renders a mechanical-mobility measurement fiche
(ISO 7626-1:2011 frequency-response-function definitions; measurement per
ISO 7626-2:2015). Mechanical mobility is a continuous frequency-response
function, not an octave-band quantity, so the sheet presents it honestly as the
mobility magnitude spectrum |Y(f)| plus a compact table of the FRF's
characteristic points (the FRF type, driving-point or transfer, the frequency
range, the peak frequency, the peak mobility magnitude and the phase there),
with a boxed peak mobility |Y| at the frequency it occurs at. It is a
characterisation, so there is no pass/fail verdict.
TransferStiffnessResult.report() renders a dynamic-transfer-stiffness
characterisation fiche for a resilient element (ISO 10846-1:2008 definition;
determined by the direct method, ISO 10846-2:2008, or the indirect
blocking-mass method, ISO 10846-3:2002). The transfer stiffness is a continuous
frequency-response function, so the sheet presents it as the transfer-stiffness
level spectrum Lk(f) plus a compact table of characteristic points (the
determination method, the blocking mass for the indirect method, the frequency
range, and the low-frequency stiffness plateau |k2,1|, its level Lk and the loss
factor there), with a boxed low-frequency Lk. It too is a characterisation, with
no verdict.
Both fiches share a common FRF body (_report/_frf_fiche.py): the title and
basis line, the optional metadata header, the two-panel body with the
characteristic-point table beside the result's own spectrum plot, the boxed
representative value and the footer. English and Spanish both render; example
inputs reuse the modules' oracle-validated closed forms.
* Reuse the result loss_factor in the transfer-stiffness fiche
Share the single ISO 10846-1 (3.8) loss-factor definition by reading the
result's own loss_factor property at the low-frequency index, instead of
recomputing eta = Im/Re in the renderer.
* Drop the unused low-frequency frequency in the stiffness table
The characteristic-point table only needs the magnitude, level and loss
factor at the low-frequency plateau, not its frequency.
Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846) (#334)
* Add structural-vibration FRF reports via .report() (ISO 7626, ISO 10846)
Add a one-page PDF .report() fiche to the two structural-vibration
frequency-response result types.
MobilityResult.report() renders a mechanical-mobility measurement fiche
(ISO 7626-1:2011 frequency-response-function definitions; measurement per
ISO 7626-2:2015). Mechanical mobility is a continuous frequency-response
function, not an octave-band quantity, so the sheet presents it honestly as the
mobility magnitude spectrum |Y(f)| plus a compact table of the FRF's
characteristic points (the FRF type, driving-point or transfer, the frequency
range, the peak frequency, the peak mobility magnitude and the phase there),
with a boxed peak mobility |Y| at the frequency it occurs at. It is a
characterisation, so there is no pass/fail verdict.
TransferStiffnessResult.report() renders a dynamic-transfer-stiffness
characterisation fiche for a resilient element (ISO 10846-1:2008 definition;
determined by the direct method, ISO 10846-2:2008, or the indirect
blocking-mass method, ISO 10846-3:2002). The transfer stiffness is a continuous
frequency-response function, so the sheet presents it as the transfer-stiffness
level spectrum Lk(f) plus a compact table of characteristic points (the
determination method, the blocking mass for the indirect method, the frequency
range, and the low-frequency stiffness plateau |k2,1|, its level Lk and the loss
factor there), with a boxed low-frequency Lk. It too is a characterisation, with
no verdict.
Both fiches share a common FRF body (_report/_frf_fiche.py): the title and
basis line, the optional metadata header, the two-panel body with the
characteristic-point table beside the result's own spectrum plot, the boxed
representative value and the footer. English and Spanish both render; example
inputs reuse the modules' oracle-validated closed forms.
* Reuse the result loss_factor in the transfer-stiffness fiche
Share the single ISO 10846-1 (3.8) loss-factor definition by reading the
result's own loss_factor property at the low-frequency index, instead of
recomputing eta = Im/Re in the renderer.
* Drop the unused low-frequency frequency in the stiffness table
The characteristic-point table only needs the magnitude, level and loss
factor at the low-frequency plateau, not its frequency.
Sound power from surface vibration report via .report() (ISO/TS 7849) (#325)
* Add ISO/TS 7849 sound-power-from-vibration .report() fiche
Render VibrationSoundPowerResult (airborne sound power radiated through
surface vibration, ISO/TS 7849-1/-2:2009) to a one-page PDF fiche via the
shared sound-power report engine. The vibration-method variant adds the
surface velocity level Lv and radiation factor epsilon columns, the
radiating area S in the boxed result and the LW = Lv + 10 lg(S/S0) +
10 lg(epsilon) + 10 lg(411/400) basis strip, and names the survey (Part 1,
fixed epsilon = 1) or engineering (Part 2, determined epsilon) method.
Add a sound_power_level_a property (A-weighted total) to the result and the
Spanish translations for the new strings.
* Add the ISO/TS 7849 example fiche and its committed preview
Register an engineering-method (Part 2) example in generate_reports.py: a
gearbox casing of radiating area S = 1.6 m2 surveyed over six octave bands
with a measured radiation factor, giving LWA = 88.7 dB(A) re 1 pW against a
declared 90 dB(A) limit. Commit the rendered PDF and its WebP preview.
* Test the ISO/TS 7849 sound-power-from-vibration fiche
Recompute LW and LWA from the closed-form ISO/TS 7849 Eq. 3/8/12 against a
clean-room oracle and assert they, the band labels, the method part and the
basis prose appear in the PDF; cover the survey/engineering variants, the
verbose radiation-factor column, the verdict, the metadata header, the
Spanish fiche and the rendering contract.
* Document the ISO/TS 7849 report and regenerate the API reference
Add a measurement-report section to the EN and ES vibration-sound-power
guides (with the ReportPreview) and the docs mirror, regenerate the
generated API page for the new report() and sound_power_level_a members, and
record the addition in the changelog.
* Address review on the ISO/TS 7849 report
- Do not present an unweighted broadband LW as LWA: sound_power_level_a now
returns nan without a band spectrum, so the fiche boxes the unweighted total
LW and draws no A-weighted verdict, and the basis strip omits the A-weighting
sentence for a broadband result.
- Drop the unused result parameter from the relation-strip helper.
- Render the fixed impedance term with the locale decimal separator (0.12 dB in
the English fiche, 0,12 dB in the Spanish one) via format_number.
- Cite the accelerometer calibration standard (ISO 16063-21) in the example
instead of IEC 60651, which specifies sound level meters.
- Assert the one-page contract on the longer one-third-octave table and add a
broadband test asserting no false A-weighted claim.
Regenerate the example fiche PDF and WebP preview and the generated API page.
Sound power from surface vibration report via .report() (ISO/TS 7849) (#325)
* Add ISO/TS 7849 sound-power-from-vibration .report() fiche
Render VibrationSoundPowerResult (airborne sound power radiated through
surface vibration, ISO/TS 7849-1/-2:2009) to a one-page PDF fiche via the
shared sound-power report engine. The vibration-method variant adds the
surface velocity level Lv and radiation factor epsilon columns, the
radiating area S in the boxed result and the LW = Lv + 10 lg(S/S0) +
10 lg(epsilon) + 10 lg(411/400) basis strip, and names the survey (Part 1,
fixed epsilon = 1) or engineering (Part 2, determined epsilon) method.
Add a sound_power_level_a property (A-weighted total) to the result and the
Spanish translations for the new strings.
* Add the ISO/TS 7849 example fiche and its committed preview
Register an engineering-method (Part 2) example in generate_reports.py: a
gearbox casing of radiating area S = 1.6 m2 surveyed over six octave bands
with a measured radiation factor, giving LWA = 88.7 dB(A) re 1 pW against a
declared 90 dB(A) limit. Commit the rendered PDF and its WebP preview.
* Test the ISO/TS 7849 sound-power-from-vibration fiche
Recompute LW and LWA from the closed-form ISO/TS 7849 Eq. 3/8/12 against a
clean-room oracle and assert they, the band labels, the method part and the
basis prose appear in the PDF; cover the survey/engineering variants, the
verbose radiation-factor column, the verdict, the metadata header, the
Spanish fiche and the rendering contract.
* Document the ISO/TS 7849 report and regenerate the API reference
Add a measurement-report section to the EN and ES vibration-sound-power
guides (with the ReportPreview) and the docs mirror, regenerate the
generated API page for the new report() and sound_power_level_a members, and
record the addition in the changelog.
* Address review on the ISO/TS 7849 report
- Do not present an unweighted broadband LW as LWA: sound_power_level_a now
returns nan without a band spectrum, so the fiche boxes the unweighted total
LW and draws no A-weighted verdict, and the basis strip omits the A-weighting
sentence for a broadband result.
- Drop the unused result parameter from the relation-strip helper.
- Render the fixed impedance term with the locale decimal separator (0.12 dB in
the English fiche, 0,12 dB in the Spanish one) via format_number.
- Cite the accelerometer calibration standard (ISO 16063-21) in the example
instead of IEC 60651, which specifies sound level meters.
- Assert the one-page contract on the longer one-third-octave table and add a
broadband test asserting no false A-weighted claim.
Regenerate the example fiche PDF and WebP preview and the generated API page.
Add ISO 9053-1 static airflow-resistance report via .report() (#339)
* Add ISO 9053-1 static airflow-resistance report via .report()
Add a one-page PDF material airflow-resistance test report to
StaticAirflowResult, laid out like an accredited ISO 9053-1:2018
static/direct airflow-method certificate.
The fiche carries a standard-basis line, an optional metadata header
(client, manufacturer, specimen, specimen thickness, test facility,
date, climate), a two-panel body with a metrics table (the evaluation
velocity, the fitted pressure difference, the airflow resistance R, the
specific airflow resistance R_s, the airflow resistivity sigma when a
thickness is available, and the through-origin fit coefficients a and b)
beside the fitted pressure-drop curve, and a boxed specific airflow
resistance R_s with R and sigma alongside, all read at the clause 7.5
reference velocity of 0.5 mm/s. ISO 9053-1 is a material
characterisation, so the fiche carries no pass/fail verdict.
The renderer reuses the shared report layout and metadata container, and
renders in English and Spanish. A worked example is registered in the
report generator and its rendered fiche committed alongside the others.
* Document the plot dependency and use a language-neutral precision note
The static airflow-resistance fiche embeds the fitted curve, so state that
rendering needs both reportlab and matplotlib (phonometry[report,plot]) in the
English and Spanish guides and the materials doc. Describe the evaluation-velocity
precision as one decimal place rather than with a locale-specific separator, and
regenerate the API page.
* Extract the shared material-test fiche scaffold
The dynamic-stiffness (EN 29052-1 / ISO 9052-1) and static airflow-resistance
(ISO 9053-1) fiches share the same one-page shape: title and basis line,
metadata identity grid, a metrics table beside the result's self-scaling plot,
a boxed single-number result with extended terms, and the footer. Move that
common scaffold into a single _material_fiche helper (the content dataclass, the
identity-grid builder, the standard-basis-line helper and the renderer) and have
both fiches supply only their own labels, metric rows and boxed statement. The
rendered output is unchanged.
Add ISO 9053-1 static airflow-resistance report via .report() (#339)
* Add ISO 9053-1 static airflow-resistance report via .report()
Add a one-page PDF material airflow-resistance test report to
StaticAirflowResult, laid out like an accredited ISO 9053-1:2018
static/direct airflow-method certificate.
The fiche carries a standard-basis line, an optional metadata header
(client, manufacturer, specimen, specimen thickness, test facility,
date, climate), a two-panel body with a metrics table (the evaluation
velocity, the fitted pressure difference, the airflow resistance R, the
specific airflow resistance R_s, the airflow resistivity sigma when a
thickness is available, and the through-origin fit coefficients a and b)
beside the fitted pressure-drop curve, and a boxed specific airflow
resistance R_s with R and sigma alongside, all read at the clause 7.5
reference velocity of 0.5 mm/s. ISO 9053-1 is a material
characterisation, so the fiche carries no pass/fail verdict.
The renderer reuses the shared report layout and metadata container, and
renders in English and Spanish. A worked example is registered in the
report generator and its rendered fiche committed alongside the others.
* Document the plot dependency and use a language-neutral precision note
The static airflow-resistance fiche embeds the fitted curve, so state that
rendering needs both reportlab and matplotlib (phonometry[report,plot]) in the
English and Spanish guides and the materials doc. Describe the evaluation-velocity
precision as one decimal place rather than with a locale-specific separator, and
regenerate the API page.
* Extract the shared material-test fiche scaffold
The dynamic-stiffness (EN 29052-1 / ISO 9052-1) and static airflow-resistance
(ISO 9053-1) fiches share the same one-page shape: title and basis line,
metadata identity grid, a metrics table beside the result's self-scaling plot,
a boxed single-number result with extended terms, and the footer. Move that
common scaffold into a single _material_fiche helper (the content dataclass, the
identity-grid builder, the standard-basis-line helper and the renderer) and have
both fiches supply only their own labels, metric rows and boxed statement. The
rendered output is unchanged.
ISO 9612 occupational noise-exposure measurement report via .report() (#288)
* feat(hearing): ISO 9612 occupational noise-exposure measurement report via .report()
ExposureResult.report() writes the one-page measurement report of ISO
9612:2009 Clause 15, laid out like a prevention-service measurement sheet:
the standard-basis line naming the applied strategy, a header grid with the
company, worker(s)/job, workplace and the new ReportMetadata free-text
instrumentation and calibration fields (Clause 15 c), the work analysis
(the per-task table of durations, Lp,A,eqT,m levels and LEX,8h,m
contributions with the result's contribution chart for a task-based
determination, or the sampling summary with the Formula C.9 budget for the
job-based/full-day strategies; verbose=True adds the per-task Annex C
uncertainty columns), and the boxed LEX,8h with the expanded uncertainty U
stated as a separate value (Clause 15 e), k = 1.65 and the one-sided 95 %
upper limit.
The fiche then assesses the result against Directive 2003/10/EC Article 3:
the lower and upper exposure action values (80/85 dB(A)) and the exposure
limit value (87 dB(A)), each marked exceeded / not exceeded on the level
rounded to one decimal exactly as displayed, with a PASS/FAIL verdict
against the limit value and a printed note that the limit value applies to
the effective exposure with the worn hearing protectors' attenuation taken
into account. A sampling advisory line surfaces the Clause 9.3/10.4/11.3
recommendations when the result carries them.
ExposureResult records the instrument class the strategy was called with,
printed as the Clause 15 c instrumentation fallback when no free text is
supplied. English and Spanish fiches (language="es" uses the RD 286/2006
vocabulary: nivel de exposicion diario equivalente, valor limite de
exposicion, comma decimals).
Tests pin a hand-derivable oracle (two 4 h tasks at 85/75 dB give
LEX,8h = 75 + 10 lg 5.5 = 82.4 dB and the closed-form
U = 1.65 sqrt((101/121) 3.25) = 2.7 dB) read back from the PDF, the Annex D
84.3 dB / 3.2 dB example, and the 80/85/87 dB(A) boundary flips on the
displayed value. The rendered Annex D welders' example is committed under
.github/reports/ and embedded in the EN/ES guides and the GitHub docs.
* test: construct the report path outside the ISO 9612 pytest.raises blocks
ISO 9612 occupational noise-exposure measurement report via .report() (#288)
* feat(hearing): ISO 9612 occupational noise-exposure measurement report via .report()
ExposureResult.report() writes the one-page measurement report of ISO
9612:2009 Clause 15, laid out like a prevention-service measurement sheet:
the standard-basis line naming the applied strategy, a header grid with the
company, worker(s)/job, workplace and the new ReportMetadata free-text
instrumentation and calibration fields (Clause 15 c), the work analysis
(the per-task table of durations, Lp,A,eqT,m levels and LEX,8h,m
contributions with the result's contribution chart for a task-based
determination, or the sampling summary with the Formula C.9 budget for the
job-based/full-day strategies; verbose=True adds the per-task Annex C
uncertainty columns), and the boxed LEX,8h with the expanded uncertainty U
stated as a separate value (Clause 15 e), k = 1.65 and the one-sided 95 %
upper limit.
The fiche then assesses the result against Directive 2003/10/EC Article 3:
the lower and upper exposure action values (80/85 dB(A)) and the exposure
limit value (87 dB(A)), each marked exceeded / not exceeded on the level
rounded to one decimal exactly as displayed, with a PASS/FAIL verdict
against the limit value and a printed note that the limit value applies to
the effective exposure with the worn hearing protectors' attenuation taken
into account. A sampling advisory line surfaces the Clause 9.3/10.4/11.3
recommendations when the result carries them.
ExposureResult records the instrument class the strategy was called with,
printed as the Clause 15 c instrumentation fallback when no free text is
supplied. English and Spanish fiches (language="es" uses the RD 286/2006
vocabulary: nivel de exposicion diario equivalente, valor limite de
exposicion, comma decimals).
Tests pin a hand-derivable oracle (two 4 h tasks at 85/75 dB give
LEX,8h = 75 + 10 lg 5.5 = 82.4 dB and the closed-form
U = 1.65 sqrt((101/121) 3.25) = 2.7 dB) read back from the PDF, the Annex D
84.3 dB / 3.2 dB example, and the 80/85/87 dB(A) boundary flips on the
displayed value. The rendered Annex D welders' example is committed under
.github/reports/ and embedded in the EN/ES guides and the GitHub docs.
* test: construct the report path outside the ISO 9612 pytest.raises blocks
Add ISO 9613-2 outdoor-propagation prediction reports via .report() (#332)
* Add ISO 9613-2 outdoor-propagation prediction reports via .report()
Add one-page PDF prediction fiches to the two outdoor-propagation result
types and a shared ISO 9613-2 family renderer.
OutdoorAttenuation.report() renders the octave-band attenuation breakdown
(divergence, atmospheric, ground and barrier terms with the total A), the
source power level and the downwind level LfT(DW), the attenuation-breakdown
plot and a boxed A-weighted downwind level LAT(DW) at the receiver. The sheet
is clearly labelled a prediction, not a measurement, and states the
meteorological and ground assumptions. A declared limit level via the metadata
requirement adds a PASS/FAIL verdict (a lower level is better). To carry the
composed level, outdoor_propagation_attenuation now accepts an optional
sound_power_level (with directivity_index, d_omega and c0).
BarrierInsertionLoss.report() renders the per-band insertion loss, the
insertion-loss spectrum and a boxed mean insertion loss over the octave bands.
Its basis line names the actual diffraction model used (the wave-theoretic
rigid-screen solution or the Kurze-Anderson closed form), a wave-acoustics
complement to the tabulated ISO 9613-2 screening term. A minimum required
insertion loss via requirement adds a PASS/FAIL verdict (higher is better).
Both fiches render in English and Spanish, register an example each under
.github/reports, are covered by structural and number-presence tests, and are
showcased in the Outdoor Sound Propagation guide.
* Regenerate API reference for the outdoor propagation report method
* Move the outdoor-propagation receiver level to a report-time SourceEmission
Keep outdoor_propagation_attenuation a pure attenuation calculation (its
signature is unchanged) and expose the downwind receiver level through a new
frozen SourceEmission object passed to OutdoorAttenuation.report(). When a
source emission is supplied the fiche lists the source power and the downwind
level and boxes the A-weighted downwind level at the receiver; without it the
fiche boxes the octave-band range of the total attenuation. The receiver-level
composition stays in the shared _compose_receiver_level helper.
Hoist the result and object construction out of the pytest.raises blocks in the
report tests so only the failing call is inside.
* Re-trigger CI for the outdoor-propagation report changes
* Restore Spanish diacritics and correct the composition-helper docstring
Add the missing accents to the two Spanish requirement comments in the outdoor
propagation guide, and update the receiver-level helper docstring: the level is
composed at report time from a SourceEmission, not stored on the attenuation
result, so drop the stale reference to the factory storing it.
* Drop the stray npm lockfile from the site
The site uses pnpm (pnpm-lock.yaml); an npm package-lock.json was generated
by accident during the site build and does not belong in the tree.
Add ISO 9613-2 outdoor-propagation prediction reports via .report() (#332)
* Add ISO 9613-2 outdoor-propagation prediction reports via .report()
Add one-page PDF prediction fiches to the two outdoor-propagation result
types and a shared ISO 9613-2 family renderer.
OutdoorAttenuation.report() renders the octave-band attenuation breakdown
(divergence, atmospheric, ground and barrier terms with the total A), the
source power level and the downwind level LfT(DW), the attenuation-breakdown
plot and a boxed A-weighted downwind level LAT(DW) at the receiver. The sheet
is clearly labelled a prediction, not a measurement, and states the
meteorological and ground assumptions. A declared limit level via the metadata
requirement adds a PASS/FAIL verdict (a lower level is better). To carry the
composed level, outdoor_propagation_attenuation now accepts an optional
sound_power_level (with directivity_index, d_omega and c0).
BarrierInsertionLoss.report() renders the per-band insertion loss, the
insertion-loss spectrum and a boxed mean insertion loss over the octave bands.
Its basis line names the actual diffraction model used (the wave-theoretic
rigid-screen solution or the Kurze-Anderson closed form), a wave-acoustics
complement to the tabulated ISO 9613-2 screening term. A minimum required
insertion loss via requirement adds a PASS/FAIL verdict (higher is better).
Both fiches render in English and Spanish, register an example each under
.github/reports, are covered by structural and number-presence tests, and are
showcased in the Outdoor Sound Propagation guide.
* Regenerate API reference for the outdoor propagation report method
* Move the outdoor-propagation receiver level to a report-time SourceEmission
Keep outdoor_propagation_attenuation a pure attenuation calculation (its
signature is unchanged) and expose the downwind receiver level through a new
frozen SourceEmission object passed to OutdoorAttenuation.report(). When a
source emission is supplied the fiche lists the source power and the downwind
level and boxes the A-weighted downwind level at the receiver; without it the
fiche boxes the octave-band range of the total attenuation. The receiver-level
composition stays in the shared _compose_receiver_level helper.
Hoist the result and object construction out of the pytest.raises blocks in the
report tests so only the failing call is inside.
* Re-trigger CI for the outdoor-propagation report changes
* Restore Spanish diacritics and correct the composition-helper docstring
Add the missing accents to the two Spanish requirement comments in the outdoor
propagation guide, and update the receiver-level helper docstring: the level is
composed at report time from a SourceEmission, not stored on the attenuation
result, so drop the stale reference to the factory storing it.
* Drop the stray npm lockfile from the site
The site uses pnpm (pnpm-lock.yaml); an npm package-lock.json was generated
by accident during the site build and does not belong in the tree.
Add ISO 9613-2 outdoor-propagation prediction reports via .report() (#332)
* Add ISO 9613-2 outdoor-propagation prediction reports via .report()
Add one-page PDF prediction fiches to the two outdoor-propagation result
types and a shared ISO 9613-2 family renderer.
OutdoorAttenuation.report() renders the octave-band attenuation breakdown
(divergence, atmospheric, ground and barrier terms with the total A), the
source power level and the downwind level LfT(DW), the attenuation-breakdown
plot and a boxed A-weighted downwind level LAT(DW) at the receiver. The sheet
is clearly labelled a prediction, not a measurement, and states the
meteorological and ground assumptions. A declared limit level via the metadata
requirement adds a PASS/FAIL verdict (a lower level is better). To carry the
composed level, outdoor_propagation_attenuation now accepts an optional
sound_power_level (with directivity_index, d_omega and c0).
BarrierInsertionLoss.report() renders the per-band insertion loss, the
insertion-loss spectrum and a boxed mean insertion loss over the octave bands.
Its basis line names the actual diffraction model used (the wave-theoretic
rigid-screen solution or the Kurze-Anderson closed form), a wave-acoustics
complement to the tabulated ISO 9613-2 screening term. A minimum required
insertion loss via requirement adds a PASS/FAIL verdict (higher is better).
Both fiches render in English and Spanish, register an example each under
.github/reports, are covered by structural and number-presence tests, and are
showcased in the Outdoor Sound Propagation guide.
* Regenerate API reference for the outdoor propagation report method
* Move the outdoor-propagation receiver level to a report-time SourceEmission
Keep outdoor_propagation_attenuation a pure attenuation calculation (its
signature is unchanged) and expose the downwind receiver level through a new
frozen SourceEmission object passed to OutdoorAttenuation.report(). When a
source emission is supplied the fiche lists the source power and the downwind
level and boxes the A-weighted downwind level at the receiver; without it the
fiche boxes the octave-band range of the total attenuation. The receiver-level
composition stays in the shared _compose_receiver_level helper.
Hoist the result and object construction out of the pytest.raises blocks in the
report tests so only the failing call is inside.
* Re-trigger CI for the outdoor-propagation report changes
* Restore Spanish diacritics and correct the composition-helper docstring
Add the missing accents to the two Spanish requirement comments in the outdoor
propagation guide, and update the receiver-level helper docstring: the level is
composed at report time from a SourceEmission, not stored on the attenuation
result, so drop the stale reference to the factory storing it.
* Drop the stray npm lockfile from the site
The site uses pnpm (pnpm-lock.yaml); an npm package-lock.json was generated
by accident during the site build and does not belong in the tree.
Add ISO 9613-2 outdoor-propagation prediction reports via .report() (#332)
* Add ISO 9613-2 outdoor-propagation prediction reports via .report()
Add one-page PDF prediction fiches to the two outdoor-propagation result
types and a shared ISO 9613-2 family renderer.
OutdoorAttenuation.report() renders the octave-band attenuation breakdown
(divergence, atmospheric, ground and barrier terms with the total A), the
source power level and the downwind level LfT(DW), the attenuation-breakdown
plot and a boxed A-weighted downwind level LAT(DW) at the receiver. The sheet
is clearly labelled a prediction, not a measurement, and states the
meteorological and ground assumptions. A declared limit level via the metadata
requirement adds a PASS/FAIL verdict (a lower level is better). To carry the
composed level, outdoor_propagation_attenuation now accepts an optional
sound_power_level (with directivity_index, d_omega and c0).
BarrierInsertionLoss.report() renders the per-band insertion loss, the
insertion-loss spectrum and a boxed mean insertion loss over the octave bands.
Its basis line names the actual diffraction model used (the wave-theoretic
rigid-screen solution or the Kurze-Anderson closed form), a wave-acoustics
complement to the tabulated ISO 9613-2 screening term. A minimum required
insertion loss via requirement adds a PASS/FAIL verdict (higher is better).
Both fiches render in English and Spanish, register an example each under
.github/reports, are covered by structural and number-presence tests, and are
showcased in the Outdoor Sound Propagation guide.
* Regenerate API reference for the outdoor propagation report method
* Move the outdoor-propagation receiver level to a report-time SourceEmission
Keep outdoor_propagation_attenuation a pure attenuation calculation (its
signature is unchanged) and expose the downwind receiver level through a new
frozen SourceEmission object passed to OutdoorAttenuation.report(). When a
source emission is supplied the fiche lists the source power and the downwind
level and boxes the A-weighted downwind level at the receiver; without it the
fiche boxes the octave-band range of the total attenuation. The receiver-level
composition stays in the shared _compose_receiver_level helper.
Hoist the result and object construction out of the pytest.raises blocks in the
report tests so only the failing call is inside.
* Re-trigger CI for the outdoor-propagation report changes
* Restore Spanish diacritics and correct the composition-helper docstring
Add the missing accents to the two Spanish requirement comments in the outdoor
propagation guide, and update the receiver-level helper docstring: the level is
composed at report time from a SourceEmission, not stored on the attenuation
result, so drop the stale reference to the factory storing it.
* Drop the stray npm lockfile from the site
The site uses pnpm (pnpm-lock.yaml); an npm package-lock.json was generated
by accident during the site build and does not belong in the tree.
Noise-control performance reports via .report() (#331)
* Add noise-control performance reports via .report()
Add a one-page PDF .report() fiche to the three noise_control result
types, each laid out with a per-band table beside the result's own plot,
a boxed single-number performance figure and an optional PASS/FAIL
verdict:
- EnclosureResult: machine-enclosure insertion loss (Bies, Hansen &
Howard, section 7.4.2). The table lists the supplied panel transmission
loss R, the interior build-up correction C and the net insertion loss
IL = R - C; the boxed figure is the mean insertion loss with the
external and internal surface areas. verbose=True adds the interior
room constant column. A declared minimum passes when the mean meets it.
- ReactiveSilencerResult: reactive-silencer transmission loss (Munjal
Eq. (3.27); Bies sections 8.8-8.9). The table lists the transmission
loss TL and, when end impedances were given, the insertion loss IL; the
boxed figure is the mean transmission loss with the peak and the device
kind. A declared minimum passes when the mean meets it.
- HvacSpectrumResult: HVAC duct-noise spectrum (Bies Chapter 8; VDI
2081-1). A regenerated-noise spectrum boxes the A-weighted sound power
level with the overall total (lower is better); an attenuation spectrum
boxes the mean attenuation (more is better). verbose=True adds the
A-weighting correction and A-weighted band-level columns.
The three renderers share a two-panel skeleton in
_report/_noise_control_fiche.py and reuse the sound-power table builder,
band labels and header grid. Each accepts an optional metadata header,
states its method basis and renders in English or Spanish.
Register one committed example per fiche under .github/reports/, add
structural and clean-room number-presence tests (EN and ES), and update
the CHANGELOG and the regenerated API reference.
* Address SonarCloud findings on the noise-control renderers
Reduce render_noise_control_fiche below the parameter-count threshold by
fixing the two-panel split widths internally (the three renderers never
overrode them), and lift the HVAC verdict symbol/unit selection out of a
nested conditional into an explicit if/elif/else. No change to rendered
output; the committed example fiches are unaffected.
* Round the requirement to display precision and fit the verbose table
Compare the declared requirement at the same one-decimal precision as the
measured value in the noise-control verdict, so the printed comparison can
never contradict the verdict at the boundary. Also trim the verbose
enclosure table columns to sum to the 64 mm left panel width.
Noise-control performance reports via .report() (#331)
* Add noise-control performance reports via .report()
Add a one-page PDF .report() fiche to the three noise_control result
types, each laid out with a per-band table beside the result's own plot,
a boxed single-number performance figure and an optional PASS/FAIL
verdict:
- EnclosureResult: machine-enclosure insertion loss (Bies, Hansen &
Howard, section 7.4.2). The table lists the supplied panel transmission
loss R, the interior build-up correction C and the net insertion loss
IL = R - C; the boxed figure is the mean insertion loss with the
external and internal surface areas. verbose=True adds the interior
room constant column. A declared minimum passes when the mean meets it.
- ReactiveSilencerResult: reactive-silencer transmission loss (Munjal
Eq. (3.27); Bies sections 8.8-8.9). The table lists the transmission
loss TL and, when end impedances were given, the insertion loss IL; the
boxed figure is the mean transmission loss with the peak and the device
kind. A declared minimum passes when the mean meets it.
- HvacSpectrumResult: HVAC duct-noise spectrum (Bies Chapter 8; VDI
2081-1). A regenerated-noise spectrum boxes the A-weighted sound power
level with the overall total (lower is better); an attenuation spectrum
boxes the mean attenuation (more is better). verbose=True adds the
A-weighting correction and A-weighted band-level columns.
The three renderers share a two-panel skeleton in
_report/_noise_control_fiche.py and reuse the sound-power table builder,
band labels and header grid. Each accepts an optional metadata header,
states its method basis and renders in English or Spanish.
Register one committed example per fiche under .github/reports/, add
structural and clean-room number-presence tests (EN and ES), and update
the CHANGELOG and the regenerated API reference.
* Address SonarCloud findings on the noise-control renderers
Reduce render_noise_control_fiche below the parameter-count threshold by
fixing the two-panel split widths internally (the three renderers never
overrode them), and lift the HVAC verdict symbol/unit selection out of a
nested conditional into an explicit if/elif/else. No change to rendered
output; the committed example fiches are unaffected.
* Round the requirement to display precision and fit the verbose table
Compare the declared requirement at the same one-decimal precision as the
measured value in the noise-control verdict, so the printed comparison can
never contradict the verdict at the boundary. Also trim the verbose
enclosure table columns to sum to the 64 mm left panel width.
Add reverberation-time report fiches via .report() (#336)
Add a one-page PDF .report() to the two reverberation result types.
ReverberationModelResult.report() renders a design-stage prediction of the
reverberation time by the five classical statistical-acoustics models (Sabine,
Eyring, Millington-Sette, Fitzroy and Arau-Puchades): a per-band table with one
reverberation-time column per model beside the model comparison plot, and a
boxed mid-frequency reverberation time from Arau-Puchades with the per-model
spread alongside. It is labelled a prediction, not a measurement: the five
models bracket the reverberation time likely to occur, so no PASS/FAIL verdict
is emitted; a target reverberation time is printed as a reference line only.
ReverberationResult.report() renders an enclosed-space characterisation
(EN 12354-6:2003): a per-band table of the equivalent sound absorption area A
and the reverberation time T beside the reverberation-time plot, the room
volume and object fraction in the header, and a boxed mid-frequency
reverberation time with the mid-frequency absorption area alongside. A target
reverberation time is likewise printed as a reference line without a verdict,
since a room reverberation time is a target range rather than a strictly
higher/lower-is-better quantity.
Both renderers live in a shared _report/reverberation.py module (shared
mid-frequency descriptor, time formatting, octave-band table and header grid
helpers). Add the English and Spanish fixed strings, one committed example
fiche per result under .github/reports/, structural and value-presence tests
in English and Spanish, and the guide sections in both languages. Regenerate
the API reference.
Add reverberation-time report fiches via .report() (#336)
Add a one-page PDF .report() to the two reverberation result types.
ReverberationModelResult.report() renders a design-stage prediction of the
reverberation time by the five classical statistical-acoustics models (Sabine,
Eyring, Millington-Sette, Fitzroy and Arau-Puchades): a per-band table with one
reverberation-time column per model beside the model comparison plot, and a
boxed mid-frequency reverberation time from Arau-Puchades with the per-model
spread alongside. It is labelled a prediction, not a measurement: the five
models bracket the reverberation time likely to occur, so no PASS/FAIL verdict
is emitted; a target reverberation time is printed as a reference line only.
ReverberationResult.report() renders an enclosed-space characterisation
(EN 12354-6:2003): a per-band table of the equivalent sound absorption area A
and the reverberation time T beside the reverberation-time plot, the room
volume and object fraction in the header, and a boxed mid-frequency
reverberation time with the mid-frequency absorption area alongside. A target
reverberation time is likewise printed as a reference line without a verdict,
since a room reverberation time is a target range rather than a strictly
higher/lower-is-better quantity.
Both renderers live in a shared _report/reverberation.py module (shared
mid-frequency descriptor, time formatting, octave-band table and header grid
helpers). Add the English and Spanish fixed strings, one committed example
fiche per result under .github/reports/, structural and value-presence tests
in English and Spanish, and the guide sections in both languages. Regenerate
the API reference.