Includes when using preprocessing sdk

I am implementing my custom preprocessing block and I came across the rich implementations inside “edge-impulse-sdk/dsp”. Sadly, when I try to #include "edge-impulse-sdk/dsp/spectral/processing.hpp" inside my own preprocessing.hpp file there are plenty of linker errors, relating to multiple definitions. I have tried similar #includes but no luck.

Here is the output from Mbed Studio, using (GCC-ARM):

Compile [100.0%]: preprocessing.cpp
[Warning] processing.hpp@512,16: 'int ei::spectral::processing::find_fft_peaks(ei::matrix_i32_t*, ei::matrix_i32_t*, float, float, uint16_t)' defined but not used [-Wunused-function]
[Warning] processing.hpp@360,16: 'int ei::spectral::processing::find_fft_peaks(ei::matrix_t*, ei::matrix_t*, float, float, uint16_t)' defined but not used [-Wunused-function]
[Warning] processing.hpp@177,16: 'int ei::spectral::processing::i16_filter(ei::matrix_i16_t*, float, uint8_t, float, float, int)' defined but not used [-Wunused-function]
[Warning] processing.hpp@144,16: 'int ei::spectral::processing::butterworth_highpass_filter(ei::matrix_t*, float, float, uint8_t)' defined but not used [-Wunused-function]
[Warning] processing.hpp@115,16: 'int ei::spectral::processing::butterworth_lowpass_filter(ei::matrix_t*, float, float, uint8_t)' defined but not used [-Wunused-function]
Link: example-standalone-inferencing-mbed
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::ei_matrix::~ei_matrix()':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/numpy.hpp:1522: multiple definition of `ei::spectral::processing::spectral_power_edges(ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, float)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:608: first defined here
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::spectral::processing::spectral_power_edges(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float)':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/././edge-impulse-sdk/dsp/spectral/processing.hpp:661: multiple definition of `ei::spectral::processing::spectral_power_edges(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:661: first defined here
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::spectral::processing::periodogram(ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, float, unsigned short)':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/././edge-impulse-sdk/dsp/spectral/processing.hpp:728: multiple definition of `ei::spectral::processing::periodogram(ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, float, unsigned short)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:728: first defined here
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::spectral::processing::periodogram(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float, unsigned short)':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/././edge-impulse-sdk/dsp/spectral/processing.hpp:820: multiple definition of `ei::spectral::processing::periodogram(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float, unsigned short)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:820: first defined here
collect2.exe: error: ld returned 1 exit status
[ERROR] c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::ei_matrix::~ei_matrix()':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/numpy.hpp:1522: multiple definition of `ei::spectral::processing::spectral_power_edges(ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, float)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:608: first defined here
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::spectral::processing::spectral_power_edges(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float)':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/././edge-impulse-sdk/dsp/spectral/processing.hpp:661: multiple definition of `ei::spectral::processing::spectral_power_edges(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:661: first defined here
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::spectral::processing::periodogram(ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, float, unsigned short)':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/././edge-impulse-sdk/dsp/spectral/processing.hpp:728: multiple definition of `ei::spectral::processing::periodogram(ei::ei_matrix*, ei::ei_matrix*, ei::ei_matrix*, float, unsigned short)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:728: first defined here
c:/gnu_arm_embedded/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/preprocessing.o: in function `ei::spectral::processing::periodogram(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float, unsigned short)':
c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/././edge-impulse-sdk/dsp/spectral/processing.hpp:820: multiple definition of `ei::spectral::processing::periodogram(ei::ei_matrix_i16*, ei::ei_matrix_i16*, ei::ei_matrix_i16*, float, unsigned short)'; BUILD/ARDUINO_NANO33BLE/GCC_ARM/source/main.o:c:\Users\Kique\Mbed Programs\example-standalone-inferencing-mbed/./edge-impulse-sdk/dsp/spectral/processing.hpp:820: first defined here
collect2.exe: error: ld returned 1 exit status

I would love to be able to benefit from those implementations, like the ones inside numpy.hpp, which I’m already using and are phenomenal.

The sdk is really rich but the documentation for this portion is just the comments inside the .hpp files so I would appreciate if you could also confirm this is a good structure for my preprocessing.hpp:

#ifndef _PREPROCESSING_H_
#define _PREPROCESSING_H_

#include "numpy.hpp"
#include "ei_model_types.h"
//#include "edge-impulse-sdk/dsp/spectral/processing.hpp" // linker errors

// Depending on your block:
typedef struct {
    uint16_t implementation_version;
    int axes;
    float scale_axes;
    bool center_data;
    int filter_order;
    float cutoff;
} ei_dsp_config_custom_t;


int extract_custom_block_features(signal_t *signal, matrix_t *output_matrix, void *config_ptr, const float f);

#endif // _PREPROCESSING_H_

Thanks in advance!

Hi @PHAN, maybe try just including the spectral.hpp function from your header file. This works for me with GCC9 and Mbed OS 6:

test-my-own.hpp

#pragma once

#include "edge-impulse-sdk/dsp/spectral/spectral.hpp"
#include "edge-impulse-sdk/dsp/speechpy/speechpy.hpp"

int test() {
    // now have access to processing features from audio files
    ei::matrix_t matrix(30, 10);
    auto bla = ei::speechpy::processing::cmvnw(&matrix);

    // from the numpy files
    float b[3];
    numpy::roll(b, 3, -1);

    // and from the spectral files
    ei::spectral::processing::scale(b, 3, 1.2);

    return bla;
}

Then, from main.hpp:

#include "mbed.h"
#include "ei_run_classifier.h"
#include "numpy.hpp"
#include "test-my-own.hpp"

int main() {
    printf("Edge Impulse standalone inferencing (Mbed)\n");

    printf("test %d\n", test());

So that seems to include fine.

(And thanks for the nice words on the SDK :slight_smile: )

1 Like

Thanks for the quick answer.

The problem is speechpy.hpp does not contain the function I want; specifically ei::spectral::processing::butterworth_lowpass_filter. That’s why I was trying to include the mentioned file :worried:

I noticed “spectral.hpp” at the same time you were writing your edit. It works now, thank you so much! Incredibly fast response.

Edit: I’m able to reproduce what you showed. For the moment I cannot get it to work on my project(similar errors). Working on it.

1 Like

I’m able to reproduce what you showed and fixed my project. Apparently, if you do the following the same errors will pop up again:

test-my-own.hpp

#pragma once

#include "numpy.hpp"
#include "edge-impulse-sdk/dsp/spectral/spectral.hpp"
#include "edge-impulse-sdk/dsp/speechpy/speechpy.hpp"

int test();

test-my-own.cpp

#include "test-my-own.hpp"

int test() {
    // now have access to processing features from audio files
    ei::matrix_t matrix(30, 10);
    auto bla = ei::speechpy::processing::cmvnw(&matrix);

    // from the numpy files
    float b[3];
    ei::numpy::roll(b, 3, -1);

    // and from the spectral files
    ei::spectral::processing::scale(b, 3, 1.2);

    return 2;
}

I know this is more of a cpp related question but I really don’t understand what’s going on. This is how I usually manage my C projects :thinking:

Anyway, as I’ve said, what you showed works without problem. Thanks!

It’s a bit finicky because we ship header-only code. @Arjan do you have an idea?

Hi Phan,

The other option would be to use the keyword extern to signal the function is declared in another translation unit. For example:

extern size_t calculate_spectral_buffer_size(bool rms, size_t peaks_count, size_t spectral_edges_count);

void test_function(void)
{
ei_printf("Buffer size: %d\r\n", spectral::feature::calculate_spectral_buffer_size(true, 16, 32));
}
2 Likes