period mono f

Detects (or at least it tries) the period (number of samples) of the input, based on zero crossings and mean value. Frequency is outputted in axoloti format
Author: Sputnki
License: BSD
Github: sptnk/detect/period mono f.axo

Inlets

frac32buffer.bipolar input signal. should be dc-free, if you're not sure, put a highpass in front of it

Outlets

int32 number of samples at s-rate sample rate

frac32.positive frequency in axoloti format

bool32.pulse trig

Parameters

frac32.u.map tolerance for the mean value part, best set to intermediate values

Attributes

spinner Maximum period allowed. Used to discard false readings

spinner Minimum period allowed. Used to discard false readings

Declaration
float count = 0;  // sample counter
float output = 0; // output reading. The period is stored here

int64_t integral = 0; // integral of the signal starting from 0-crossing
int32_t dx = 0;       // derivative at zero crossing
int32_t x0 = 0;       // value of the signal at previous zero crossing
int64_t ramp = 0;     //"tolerance" ramp

bool sign_old = 0; // sign of previous sample
bool sign = 0;     // sign of current sample

int32_t in_old; // old input
Control Rate
outlet_smp = output;              // output the reading
outlet_f = 268435456.0f / output; // calculate the frequency and output it
outlet_trig = 0;
Audio Rate
count += 1.0f;               // increase the counter by 1
sign = inlet_in > 0 ? 1 : 0; // calculate the sign of curent input
integral += inlet_in;        // integrate the input
ramp += ___SMMUL(
    dx, param_tol
            << 2); // integrate the ramp, using the derivative at zero crossing

float intercept = ((float)inlet_in) / ((float)(in_old - inlet_in));
// calculating the exact zero crossing point -> we want higher precision!

// too early
bool trig = (count > attr_min) && ((ramp > 0) ? (integral < ramp ? 1 : 0)
                                              : (integral > ramp ? 0 : 1));
// this condition serves to filter out meaningless zero crossings:
// if count<attr_min it means it's too early to provide a reading (maybe there's
// some noise in the signal) the second condition serves to test if the mean
// value of the signal is sufficiently close to 0 let's be honest: we'll never be
// so lucky to get it exactly to 0, so we'll settle at a sufficiently small value
// how small? it depends on how steep was the signal at zero crossing and on how
// happy we are with approximate readings

if (sign != sign_old) // a zero crossing has occurred
{
  if (trig) // if the "condition zero" i've explained before is met, we have a
            // readout!
  {
    outlet_trig = 1;
    output = count +
             intercept; // readout, accounting for the "snippet" between samples
    count = -intercept; // resetting the counter, adding the snippet betweein
                        // samples
    integral = 0;           // resetting the integrator
    ramp = 0;               // resetting the ramp integrator
    dx = inlet_in - in_old; // calculating a new derivative at 0x
  }
  if (count > attr_max) // the reading is taking too long. I'll start counting
                        // from here without passing the readout.
  {
    count = -intercept;     // resetting the counter
    integral = 0;           // resetting the integrator
    ramp = 0;               // resetting the ramp integrator
    dx = inlet_in - in_old; // calculating a new derivative at 0x
  }
}

sign_old = sign;
in_old = inlet_in;

Privacy

© 2024 Zrna Research