Skip to content

CODE

PP Implementation — Welch PSD → Average → Peak Detection → sqrt(PSD) Shapes

int tiny_sysid_pp(const float *data, int n_ch, int n, float fs,
                  int fft_len, int n_modes, tiny_sysid_result_t *result)
{
    int target_seg = (n < 128) ? n : (n / 3 < 512 ? n / 3 : 512);
    int seg_len = 1;
    while (seg_len * 2 <= target_seg && seg_len * 2 <= fft_len)
        seg_len <<= 1;
    if (seg_len < 32) seg_len = 32;

    int n_bins;
    float *psd = malloc(n_ch * (fft_len / 2) * sizeof(float));
    tiny_sysid_psd_welch(data, n_ch, n, seg_len, fft_len, fs, psd, &n_bins);

    float *psd_avg = malloc(n_bins * sizeof(float));
    tiny_sysid_psd_average(psd, n_ch, n_bins, psd_avg);

    int peak_bins[n_modes], n_found = 0;
    tiny_sysid_find_peaks(psd_avg, n_bins, n_modes, peak_bins, &n_found);

    result->n_modes = n_found;
    for (int m = 0; m < n_found; m++) {
        int bin = peak_bins[m];
        result->frequencies[m] = tiny_sysid_bin_to_freq(bin, fft_len, fs);
        for (int ch = 0; ch < n_ch; ch++)
            result->shapes[m][ch] = sqrtf(psd[ch * n_bins + bin]);
        tiny_sysid_normalise_shape(result->shapes[m], n_ch);
    }
    tiny_sysid_dedup_modes(result, psd_avg);
    result->success = 1;
    return 0;
}

Key: seg_len auto-adapts, sqrt(PSD) for shapes, 5-bin min peak distance.