The settings the scalogram is computed with, as a table beside it.
Four values are set here: the bottom and top of the frequency range,
the lines per octave, and the number of cycles under the wavelet, which
sets how it trades time resolution against frequency resolution. Three
more are shown that follow from them: the width of the cone of
influence at the bottom of the range, the frequency resolution there,
and the number of lines.
The record is not chosen here. The scalogram uses the record selected
in the project tree, as every other view does, and this panel holds
only the settings the tree cannot.
The derived values are shown because the scalogram is the one reading
in this toolset where the settings decide whether most of the picture
is artifact. Ask for 1 Hz on a two-second record and the bottom of the
axis is all cone of influence, and the picture still looks plausible
while it says nothing about the measurement. So the panel says so before
the transform runs, with a note under the table when the cone at the
lowest frequency covers a third of the record or more.
Nothing here computes the transform. The panel shows the settings and
reports when they change, as the averaging panel does.
Classes:
| Name |
Description |
WaveletPanel |
The scalogram's settings. Each edit is reported on changed as
|
Classes
WaveletPanel
WaveletPanel(parent: QWidget | None = None)
Bases: QWidget
The scalogram's settings. Each edit is reported on changed as
the whole settings dict: 'low' and 'high' in Hz, 'per_octave' and
'omega0'.
Methods:
| Name |
Description |
show_history |
Show the settings for a time history.
|
suggested |
The default settings for this record.
|
settings |
The settings the editors show now, as a dict: 'low' and 'high'
|
Source code in src/visualdynamics/gui/wavelet_panel.py
| def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.sample_rate: float = 1.0
self.samples: int = 0
self.duration: float = 0.0
#: set while the panel writes to its own editors, so restating a
#: clamped value does not read as a fresh edit
self._loading = False
self.title: QLabel = QLabel('Wavelet')
grid = panel_grid(self, self.title)
self.low_box: DoubleSpinBox = DoubleSpinBox()
self.low_box.setDecimals(2)
self.low_box.setSuffix(' Hz')
self.low_box.setToolTip(
'The bottom of the frequency axis. Low frequencies use long '
'wavelets, so this is what decides how much of the picture '
'is cone of influence')
self.high_box: DoubleSpinBox = DoubleSpinBox()
self.high_box.setDecimals(2)
self.high_box.setSuffix(' Hz')
self.high_box.setToolTip(
'The top of the frequency axis. Defaults to everything the '
'record carries; the reading stays true to a fraction of a '
'percent right up against Nyquist')
self.per_octave_box: SpinBox = SpinBox()
self.per_octave_box.setRange(1, 96)
self.per_octave_box.setToolTip(
'Lines per octave. The axis is logarithmic because a '
"wavelet's bandwidth is a constant fraction of its "
'frequency — evenly spaced lines would crowd at the top')
self.omega_box: DoubleSpinBox = DoubleSpinBox()
self.omega_box.setDecimals(1)
self.omega_box.setRange(3.0, 30.0)
self.omega_box.setSingleStep(1.0)
self.omega_box.setToolTip(
'Cycles under the wavelet, which is the trade itself: low '
'resolves when and blurs what, high resolves what and '
'blurs when. Six is conventional, and near the lowest value '
'for which the transform is admissible at all')
rows = (('From', self.low_box),
('To', self.high_box),
('Per octave', self.per_octave_box),
('Cycles', self.omega_box))
add_settings(grid, rows)
add_rule(grid, len(rows) + 1)
self.derived: dict[str, QLabel] = {}
derived = (('cone', 'Cone at bottom'), ('resolves', 'Resolves'),
('transforms', 'Lines'))
for key, (_name, value) in add_derived(grid, derived,
len(rows) + 2).items():
self.derived[key] = value
self.note: QLabel = QLabel()
self.note.setWordWrap(True)
self.note.setEnabled(False)
grid.addWidget(self.note, len(rows) + 2 + len(derived), 0, 1, 2)
grid.setRowStretch(len(rows) + 3 + len(derived), 1)
commit_on_enter(self.low_box, self.high_box, self.per_octave_box,
self.omega_box)
for editor in (self.low_box, self.high_box, self.per_octave_box,
self.omega_box):
editor.valueChanged.connect(self._edited)
|
Methods:
show_history
show_history(history: TimeHistory, settings: dict[str, Any] | None = None) -> None
Show the settings for a time history.
settings is the scalogram's settings on that history, and when
it is None the panel opens on suggested. The limits every value
is clamped to come from this history's sample rate, not from the
values the boxes held for the last record, and the range is
clamped as a pair, so it keeps at least an octave of width.
Source code in src/visualdynamics/gui/wavelet_panel.py
| def show_history(self, history: TimeHistory,
settings: dict[str, Any] | None = None) -> None:
"""Show the settings for a time history.
`settings` is the scalogram's settings on that history, and when
it is None the panel opens on `suggested`. The limits every value
is clamped to come from this history's sample rate, not from the
values the boxes held for the last record, and the range is
clamped as a pair, so it keeps at least an octave of width.
"""
self.sample_rate = history.sample_rate
self.samples = len(history.abscissa)
self.duration = self.samples / self.sample_rate if self.sample_rate \
else 0.0
settled = dict(self.suggested()) if settings is None else dict(settings)
# through the clamp, not straight into the boxes: a range tuned
# on one record and carried to a slower one arrives above this
# Nyquist, and each box clamping on its own would settle both
# ends onto the same number — a range of no width, which is not
# a range the derived rows can be computed from
settled = self._clamped_against(settled, history.sample_rate)
self._loading = True
try:
self._apply_limits()
self.low_box.setValue(settled['low'])
self.high_box.setValue(settled['high'])
self.per_octave_box.setValue(settled['per_octave'])
self.omega_box.setValue(settled['omega0'])
finally:
self._loading = False
self._restate(self.settings())
|
suggested
suggested() -> dict[str, Any]
The default settings for this record.
The range is core.wavelet.default_range: the top at 0.98 of
Nyquist, and the bottom at eight cycles over the record's
duration, so the longest wavelets still fit inside the record and
the bottom of the range is not mostly cone of influence. Lines per
octave and cycles are the defaults core.wavelet.PER_OCTAVE and
core.wavelet.OMEGA0.
Source code in src/visualdynamics/gui/wavelet_panel.py
| def suggested(self) -> dict[str, Any]:
"""The default settings for this record.
The range is `core.wavelet.default_range`: the top at 0.98 of
Nyquist, and the bottom at eight cycles over the record's
duration, so the longest wavelets still fit inside the record and
the bottom of the range is not mostly cone of influence. Lines per
octave and cycles are the defaults `core.wavelet.PER_OCTAVE` and
`core.wavelet.OMEGA0`.
"""
low, high = wavelet.default_range(self.sample_rate or 1.0,
self.duration)
return {'low': low, 'high': high,
'per_octave': wavelet.PER_OCTAVE, 'omega0': wavelet.OMEGA0}
|
settings
settings() -> dict[str, Any]
The settings the editors show now, as a dict: 'low' and 'high'
in Hz, 'per_octave' and 'omega0'.
Source code in src/visualdynamics/gui/wavelet_panel.py
| def settings(self) -> dict[str, Any]:
"""The settings the editors show now, as a dict: 'low' and 'high'
in Hz, 'per_octave' and 'omega0'."""
return {'low': self.low_box.value(),
'high': self.high_box.value(),
'per_octave': self.per_octave_box.value(),
'omega0': self.omega_box.value()}
|
Functions: