pyFDN.MatchCumulativeEnergy#

class pyFDN.MatchCumulativeEnergy(target, *, window=1024, hop=None, power=0.5, floor_db=-100.0, frequency='descending')[source]#

Doubly-cumulated energy against a reference – decay and colour, no bands.

Takes the short-time power spectrum of both signals and integrates it twice, backwards in time and downwards in frequency:

\[E[f, t] = \sum_{t' \ge t} \; \sum_{f' \ge f} \big| S[f', t'] \big|^2\]

so \(E[f, t]\) is the energy still to come after time \(t\) in the band above \(f\), and \(E[0, 0]\) is the total energy. The loss is the RMS difference of the two surfaces after a compressive power.

Cumulating twice carries both things a fit needs: read down the \(t = 0\) edge and you have the integrated spectrum (the colour), read across the \(f = 0\) edge and you have the full-band decay, and the interior ties them together band by band – without the arbitrary quantization of octave bands. The compressive power (rather than a logarithm) keeps the surface’s six-orders-of-magnitude dynamic range visible to the loss while staying bounded. See the design note for the reasoning behind the defaults.

Parameters:
  • target (Any) – Reference IR, shape (n_samples,), (n_samples, n_out) or (n_samples, n_out, n_in). Zero-padded or truncated to the model’s nfft.

  • window (int) – STFT window and hop in samples. Unlike MatchEnergyDecay this loss needs no window long enough to resolve an octave – it never splits into octaves – so the default is short.

  • hop (int | None) – STFT window and hop in samples. Unlike MatchEnergyDecay this loss needs no window long enough to resolve an octave – it never splits into octaves – so the default is short.

  • power (float) – The compression exponent \(p \in (0, 1]\) applied to the normalized surface. 1 is no compression (raw energies), 0.5 the default, 0.25 stronger.

  • floor_db (float) – Hard floor on the normalized surface, in energy dB below the reference’s total energy. It bounds the gradient of the compression near zero and keeps the fit off the numerical floor of the render; clamp means no gradient flows from anything below it.

  • frequency (str) – Which way the frequency cumulation runs, and with it the loss’s balance between the ends of the spectrum. The default "descending" (the plain reading of “energy above this frequency”) gives a low band little gradient; "both" scores both directions and averages, and is what to reach for when the fit has to find a decay it was not given. See the design note for the comparison.

Notes

The surface is normalized by the reference’s total energy, one constant – not each surface by its own – so a level error is a genuine error of the loss rather than something it is blind to. Fitting shape only, with the level left to another term, is the one thing this loss deliberately does not do.

__init__(target, *, window=1024, hop=None, power=0.5, floor_db=-100.0, frequency='descending')[source]#

Methods

__init__(target, *[, window, hop, power, ...])

check(model)

Preflight against the model it will train, before the first step.

terms()

Flatten into (weight, loss) leaves.

Attributes

name

Short label, used as the key in pyFDN.TrainLog.loss_log.

check(model)[source]#

Preflight against the model it will train, before the first step.

Override to reject or warn about a model this loss cannot be fit on – raising here beats a silently useless optimization run. Most losses place no demands on the model, hence the no-op default.

Return type:

None