rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
tone.c File Reference

ESC tones from the edges of one motor phase. More...

#include "tone.h"
#include <string.h>

Data Structures

struct  ratio_t

Functions

void tone_cfg_defaults (tone_cfg_t *c, uint32_t tick_hz)
 Defaults for a clock of tick_hz: 8000us windows, 400 to 6500Hz, carrier from 7kHz, 500ns glitch, 8000ns hold-off, 3000us gap, 8% split, 3 periods a beep, 2 a window.
static uint64_t div_up (uint64_t a, uint64_t b)
 a / b rounded up.
uint64_t tone_ns_ticks (uint64_t tick_hz, uint64_t ns)
 ns as ticks of a tick_hz clock, rounded up: the conversion of every time setting.
static uint64_t ns_ticks (uint32_t tick_hz, uint64_t ns)
 Convert nanoseconds to ticks, rounded up.
bool tone_init (tone_t *d, const tone_cfg_t *c)
 Start from nothing.
static float hz_of (const tone_t *d, uint32_t n, uint64_t ticks)
 n periods over ticks, in Hz; 0 for none.
static ratio_t ratio (uint64_t s, uint64_t n)
 Make a mean from a sum and a count.
static uint64_t ratio_diff (ratio_t x, ratio_t y, bool *x_more)
 x - y, scaled by both counts: x.s * y.n - y.s * x.n, as its size and whether x is the larger.
static bool off_by_more (ratio_t x, ratio_t y, uint32_t pct, uint32_t den)
 x lies more than pct / den percent from y, relative to y: |x
static ratio_t beep_mean (const tone_t *d)
 The beep's mean, as a sum over a count.
static uint64_t carrier (const tone_t *d)
 The carrier period, ticks; 0 with no carrier seen.
static bool in_band (const tone_t *d, ratio_t m)
 A mean period inside the tone range: per_min <= s / n <= per_max.
static void window_finish (tone_t *d)
 Close the window under way and publish it.
static void window_open (tone_t *d, uint64_t index)
 Open the window with an index.
static void windows_to (tone_t *d, uint64_t t)
 Close every window that ends at or before t.
static void emit (tone_t *d, uint64_t end)
 Queue the beep that ends at a tick, if it passes the checks.
static void beep_open (tone_t *d, uint64_t start, uint8_t flags)
 Open a beep at a tick.
static void commit (tone_t *d, uint32_t n, ratio_t ref)
 The oldest n periods waiting join the beep under way: each is a burst, and an in-range one near the beep's mean (or, before the beep has one, near ref) is part of the mean.
static ratio_t block_pitch (const tone_t *d)
 The block's pitch: the mean of its in-range periods within TONE_OUTLIER_PCT of their median, as a sum over a count.
static uint32_t on_side (const tone_t *d, ratio_t bm, ratio_t m, uint32_t pct)
 The block's periods that lie more than half of pct from m on the side of bm.
static bool moved (const tone_t *d, ratio_t bm, ratio_t m, uint32_t pct)
 The block's pitch bm lies more than pct from the beep's mean m, and all but one of the block's periods lie more than half that on the same side.
static uint64_t dist (uint64_t p, ratio_t x)
 |p - x|, scaled by x.n.
static void block_check (tone_t *d)
 A full block: the oldest period joins the beep, or the pitch has moved.
static void period (tone_t *d, uint64_t p, uint64_t s_open, uint64_t e_before)
 Count one period between two burst starts.
static void run_end (tone_t *d)
 The run ends at its last edge.
static void burst (tone_t *d, uint64_t t, uint64_t e_before)
 Count one burst, opening a run when none is under way.
static bool time_to (tone_t *d, uint64_t t)
 Time reaches t: windows close, and a silence ends the run.
static void rise (tone_t *d, uint64_t t, uint64_t e_before)
 Handle a rising edge: decide whether it starts a burst.
void tone_edge (tone_t *d, uint64_t t, bool level)
 One edge at tick t, level after it.
void tone_feed (tone_t *d, const tone_edge_t *e, size_t n)
 n edges in time order.
void tone_advance (tone_t *d, uint64_t now)
 No edge up to tick now: a silence ends a beep, a window closes.
void tone_flush (tone_t *d)
 End the beep under way at its last edge, as a silence would, and forget the line's level, so the first rise after it starts a run: the caller's edges have a hole (a buffer overrun) or the recording ends.
bool tone_window (const tone_t *d, tone_window_t *w)
 The last window finished; false before the first.
bool tone_next_beep (tone_t *d, tone_beep_t *b)
 Take the oldest beep reported; false with none waiting.
bool tone_busy (const tone_t *d)
 A run of bursts is under way.
const tone_stats_t * tone_stats (const tone_t *d)
 The counters of the detector.
uint64_t tone_ticks_us (const tone_t *d, uint64_t ticks)
 ticks of the detector's clock in microseconds, rounded down.
void tone_holdoff_init (tone_holdoff_t *h, uint32_t tick_hz, uint32_t hold_ns)
 hold_ns of a clock of tick_hz, rounded up to whole ticks; the line starts low.
size_t tone_holdoff_edge (tone_holdoff_t *h, uint64_t t, bool level, tone_edge_t out[2])
 One edge at t; the edges reported, 0 to 2, into out in time order: a held fall whose low lasted the hold-off, then the rise.
size_t tone_holdoff_advance (tone_holdoff_t *h, uint64_t now, tone_edge_t out[1])
 No edge up to now: a held fall whose low has lasted the hold-off by then, into out; 0 or 1.
uint64_t tone_holdoff_horizon (const tone_holdoff_t *h, uint64_t now)
 now less the hold-off, at least 0, and never before the latest edge handed out: every edge before it is out, and it never runs backward, so advancing the detector to it after feeding the edges out keeps the detector's time in order.

Detailed Description

ESC tones from the edges of one motor phase.

The rules are in tone.h.

SPDX-License-Identifier: MIT

Function Documentation

◆ beep_mean()

ratio_t beep_mean ( const tone_t * d)
static

The beep's mean, as a sum over a count.

Parameters
dDetector state.
Returns
The mean of the beep's periods so far.

◆ beep_open()

void beep_open ( tone_t * d,
uint64_t start,
uint8_t flags )
static

Open a beep at a tick.

Parameters
dDetector state.
startTick of the beep's first rise.
flagsFlags of the beep, tone_beep_flag_t bits.

◆ block_check()

void block_check ( tone_t * d)
static

A full block: the oldest period joins the beep, or the pitch has moved.

A beep with a mean of TONE_BLOCK periods or more splits where the new pitch begins, when the block moved by split_pct. One with fewer keeps its start and starts its mean again, when the block moved by TONE_OUTLIER_PCT: its first periods came before the carrier was known, and every period after them would be an outlier to them.

◆ block_pitch()

ratio_t block_pitch ( const tone_t * d)
static

The block's pitch: the mean of its in-range periods within TONE_OUTLIER_PCT of their median, as a sum over a count.

The median keeps one stray period – a burst missed, a stuck line's rise – out of the mean; the mean of neighbours keeps a burst start that moves, as one gated from a carrier running free does, from moving the pitch.

◆ burst()

void burst ( tone_t * d,
uint64_t t,
uint64_t e_before )
static

Count one burst, opening a run when none is under way.

Parameters
dDetector state.
tTick of the burst's first rise.
e_beforeLast edge before the burst.

◆ carrier()

uint64_t carrier ( const tone_t * d)
static

The carrier period, ticks; 0 with no carrier seen.

The shortest rise interval inside a burst, not counting a burst's first, once there is one; until then the shortest carrier-rate low and the longest carrier-rate high. The rise interval is the better: a high that spans two carrier periods, the low between them too short to reach the input, lengthens the second and is a multiple of the first.

◆ emit()

void emit ( tone_t * d,
uint64_t end )
static

Queue the beep that ends at a tick, if it passes the checks.

Parameters
dDetector state.
endTick of the beep's last edge.

◆ hz_of()

float hz_of ( const tone_t * d,
uint32_t n,
uint64_t ticks )
static

n periods over ticks, in Hz; 0 for none.

Only at a window's or a beep's end, never per edge.

◆ moved()

bool moved ( const tone_t * d,
ratio_t bm,
ratio_t m,
uint32_t pct )
static

The block's pitch bm lies more than pct from the beep's mean m, and all but one of the block's periods lie more than half that on the same side.

One stray period moves the block's pitch and is alone on its side. A carrier running free of the tone moves burst starts, and with them single periods, by up to one carrier period; the block's pitch, a mean of neighbours, by up to a quarter of that. A block whose pitch rests on two periods far apart, their median, has not moved.

◆ ns_ticks()

uint64_t ns_ticks ( uint32_t tick_hz,
uint64_t ns )
static

Convert nanoseconds to ticks, rounded up.

Parameters
tick_hzClock, Hz.
nsTime, nanoseconds.
Returns
Ticks, rounded up.

◆ off_by_more()

bool off_by_more ( ratio_t x,
ratio_t y,
uint32_t pct,
uint32_t den )
static

x lies more than pct / den percent from y, relative to y: |x

  • y| * 100 * den > pct * y, with both sides times x.n * y.n.

◆ period()

void period ( tone_t * d,
uint64_t p,
uint64_t s_open,
uint64_t e_before )
static

Count one period between two burst starts.

Parameters
dDetector state.
pPeriod, ticks.
s_openBurst start the period begins at.
e_beforeLast edge before s_open.

◆ ratio()

ratio_t ratio ( uint64_t s,
uint64_t n )
static

Make a mean from a sum and a count.

Parameters
sSum, in ticks.
nCount of periods; 0 for no mean.
Returns
The ratio.

◆ rise()

void rise ( tone_t * d,
uint64_t t,
uint64_t e_before )
static

Handle a rising edge: decide whether it starts a burst.

Parameters
dDetector state.
tTick of the rise.
e_beforeLast edge before the rise.

◆ tone_advance()

void tone_advance ( tone_t * d,
uint64_t now )

No edge up to tick now: a silence ends a beep, a window closes.

Parameters
dDetector state.
nowTick the detector is advanced to.

◆ tone_busy()

bool tone_busy ( const tone_t * d)

A run of bursts is under way.

Parameters
dDetector state.
Returns
true while a run is open.

◆ tone_cfg_defaults()

void tone_cfg_defaults ( tone_cfg_t * c,
uint32_t tick_hz )

Defaults for a clock of tick_hz: 8000us windows, 400 to 6500Hz, carrier from 7kHz, 500ns glitch, 8000ns hold-off, 3000us gap, 8% split, 3 periods a beep, 2 a window.

Parameters
cSettings to fill.
tick_hzClock of the edge stamps, Hz.

◆ tone_edge()

void tone_edge ( tone_t * d,
uint64_t t,
bool level )

One edge at tick t, level after it.

Parameters
dDetector state.
tTick of the edge.
levelLevel after the edge: true for a rise.

◆ tone_feed()

void tone_feed ( tone_t * d,
const tone_edge_t * e,
size_t n )

n edges in time order.

Parameters
dDetector state.
eEdges, in time order.
nNumber of edges in e.

◆ tone_flush()

void tone_flush ( tone_t * d)

End the beep under way at its last edge, as a silence would, and forget the line's level, so the first rise after it starts a run: the caller's edges have a hole (a buffer overrun) or the recording ends.

Parameters
dDetector state.

◆ tone_holdoff_advance()

size_t tone_holdoff_advance ( tone_holdoff_t * h,
uint64_t now,
tone_edge_t out[1] )

No edge up to now: a held fall whose low has lasted the hold-off by then, into out; 0 or 1.

Parameters
hHold-off state.
nowTick the hold-off is advanced to.
outReceives the released fall.
Returns
0 or 1, the number of edges written to out.

◆ tone_holdoff_edge()

size_t tone_holdoff_edge ( tone_holdoff_t * h,
uint64_t t,
bool level,
tone_edge_t out[2] )

One edge at t; the edges reported, 0 to 2, into out in time order: a held fall whose low lasted the hold-off, then the rise.

Parameters
hHold-off state.
tTick of the edge.
levelLevel after the edge: true for a rise.
outReceives the edges that are released.
Returns
Number of edges written to out.

◆ tone_holdoff_horizon()

uint64_t tone_holdoff_horizon ( const tone_holdoff_t * h,
uint64_t now )

now less the hold-off, at least 0, and never before the latest edge handed out: every edge before it is out, and it never runs backward, so advancing the detector to it after feeding the edges out keeps the detector's time in order.

Parameters
hHold-off state.
nowCurrent tick.
Returns
The horizon tick.

◆ tone_holdoff_init()

void tone_holdoff_init ( tone_holdoff_t * h,
uint32_t tick_hz,
uint32_t hold_ns )

hold_ns of a clock of tick_hz, rounded up to whole ticks; the line starts low.

Parameters
hHold-off state to initialise.
tick_hzClock, Hz.
hold_nsHold-off, nanoseconds.

◆ tone_init()

bool tone_init ( tone_t * d,
const tone_cfg_t * c )

Start from nothing.

False, leaving d unusable, when c contradicts itself or names a range the tick clock cannot resolve: f_min_hz >= f_max_hz, carrier_min_hz <= f_max_hz, f_max_hz or carrier_min_hz above tick_hz (a period under one tick), hold_ns above TONE_HOLD_NS_MAX, glitch_ns outside 1 to TONE_GLITCH_NS_MAX or under one tick, gap_us under the period of f_min_hz or above TONE_GAP_US_MAX, a window outside 1000us to TONE_WINDOW_US_MAX, f_min_hz under 50Hz, a minimum of 0, split_pct above 100. Also refused, as settings under which no signal makes a tone, in whole ticks: the period of f_min_hz, or the gap, at most the glitch or at most twice the hold-off (no low could part two bursts without being a glitch, being too short to start one, or ending the run); the period of f_max_hz rounded down at most the period of carrier_min_hz rounded up, where the tone and carrier ranges meet in whole ticks; window_min_periods - 1 of the shortest burst-start spacings (tone_t's spacing) filling a window.

Parameters
dDetector state; set up by this call.
cSettings to check and use.
Returns
true when the detector is ready.

◆ tone_next_beep()

bool tone_next_beep ( tone_t * d,
tone_beep_t * b )

Take the oldest beep reported; false with none waiting.

Parameters
dDetector state.
bReceives the beep.
Returns
false with none waiting.

◆ tone_ns_ticks()

uint64_t tone_ns_ticks ( uint64_t tick_hz,
uint64_t ns )

ns as ticks of a tick_hz clock, rounded up: the conversion of every time setting.

Exact for every result that fits 64 bits; no intermediate product overflows.

Parameters
tick_hzClock, Hz.
nsTime, nanoseconds.
Returns
Ticks, rounded up.

◆ tone_stats()

const tone_stats_t * tone_stats ( const tone_t * d)

The counters of the detector.

Parameters
dDetector state.
Returns
Pointer to the counters inside d.

◆ tone_ticks_us()

uint64_t tone_ticks_us ( const tone_t * d,
uint64_t ticks )

ticks of the detector's clock in microseconds, rounded down.

Parameters
dDetector state; gives the clock.
ticksTicks of the detector's clock.
Returns
Microseconds, rounded down.

◆ tone_window()

bool tone_window ( const tone_t * d,
tone_window_t * w )

The last window finished; false before the first.

Parameters
dDetector state.
wReceives the window.
Returns
false before the first window is finished.

◆ window_finish()

void window_finish ( tone_t * d)
static

Close the window under way and publish it.

Parameters
dDetector state.

◆ window_open()

void window_open ( tone_t * d,
uint64_t index )
static

Open the window with an index.

Parameters
dDetector state.
indexWindow index: start tick divided by the window length.

◆ windows_to()

void windows_to ( tone_t * d,
uint64_t t )
static

Close every window that ends at or before t.

A stretch of empty windows reports the last of them only.