Skip to content

Commit 52df749

Browse files
(Perf improvement) Simplify filterPeaks, reduce memory usage & inline calcs.
Historical data was kept in arrays that are not needed, as only the previous result was consulted. Calculating mean and the standard deviation ended up calculating the mean twice, so an inline combined function is used instead. In the built-in example model this improves the overall filter times by ~10%.
1 parent 9a57a68 commit 52df749

File tree

1 file changed

+36
-42
lines changed

1 file changed

+36
-42
lines changed

mlrunner/mldataprocessor.c

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,24 @@ MldpReturn_t filterStdDev(const float *data_in, const int in_size, float *data_o
7878
return MLDP_SUCCESS;
7979
}
8080

81+
// This combined function is more efficient than calling filterMean and filterStdDev separately
82+
static inline void calcMeanAndStdDev(const float *data_in, const int in_size, float *mean, float *std_dev) {
83+
float sum = 0;
84+
for (int i = 0; i < in_size; i++) {
85+
sum += data_in[i];
86+
}
87+
const float _mean = sum / (float)in_size;
88+
89+
float sum_of_squares = 0;
90+
for (int i = 0; i < in_size; i++) {
91+
float f = data_in[i] - _mean;
92+
sum_of_squares += f * f;
93+
}
94+
*std_dev = sqrtf(sum_of_squares / (float)in_size);
95+
*mean = _mean;
96+
}
97+
8198
// Count the number of peaks
82-
// Warning! This can allocate 5x the in_size of the data in the stack
83-
// so ensure DEVICE_STACK_SIZE is appropriately set
8499
MldpReturn_t filterPeaks(const float *data_in, const int in_size, float *data_out, const int out_size) {
85100
const int lag = 5;
86101
const float threshold = 3.5;
@@ -90,71 +105,50 @@ MldpReturn_t filterPeaks(const float *data_in, const int in_size, float *data_ou
90105
return MLDP_ERROR_CONFIG;
91106
}
92107

93-
static float *signals = NULL;
94-
static float *filtered_y = NULL;
95-
static float *avg_filter = NULL;
96-
static float *std_filter = NULL;
97-
static int arrays_alloc_size = 0;
98-
float lead_in[lag];
99-
100108
// Keep memory allocated between calls to avoid malloc/free overhead
101-
if (arrays_alloc_size < in_size) {
102-
free(signals); free(filtered_y); free(avg_filter); free(std_filter);
103-
signals = (float *)malloc(in_size * sizeof(float));
109+
static float *filtered_y = NULL;
110+
static int alloc_size = 0;
111+
if (alloc_size < in_size) {
112+
free(filtered_y);
104113
filtered_y = (float *)malloc(in_size * sizeof(float));
105-
avg_filter = (float *)malloc(in_size * sizeof(float));
106-
std_filter = (float *)malloc(in_size * sizeof(float));
107-
if (signals == NULL || filtered_y == NULL || avg_filter == NULL|| std_filter == NULL) {
108-
free(signals); free(filtered_y); free(avg_filter); free(std_filter);
109-
signals = NULL; filtered_y = NULL; avg_filter = NULL; std_filter = NULL;
110-
arrays_alloc_size = 0;
114+
if (filtered_y == NULL) {
115+
alloc_size = 0;
111116
return MLDP_ERROR_ALLOC;
112117
}
113-
arrays_alloc_size = in_size;
118+
alloc_size = in_size;
114119
}
115-
memset(signals, 0, in_size * sizeof(float));
116120
memcpy(filtered_y, data_in, lag * sizeof(float));
117-
memcpy(lead_in, data_in, lag * sizeof(float));
118121

119122
float mean_lag, std_dev_lag;
120-
MldpReturn_t mean_result = filterMean(lead_in, lag, &mean_lag, 1);
121-
MldpReturn_t std_dev_result = filterStdDev(lead_in, lag, &std_dev_lag, 1);
122-
if (std_dev_result != MLDP_SUCCESS || mean_result != MLDP_SUCCESS) {
123-
return MLDP_ERROR_CONFIG;
124-
}
125-
126-
avg_filter[lag - 1] = mean_lag;
127-
std_filter[lag - 1] = std_dev_lag;
123+
calcMeanAndStdDev(filtered_y, lag, &mean_lag, &std_dev_lag);
128124

125+
int previous_signal = 0;
129126
int peaksCounter = 0;
130127
for (int i = lag; i < in_size; i++) {
131-
const float diff = fabsf(data_in[i] - avg_filter[i - 1]);
128+
int current_signal;
129+
const float diff = fabsf(data_in[i] - mean_lag);
132130
if (
133131
diff > 0.1f &&
134-
diff > threshold * std_filter[i - 1]
132+
diff > threshold * std_dev_lag
135133
) {
136-
if (data_in[i] > avg_filter[i - 1]) {
137-
signals[i] = +1; // positive signal
138-
if (i - 1 > 0 && signals[i - 1] == 0) {
134+
if (data_in[i] > mean_lag) {
135+
current_signal = +1; // positive signal
136+
if (previous_signal == 0) {
139137
peaksCounter++;
140138
}
141139
} else {
142-
signals[i] = -1; // negative signal
140+
current_signal = -1; // negative signal
143141
}
144142
// make influence lower
145143
filtered_y[i] = influence * data_in[i] + (1.0f - influence) * filtered_y[i - 1];
146144
} else {
147-
signals[i] = 0; // no signal
145+
current_signal = 0; // no signal
148146
filtered_y[i] = data_in[i];
149147
}
148+
previous_signal = current_signal;
150149

151150
// adjust the filters
152-
float y_lag[lag];
153-
memcpy(y_lag, &filtered_y[i - lag], lag * sizeof(float));
154-
filterMean(y_lag, lag, &mean_lag, 1);
155-
filterStdDev(y_lag, lag, &std_dev_lag, 1);
156-
avg_filter[i] = mean_lag;
157-
std_filter[i] = std_dev_lag;
151+
calcMeanAndStdDev(&filtered_y[i - lag], lag, &mean_lag, &std_dev_lag);
158152
}
159153
*data_out = peaksCounter;
160154

0 commit comments

Comments
 (0)