cardioception.PAT.engine.PhaseEngine#

class cardioception.PAT.engine.PhaseEngine(source, player, mode, latency_bias=0.05, audio_lead=0.05, min_tone_gap=0.3, outlet=None, clock=None)[source]#

Play one tone per heartbeat at the phase set with the dial.

Call start_trial(), then poll() every frame and nudge() whenever the dial moves; stop_tones() at the press, and end_trial() for the trial’s row. See the module docstring for the scheduling rule.

The dial is kept as a phase in degrees in relative mode (it wraps at 360) and as a delay in ms in absolute mode (it wraps at the anticipated period, and the delay used for a beat is clamped to that beat’s period). In absolute mode a dial left beyond a period that has since shrunk reads, in phase_deg, delay_ms and the markers, as the clamped delay the scheduler plays, and the next turn starts from there. Each trial starts with the dial at the trial’s start phase.

With a virtual source (source.virtual true, the exteroceptive task) each beat also gets a vibration burst at r_time - latency_bias, anchor virtual.

Parameters
source

A BeatSource.

player

A TonePlayer, or anything with schedule(when, kind) and poll_onsets().

mode

"relative" or "absolute".

latency_bias

Seconds subtracted from every target (see the module docstring).

audio_lead

Least time, in seconds, between scheduling a sound and its target.

min_tone_gap

A tone less than this many seconds after the previous one is skipped.

outlet

A pylsl StreamOutlet of one string channel for the JSON markers, or None for none.

clock

The clock beats and tones are timed on; pylsl.local_clock by default.

__init__(source, player, mode, latency_bias=0.05, audio_lead=0.05, min_tone_gap=0.3, outlet=None, clock=None)[source]#

Methods

__init__(source, player, mode[, ...])

close()

Stop the source and release the audio device.

end_trial([on_wait])

The trial's row of final.txt (all but the confidence columns).

idle_poll()

Pull and detect beats, push their markers, collect onsets; no tones.

mark(kind[, stamp])

Push one JSON marker {"kind": kind, ...}.

nudge(notches, gain_deg, gain_ms)

Turn the dial by notches (negative turns back).

poll()

Pull new beats, schedule their tones, collect onsets.

start_trial(trial, start_phase_deg[, block])

Set the dial to start_phase_deg and start playing tones.

stop_tones([reason])

The trial stops: no more tones are scheduled.

Attributes

delay_ms

The dial as ms after the R-wave, clamped to the anticipated period in absolute mode; NaN in relative mode while no period is known.

phase_deg

The dial as a phase, degrees in [0, 360); NaN in absolute mode while no period is known.

tones

Every tone and vibration scheduled so far, as tones.txt rows.

counts

Tones of the current trial: real, predicted, skipped.