├── .gitignore ├── README.md ├── LICENSE ├── source └── main.cpp └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.gcda 3 | utensor-model/ 4 | tflite-model/ 5 | model-parameters/ 6 | edge-impulse-sdk/ 7 | CMakeLists.txt 8 | deploy.zip 9 | *.o 10 | analyze-eon-*.js 11 | *.py 12 | .venv/ 13 | edge-impulse-sdk 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Edge Impulse Example: stand-alone inferencing (C++) 2 | 3 | This builds and runs an exported impulse locally on your machine. See the documentation at [Deploy your model as a C++ library](https://docs.edgeimpulse.com/docs/deployment/running-your-impulse-locally/running-your-impulse-locally). There is also a [C version](https://github.com/edgeimpulse/example-standalone-inferencing-c) of this application. 4 | 5 | > **No hardware optimization!** This example repository contains the bare minimum example of compiling your impulse, and does not contain hardware optimizations for MPUs or on Linux. See [example-standalone-inferencing-linux](https://github.com/edgeimpulse/example-standalone-inferencing-linux) to compile with optimizations. 6 | 7 | ## Basic steps 8 | 9 | * Download and unzip your Edge Impulse C++ library into this directory 10 | * Copy a test sample's *raw features* into the `features[]` array in *source/main.cpp* 11 | * Enter `make -j` in this directory to compile the project. If you encounter any OOM memory error try `make -j4` (replace 4 with the number of cores available) 12 | * Enter `./build/app` to run the application 13 | * Compare the output predictions to the predictions of the test sample in the Edge Impulse Studio 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Clear BSD License 2 | 3 | Copyright (c) 2025 EdgeImpulse Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted (subject to the limitations in the disclaimer 8 | below) provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from this 19 | software without specific prior written permission. 20 | 21 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY 22 | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 30 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "edge-impulse-sdk/classifier/ei_run_classifier.h" 3 | 4 | // Callback function declaration 5 | static int get_signal_data(size_t offset, size_t length, float *out_ptr); 6 | 7 | // Raw features copied from test sample 8 | static const float features[] = { 9 | // Copy raw features here (e.g. from the 'Live classification' page) 10 | }; 11 | 12 | int main(int argc, char **argv) { 13 | 14 | signal_t signal; // Wrapper for raw input buffer 15 | ei_impulse_result_t result; // Used to store inference output 16 | EI_IMPULSE_ERROR res; // Return code from inference 17 | 18 | // Calculate the length of the buffer 19 | size_t buf_len = sizeof(features) / sizeof(features[0]); 20 | 21 | // Make sure that the length of the buffer matches expected input length 22 | if (buf_len != EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE) { 23 | ei_printf("ERROR: The size of the input buffer is not correct.\r\n"); 24 | ei_printf("Expected %d items, but got %d\r\n", 25 | EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, 26 | (int)buf_len); 27 | return 1; 28 | } 29 | 30 | run_classifier_init(); 31 | 32 | #if EI_CLASSIFIER_FREEFORM_OUTPUT 33 | // for "freeform" outputs, the application needs to allocate the memory (one matrix_t per output tensor) 34 | std::vector freeform_outputs; 35 | freeform_outputs.reserve(ei_default_impulse.impulse->freeform_outputs_size); 36 | for (size_t ix = 0; ix < ei_default_impulse.impulse->freeform_outputs_size; ++ix) { 37 | freeform_outputs.emplace_back(ei_default_impulse.impulse->freeform_outputs[ix], 1); 38 | } 39 | ei_set_freeform_output(freeform_outputs.data(), freeform_outputs.size()); 40 | #endif // EI_CLASSIFIER_FREEFORM_OUTPUT 41 | 42 | // Assign callback function to fill buffer used for preprocessing/inference 43 | signal.total_length = EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; 44 | signal.get_data = &get_signal_data; 45 | 46 | // Perform DSP pre-processing and inference 47 | res = run_classifier(&signal, &result, false); 48 | 49 | // Print return code and how long it took to perform inference 50 | ei_printf("run_classifier returned: %d\r\n", res); 51 | if (res != 0) { 52 | return 1; 53 | } 54 | 55 | // See edge-impulse-sdk/classifier/ei_print_results.h 56 | ei_print_results(&ei_default_impulse, &result); 57 | 58 | return 0; 59 | } 60 | 61 | // Callback: fill a section of the out_ptr buffer when requested 62 | static int get_signal_data(size_t offset, size_t length, float *out_ptr) { 63 | for (size_t i = 0; i < length; i++) { 64 | out_ptr[i] = (features + offset)[i]; 65 | } 66 | 67 | return EIDSP_OK; 68 | } 69 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Tool macros 2 | CC ?= gcc 3 | CXX ?= g++ 4 | 5 | # Settings 6 | NAME = app 7 | BUILD_PATH = ./build 8 | 9 | # Location of main.cpp (must use C++ compiler for main) 10 | CXXSOURCES = source/main.cpp 11 | 12 | # Search path for header files (current directory) 13 | CFLAGS += -I. 14 | 15 | # C and C++ Compiler flags 16 | CFLAGS += -Wall # Include all warnings 17 | CFLAGS += -g # Generate GDB debugger information 18 | CFLAGS += -Wno-strict-aliasing # Disable warnings about strict aliasing 19 | CFLAGS += -Os # Optimize for size 20 | CFLAGS += -DNDEBUG # Disable assert() macro 21 | 22 | # C++ only compiler flags 23 | CXXFLAGS += -std=c++11 # Use C++11 standard 24 | 25 | # Linker flags 26 | LDFLAGS += -lm # Link to math.h 27 | LDFLAGS += -lstdc++ # Link to stdc++.h 28 | 29 | # Include C source code for required libraries 30 | CSOURCES += $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/TransformFunctions/*.c) \ 31 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/CommonTables/*.c) \ 32 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/BasicMathFunctions/*.c) \ 33 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/ComplexMathFunctions/*.c) \ 34 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/FastMathFunctions/*.c) \ 35 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/SupportFunctions/*.c) \ 36 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/MatrixFunctions/*.c) \ 37 | $(wildcard edge-impulse-sdk/CMSIS/DSP/Source/StatisticsFunctions/*.c) 38 | 39 | # Include C++ source code for required libraries 40 | CXXSOURCES += $(wildcard tflite-model/*.cpp) \ 41 | $(wildcard edge-impulse-sdk/dsp/kissfft/*.cpp) \ 42 | $(wildcard edge-impulse-sdk/dsp/dct/*.cpp) \ 43 | $(wildcard edge-impulse-sdk/dsp/memory.cpp) \ 44 | $(wildcard edge-impulse-sdk/porting/posix/*.c*) \ 45 | $(wildcard edge-impulse-sdk/porting/mingw32/*.c*) 46 | CCSOURCES += 47 | 48 | # Use TensorFlow Lite for Microcontrollers (TFLM) 49 | CFLAGS += -DTF_LITE_DISABLE_X86_NEON=1 50 | CSOURCES += edge-impulse-sdk/tensorflow/lite/c/common.c 51 | CCSOURCES += $(wildcard edge-impulse-sdk/tensorflow/lite/kernels/*.cc) \ 52 | $(wildcard edge-impulse-sdk/tensorflow/lite/kernels/internal/*.cc) \ 53 | $(wildcard edge-impulse-sdk/tensorflow/lite/micro/kernels/*.cc) \ 54 | $(wildcard edge-impulse-sdk/tensorflow/lite/micro/*.cc) \ 55 | $(wildcard edge-impulse-sdk/tensorflow/lite/micro/memory_planner/*.cc) \ 56 | $(wildcard edge-impulse-sdk/tensorflow/lite/core/api/*.cc) 57 | 58 | # Include CMSIS-NN if compiling for an Arm target that supports it 59 | ifeq (${CMSIS_NN}, 1) 60 | 61 | # Include CMSIS-NN and CMSIS-DSP header files 62 | CFLAGS += -Iedge-impulse-sdk/CMSIS/NN/Include/ 63 | CFLAGS += -Iedge-impulse-sdk/CMSIS/DSP/PrivateInclude/ 64 | 65 | # C and C++ compiler flags for CMSIS-NN and CMSIS-DSP 66 | CFLAGS += -Wno-unknown-attributes # Disable warnings about unknown attributes 67 | CFLAGS += -DEI_CLASSIFIER_TFLITE_ENABLE_CMSIS_NN=1 # Use CMSIS-NN functions in the SDK 68 | CFLAGS += -D__ARM_FEATURE_DSP=1 # Enable CMSIS-DSP optimized features 69 | CFLAGS += -D__GNUC_PYTHON__=1 # Enable CMSIS-DSP intrisics (non-C features) 70 | 71 | # Include C source code for required CMSIS libraries 72 | CSOURCES += $(wildcard edge-impulse-sdk/CMSIS/NN/Source/ActivationFunctions/*.c) \ 73 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/BasicMathFunctions/*.c) \ 74 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/ConcatenationFunctions/*.c) \ 75 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/ConvolutionFunctions/*.c) \ 76 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/FullyConnectedFunctions/*.c) \ 77 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/NNSupportFunctions/*.c) \ 78 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/PoolingFunctions/*.c) \ 79 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/ReshapeFunctions/*.c) \ 80 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/SoftmaxFunctions/*.c) \ 81 | $(wildcard edge-impulse-sdk/CMSIS/NN/Source/SVDFunctions/*.c) 82 | endif 83 | 84 | # Generate names for the output object files (*.o) 85 | COBJECTS := $(patsubst %.c,%.o,$(CSOURCES)) 86 | CXXOBJECTS := $(patsubst %.cpp,%.o,$(CXXSOURCES)) 87 | CCOBJECTS := $(patsubst %.cc,%.o,$(CCSOURCES)) 88 | 89 | # Default rule 90 | .PHONY: all 91 | all: app 92 | 93 | # Compile library source code into object files 94 | $(COBJECTS) : %.o : %.c 95 | $(CXXOBJECTS) : %.o : %.cpp 96 | $(CCOBJECTS) : %.o : %.cc 97 | %.o: %.c 98 | $(CC) $(CFLAGS) -c $^ -o $@ 99 | %.o: %.cc 100 | $(CXX) $(CFLAGS) $(CXXFLAGS) -c $^ -o $@ 101 | %.o: %.cpp 102 | $(CXX) $(CFLAGS) $(CXXFLAGS) -c $^ -o $@ 103 | 104 | # Build target (must use C++ compiler) 105 | .PHONY: app 106 | app: $(COBJECTS) $(CXXOBJECTS) $(CCOBJECTS) 107 | ifeq ($(OS), Windows_NT) 108 | if not exist build mkdir build 109 | else 110 | mkdir -p $(BUILD_PATH) 111 | endif 112 | $(CXX) $(COBJECTS) $(CXXOBJECTS) $(CCOBJECTS) -o $(BUILD_PATH)/$(NAME) $(LDFLAGS) 113 | 114 | # Remove compiled object files 115 | .PHONY: clean 116 | clean: 117 | ifeq ($(OS), Windows_NT) 118 | del /Q $(subst /,\,$(patsubst %.c,%.o,$(CSOURCES))) >nul 2>&1 || exit 0 119 | del /Q $(subst /,\,$(patsubst %.cpp,%.o,$(CXXSOURCES))) >nul 2>&1 || exit 0 120 | del /Q $(subst /,\,$(patsubst %.cc,%.o,$(CCSOURCES))) >nul 2>&1 || exit 0 121 | else 122 | rm -f $(COBJECTS) 123 | rm -f $(CCOBJECTS) 124 | rm -f $(CXXOBJECTS) 125 | endif --------------------------------------------------------------------------------