visualdynamics.plot.tracking_filter¶
tracking_filter
¶
Drawing a tracking filter's band on the record it is applied to.
A level read through a tracking filter depends on a band that moves with the drive frequency. This view draws the band where it is applied, in the same way the averaging frames are drawn on the record they are cut from and a filter preview is drawn over the time history it filters. It shows one tone of one channel: the record at the top, its scalogram below, and beside the scalogram the band's magnitude at one instant.
The record is drawn gray and the band's output, the waveform it
passes, is drawn over it in color, as in the filter preview, because
the passed waveform is what is being judged. The color is the theme's
filter_preview (magenta) and not the channel's own color, which is
the one difference from the filter preview. The same color is used for
the band's corridor, its shape and its weight on the record, so that on
all three panels magenta means the filter and nothing else is drawn in
it.
The time-frequency picture is the scalogram of core.wavelet, drawn by
plot.scalogram.scalogram_image with time across, log frequency up and
the cone of influence shaded. Its rows are evenly spaced in log
frequency, the axis on which a proportional band has a constant width.
Two settings differ from the scalogram view. First, the color is the
magnitude in dB below the picture's largest value, over COLOR_RANGE.
On the scalogram's linear scale, a noise floor a fifth of the tone's
amplitude spread over the whole band is a few percent of the color bar
and is drawn black, and this picture has to show the noise in order to
show the band keeping it out. Second, the wavelet is narrower in
frequency: OMEGA0 is twelve cycles, against the scalogram's six, so
the tone's ridge is narrower than the common bands. At six cycles the
ridge is 14 % either side of the tone at -3 dB, more than half of a
50 % band's 25 %; at twelve it is 7 %. A band narrower than that, such
as 10 % proportional or a few hertz fixed, is narrower than the picture
can resolve for a moving tone, and its corridor is drawn inside the
ridge. The cost is resolution in time, because a longer wavelet spreads
a sweep along the time axis. At one octave per second the drive moves
about 7 % within the wavelet's width at 20 Hz, as much as the wavelet
resolves, and a fifth of that at 100 Hz, so the ridge stays narrow from
the bottom of a sweep up.
The band is drawn over the picture as a corridor that follows the sweep. Its edges are the drive plus and minus half the bandwidth, the -3 dB points, drawn as dashed lines over a wider line in the background color. The dashes let a reader who cannot tell magenta from the colormap still tell the line from the image, and the wider line under them keeps a thin line visible over every color of the colormap. A proportional band has a constant width on the log axis and is drawn as a pair of lines parallel to the ridge. A fixed band has a constant width in hertz, so it is wide at the bottom of the axis and narrow at the top. Showing that difference is the purpose of the picture.
The band's magnitude at the cursor (SineTracking.response) is drawn
beside the picture with frequency up, on an axis linked to the
picture's, so the -3 dB edges of the shape line up with the corridor's
edges, and the drive and its harmonics are marked at the same heights
on both. The drive is inside the band, where the shape is 0 dB; a
harmonic is outside it, where the shape gives its rejection. The drive
is marked with a circle and a harmonic with a triangle, each filled
with the background color and outlined in the foreground color, so
they can be seen over any color of the colormap.
The band's output at an instant is the record before that instant
weighted by the low-pass filter's impulse response
(SineTracking.weighting). That weight is shaded on the record,
reaching back from the cursor and fading as the weight decreases, in
the same way the averaging band's shading shows the weight each part of
the record carries in a frame. Its length is the settling time given in
the readout: a wide band's weight is short, a narrow band's reaches
back across a change in level, and the envelope of the passed waveform
follows that change over the same time. The shading is clipped at zero
where the impulse response is negative. For the default fourth-order
filter the negative part is about a sixth of the peak, and it is the
reason the band overshoots a step.
One setting is drawn per view. Several corridors over one picture, each with its own shape beside it, would cover the image they are read against, so two settings are two calls placed side by side. A strip of the level under the record is left out for the same reason: the envelope of the passed waveform is the 'filtered' reading and is already drawn at every sample.
In the application the cursor can be dragged along either time axis,
and the shape, the marks, the weight and the readout follow it. Each is
computed in closed form, so the redraw is immediate. In a script the
cursor is set by the cursor argument or by
TrackingFilterView.set_cursor.
Classes:
| Name | Description |
|---|---|
TrackingFilterView |
The items |
Functions:
| Name | Description |
|---|---|
default_range |
The picture's frequency range in Hz, as (low, high). |
build_tracking_filter |
Draw one tone's tracking band on its record and return the view. |
Classes¶
TrackingFilterView
¶
TrackingFilterView(record_plot: Any, picture: Any, shape: Any, readout: Any, waveform: Any, frequencies: ndarray, harmonics: Sequence[int], colors: Mapping[str, str], heights: tuple[float, float], interactive: bool)
The items build_tracking_filter draws, and the cursor that moves them.
The view owns every item it adds. set_cursor redraws the shape,
the marks, the weight and the readout for a new instant. After each
call, cursor, drive_hz, bandwidth_hz, edges_hz,
harmonic_db and text hold what was read there.
Methods:
| Name | Description |
|---|---|
set_cursor |
Move the cursor to |
Source code in src/visualdynamics/plot/tracking_filter.py
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | |
Methods:¶
set_cursor
¶
Move the cursor to seconds and redraw what is read there.
seconds is on the record's clock, and the cursor is held
inside the tone's span. Returns the time it was placed at, in
seconds.
Source code in src/visualdynamics/plot/tracking_filter.py
Functions:¶
default_range
¶
The picture's frequency range in Hz, as (low, high).
From an octave below the lowest drive frequency up to 1.5 times the
highest harmonic marked, or 1.5 times the band's top edge if that is
higher, and no higher than 0.45 times sample_rate.
Source code in src/visualdynamics/plot/tracking_filter.py
build_tracking_filter
¶
build_tracking_filter(layout: Any, history: Any, waveform: Any, *, cursor: float | None = None, span: tuple[float, float] | None = None, harmonics: Sequence[int] = HARMONICS, low: float | None = None, high: float | None = None, omega0: float = OMEGA0, unit_system: Any = None, theme: Any = None, interactive: bool = True) -> TrackingFilterView
Draw one tone's tracking band on its record and return the view.
waveform is the result of core.sine_tracking.track_waveform for
channel waveform.dof of history. The record and the passed
waveform are drawn in row 0, the picture and the corridor in row 2
with the shape beside it in column 1, the readout above the shape,
and the legend under the picture. cursor is a time in seconds on
the record's clock, the middle of the tone's span by default; span
is the (start, stop) the time axes show, the whole record by
default. harmonics are the multiples of the drive frequency that
are marked, the third by default. low and high are the
picture's frequency range in Hz (default_range when omitted), and
omega0 is the wavelet's width parameter (OMEGA0). With
interactive False the cursor cannot be dragged.
Source code in src/visualdynamics/plot/tracking_filter.py
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | |