Merge remote-tracking branch 'origin/codex/trend-display-scale' into HEAD
This commit is contained in:
@@ -11,10 +11,10 @@ static int finite_values(const double *v, size_t n) {
|
||||
uint32_t set_plot_abi_version(void) { return 1U; }
|
||||
|
||||
size_t set_plot_eval(uint32_t op, const double *v, size_t n, double *out, size_t cap) {
|
||||
static const size_t sizes[] = {10, 3, 4, 4, 6, 2, 3, 2};
|
||||
static const size_t sizes[] = {10, 3, 4, 4, 6, 2, 3, 2, 4};
|
||||
double span, fraction;
|
||||
if (op > SET_PLOT_DB_DELTA || !v || !out || n != sizes[op] ||
|
||||
cap < (op == SET_PLOT_TRANSFORM ? 4U : 1U)) return 0;
|
||||
if (op > SET_PLOT_LIMITS || !v || !out || n != sizes[op] ||
|
||||
cap < (op == SET_PLOT_TRANSFORM || op == SET_PLOT_LIMITS ? 4U : 1U)) return 0;
|
||||
if (op == SET_PLOT_TRANSFORM) {
|
||||
double w, h, fx, fy;
|
||||
if (!finite_values(v, 4) || v[2] < 1.0/128 || v[2] > 1 ||
|
||||
@@ -69,6 +69,10 @@ size_t set_plot_eval(uint32_t op, const double *v, size_t n, double *out, size_t
|
||||
if (v[0] == 0 || v[1] == 0) return 0;
|
||||
out[0] = 20 * log10(fabs(v[1] / v[0]));
|
||||
break;
|
||||
case SET_PLOT_LIMITS:
|
||||
if (v[0] >= v[1] || v[2] >= v[3]) return 0;
|
||||
out[0] = v[0]; out[1] = v[1]; out[2] = v[2]; out[3] = v[3];
|
||||
return 4;
|
||||
default: return 0;
|
||||
}
|
||||
return isfinite(out[0]) ? 1 : 0;
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
static int compare_double(const void *left, const void *right)
|
||||
{
|
||||
const double a = *(const double *)left;
|
||||
const double b = *(const double *)right;
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
static double window_value(int window, size_t index, size_t n)
|
||||
{
|
||||
double phase = 2.0 * PI * (double)index / (double)n;
|
||||
@@ -124,3 +131,35 @@ int set_spectrum_analyze(const double *times, const double *values, size_t count
|
||||
free(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
int set_spectrum_dominant_peak(const double *amplitudes, size_t count,
|
||||
double bin_hz, double relative_threshold, double absolute_floor,
|
||||
double *scratch, size_t scratch_capacity, double *peak, size_t peak_capacity)
|
||||
{
|
||||
size_t i, usable = 0U, peak_bin = 0U;
|
||||
double peak_amplitude = -1.0, median, threshold;
|
||||
if (amplitudes == NULL || scratch == NULL || peak == NULL || count < 3U ||
|
||||
scratch_capacity < count - 1U || peak_capacity < 2U || !isfinite(bin_hz) ||
|
||||
bin_hz <= 0.0 || !isfinite(relative_threshold) || relative_threshold <= 0.0 ||
|
||||
!isfinite(absolute_floor) || absolute_floor < 0.0) return -1;
|
||||
for (i = 1U; i < count; ++i) {
|
||||
if (isfinite(amplitudes[i]) && amplitudes[i] >= 0.0)
|
||||
scratch[usable++] = amplitudes[i];
|
||||
}
|
||||
if (usable < 2U) return 0;
|
||||
qsort(scratch, usable, sizeof(double), compare_double);
|
||||
median = scratch[usable / 2U];
|
||||
for (i = 1U; i + 1U < count; ++i) {
|
||||
const double value = amplitudes[i];
|
||||
if (isfinite(value) && isfinite(amplitudes[i - 1U]) && isfinite(amplitudes[i + 1U]) &&
|
||||
value >= amplitudes[i - 1U] && value > amplitudes[i + 1U] && value > peak_amplitude) {
|
||||
peak_bin = i;
|
||||
peak_amplitude = value;
|
||||
}
|
||||
}
|
||||
threshold = fmax(absolute_floor, median * relative_threshold);
|
||||
if (peak_bin == 0U || peak_amplitude < threshold) return 0;
|
||||
peak[0] = (double)peak_bin * bin_hz;
|
||||
peak[1] = peak_amplitude;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ static uint16_t get16(const uint8_t *p)
|
||||
return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8));
|
||||
}
|
||||
|
||||
static uint32_t get32(const uint8_t *p)
|
||||
{
|
||||
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) |
|
||||
((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
|
||||
}
|
||||
|
||||
static void put16(uint8_t *p, uint16_t value)
|
||||
{
|
||||
p[0] = (uint8_t)value;
|
||||
@@ -63,6 +69,12 @@ int set_trend_watch_ack(const uint8_t *payload, size_t size, uint16_t period_ms,
|
||||
}
|
||||
|
||||
int set_trend_watch_values(const uint8_t *payload, size_t size, uint16_t *words, size_t capacity)
|
||||
{
|
||||
return set_trend_watch_decode(payload, size, NULL, words, capacity);
|
||||
}
|
||||
|
||||
int set_trend_watch_decode(const uint8_t *payload, size_t size, uint32_t *timestamp_ms,
|
||||
uint16_t *words, size_t capacity)
|
||||
{
|
||||
size_t i, count;
|
||||
if (payload == NULL || size < 6U) return -1;
|
||||
@@ -70,5 +82,6 @@ int set_trend_watch_values(const uint8_t *payload, size_t size, uint16_t *words,
|
||||
if (count > SET_TREND_WATCH_MAX || size != 6U + count * 2U || count > capacity ||
|
||||
(count > 0U && words == NULL)) return -1;
|
||||
for (i = 0U; i < count; ++i) words[i] = get16(payload + 6U + i * 2U);
|
||||
if (timestamp_ms != NULL) *timestamp_ms = get32(payload);
|
||||
return (int)count;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user