CALCRATIO

Introduction

The CalcRatio algorithm is a real-time sample rate ratio estimator designed to track clock mismatch between two asynchronous audio domains. It computes the ratio of output (Tx) to input (Rx) sample counters and applies a Two-stage moving average to deliver a smooth, stable actual ratio for Asynchronous Sample Rate Conversion (ASRC).

Key Features

  • DMA-Counter-Based Ratio Calculation

  • Two-Stage Moving Average

  • One-Shot Noise Rejection

  • High Accuracy Ratio Tracking

Algorithm Overview

The CalcRatio algorithm works as follows:

  1. Initialization (calcRatio_init()):

    • Initializes the CALC_RATIO module with input and output sample rates.

    • Computes the target ratio (sampleRateOut / sampleRateIn).

    • Resets all internal states: Moving-average buffers, Window pointers, Accumulated sums, Counters and the one-shot flag.

    • Prepares the module for accurate ratio estimation.

  2. First Stage Moving Average (MA1):

    • Applies a 1024-point moving average to the instantaneous ratio.

    • Removes high-frequency noise and sudden spikes.

    • Produces a smoothed ratio that still responds to short-term changes.

  3. Second Stage Filtering (MA2):

    • Applies a 128-point moving average to the output of MA1.

    • Reduces long-term drift and stabilizes the ratio.

    • Generates a clean, low-noise ratio used by the resampling stage.

  4. Ratio Calculation (calcRatio_exec()):

    • Reads instantaneous ratio from the TX/RX DMA counters.

    • Uses a one-shot skip to ignore the first noisy measurement.

    • Updates MA1 and MA2 buffers and their accumulated sums.

    • Computes the actual ratio using both filtering stages.

  5. Output (calcRatio_getActualratio()):

    • Provides two key ratio values:

      • Target Ratio: Calculated at initialization.

      • Actual Ratio: Filtered, stable ratio for SW_ASRC operation.

    • Thread-safe access using a global semaphore to avoid race conditions.

API Sequence

To use CALC_RATIO, the application should call the following APIs:

  • calcRatio_init() — Initialize the CALC_RATIO module.

  • calcRatio_exec() — Processes the instantaneous ratio input and computes the filtered, stable actual ratio.

  • calcRatio_getActualratio() — Returns the latest calculated actual ratio for use by the SW_ASRC.

API Reference

group APIs for CALCRATIO

This module contains APIs to program and use the CALCRATIO module.

Defines

CALCRATIO_MA1_LENGTH

Length of the first-stage moving average filter used in ratio smoothing.

CALCRATIO_MA1_LENGTH: Defines the window size (1024 samples) for the coarse moving average filter. This large window effectively suppresses high-frequency jitter in the measured TX/RX sample ratio before finer filtering.

CALCRATIO_MA2_LENGTH

Length of the second-stage moving average filter for refined smoothing.

CALCRATIO_MA2_LENGTH: Defines the window size (128 samples) for the secondary moving average filter. Applied after the first stage to further reduce residual noise and provide a stable, smooth ratio value for resampling control.

Functions

int32_t calcRatio_init(CalcRatio_t *calcRatioInstance, float sampleRateIn, float sampleRateOut)

Initializes the ratio calculation module for ASRC (Asynchronous Sample Rate Converter) with input and output sample rates.

This function configures the CALCRATIO module by setting the input and output sample rates, computing the target ratio (fso / fsi), and resetting all internal filter states (moving average buffers, pointers, sums, and counters) to prepare for accurate ratio tracking.

Parameters:
  • calcRatioInstance – Pointer to the CalcRatio_t instance to initialize.

  • sampleRateIn[in] Input sampling frequency in Hz.

  • sampleRateOut[in] Output sampling frequency in Hz.

Returns:

The computed target ratio (same value written to *targetRatio).

int32_t calcRatio_exec(CalcRatio_t *calcRatioInstance, double *Tx_Counter, double *Rx_Counter)

Executes the CALCRATIO algorithm to derive and update the smoothed actual sample rate ratio.

This function must not be called from an ISR context because it uses semaphores for synchronization.

It performs one iteration of the two-stage moving average filter

  1. If enabled, it discards the first (noisy) measurement using the one_shot flag.

  2. Stores the incoming instantaneousRatio into the first-stage circular buffer (capture_history).

  3. Updates the first-stage moving average sum (movingAvg1Sum).

  4. Feeds the first-stage average into the second-stage buffer (capture2_history).

  5. Updates the second-stage moving average sum (movingAvg2Sum) using a graduated counter.

  6. Computes and returns the smoothed actual ratio via actualRatio.

The result converges to target_ratio as more samples are processed.

Parameters:
  • calcRatioInstance – Pointer to a valid, initialized CalcRatio_t instance.

  • Tx_Counter[in] Pointer to the latest sampled TX DMA transfer count (double).

  • Rx_Counter[in] Pointer to the latest sampled RX DMA transfer count (double).

Returns:

Success/Failure for configuration.

double calcRatio_getActualratio(CalcRatio_t *calcRatioInstance)

Safely retrieve the derived actual sample rate ratio.

This function retrieves the current value of actual_ratio from the specified CalcRatio_t instance in a thread-safe manner. It uses a global binary semaphore (gBinarySem_obj) to guarantee exclusive access and avoid race conditions when calcRatio_exec() updates the ratio concurrently (for example, from a timer callback or another task). It must not be invoked from an ISR context because semaphore-based synchronization is used internally.

Parameters:

calcRatioInstance – Pointer to the CalcRatio instance.

Returns:

The current value of actual_ratio.

struct CalcRatio_t
#include <calcratio.h>

CALCRATIO Parameters.

The CALCRATIO algorithm estimates the ratio between an input fs and an output fs (e.g., sample-rate conversion, clock scaling, etc.) by measuring timing periods and smoothing them with a two-stage moving-average filter. This structure holds:

  1. User-provided sample rates (fsi, fso) – the nominal input and output rates set by the user.

  2. Target ratio – the ideal fso / fsi ratio computed once at initialization.

  3. Actual ratio – the smoothed ratio produced on every execution of calcRatio_exec(). It converges toward the target ratio as the filters settle.

  4. Two-stage moving-average state – separate buffers, sums, and pointers for the first-stage (coarse) and second-stage (fine) filters.

  5. Auxiliary counters – used to manage filter updates and to discard the first (often noisy) measurement.

The first stage (MA1) uses a long window (CALCRATIO_MA1_LENGTH = 1024) to heavily dampen jitter. Its output feeds the second stage (MA2), which uses a shorter window (CALCRATIO_MA2_LENGTH = 128) for finer smoothing. The final smoothed period yields actual_ratio.

Public Members

float fsi

Input sample rate set by the user (Hz).

float fso

Output sample rate set by the user (Hz).

double target_ratio

Target ratio produced by calcRatio_init.

Computed as target_ratio = (double)fso / (double)fsi. This is the ideal ratio the algorithm tries to track.

double actual_ratio

Actual ratio produced by calcRatio_exec on each call.

Starts near zero and converges to target_ratio as the two-stage moving-average filters accumulate enough samples.

double movingAvg1Sum

Accumulator for the first-stage moving-average sum.

double capture_history[CALCRATIO_MA1_LENGTH]

Circular buffer holding the most recent period measurements for the first-stage moving-average filter.

Size = CALCRATIO_MA1_LENGTH (1024 entries). Each entry stores the measured period (in seconds) between successive input events.

double *P2_capture_hist

Pointer into capture_history indicating where the next period sample will be written.

Updated in a wrap-around fashion; the filter logic uses (P2_capture_hist - capture_history) as the current index.

double movingAvg2Sum

Accumulator for the second-stage moving-average sum.

double capture2_history[CALCRATIO_MA2_LENGTH]

Circular buffer for the second-stage moving-average filter.

Holds the per-sample output of the first-stage filter. Size = CALCRATIO_MA2_LENGTH (128 entries).

double *P2_capture2_hist

Pointer into capture2_history for the next write location.

Behaves identically to P2_capture_hist but for the second stage.

uint32_t movingAvg2Count

Counter for the graduated (incremental) update of the second-stage average.

When the first-stage filter produces a new value, this counter is incremented until it reaches CALCRATIO_MA2_LENGTH; only then is the oldest entry subtracted from movingAvg2Sum. This implements a “graduated average” that avoids abrupt changes when the buffer wraps.

uint16_t one_shot

One-shot flag to discard the very first captured period.

The first measurement is often spurious (e.g., due to startup transients). Setting one_shot = 1 causes calcRatio_exec() to ignore it and clear the flag immediately afterward.