diff --git a/src/drone-software/src/acoustic/build/demo_offline.exe b/src/drone-software/src/acoustic/build/demo_offline.exe index 4aa5854..085c1e9 100644 Binary files a/src/drone-software/src/acoustic/build/demo_offline.exe and b/src/drone-software/src/acoustic/build/demo_offline.exe differ diff --git a/src/drone-software/src/acoustic/include/acoustic_analyzer/core/fft_utils.h b/src/drone-software/src/acoustic/include/acoustic_analyzer/core/fft_utils.h index 7274f5a..41bb394 100644 --- a/src/drone-software/src/acoustic/include/acoustic_analyzer/core/fft_utils.h +++ b/src/drone-software/src/acoustic/include/acoustic_analyzer/core/fft_utils.h @@ -15,13 +15,13 @@ void compute_power_spectrum(const float* frame, int n_fft, float* power_out); /** * @brief FFT 计算工具类 * - * 封装 kiss_fft,提供复数 FFT 与功率谱计算。 + * 提供复数 FFT 与功率谱计算(内联实现,无外部库依赖)。 */ class FftUtils { public: /** * @brief 构造时预分配 FFT 计划 - * @param nfft FFT 长度(必须为 2 的幂或 kiss_fft 支持的长度) + * @param nfft FFT 长度 */ explicit FftUtils(std::size_t nfft); diff --git a/src/drone-software/src/acoustic/src/core/gunshot_classifier.cpp b/src/drone-software/src/acoustic/src/core/gunshot_classifier.cpp index 494a83e..8f6d33f 100644 --- a/src/drone-software/src/acoustic/src/core/gunshot_classifier.cpp +++ b/src/drone-software/src/acoustic/src/core/gunshot_classifier.cpp @@ -100,7 +100,9 @@ struct GunshotClassifier::Impl { } } if (!config.model_path.empty()) { - if (!LoadModel(config.model_path)) return false; + if (!LoadModel(config.model_path)) { + return false; + } } loaded = session != nullptr; return loaded; @@ -120,15 +122,17 @@ struct GunshotClassifier::Impl { } } - Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + // Cached memory info and I/O names (created once on first use) + static Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + static const char* input_names[] = {"input"}; + static const char* output_names[] = {"output"}; + std::vector input_shape = {1, n_frames, n_mels}; Ort::Value input_tensor = Ort::Value::CreateTensor( memory_info, input_data.data(), input_data.size(), input_shape.data(), input_shape.size()); // Run inference - const char* input_names[] = {"input"}; - const char* output_names[] = {"output"}; auto output_tensors = session->Run( Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, diff --git a/src/drone-software/src/acoustic/tests/demo_offline.cpp b/src/drone-software/src/acoustic/tests/demo_offline.cpp index f090700..a027bdc 100644 --- a/src/drone-software/src/acoustic/tests/demo_offline.cpp +++ b/src/drone-software/src/acoustic/tests/demo_offline.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "acoustic_analyzer/core/feature_extractor.h" #include "acoustic_analyzer/core/gunshot_classifier.h" @@ -50,7 +51,8 @@ float compute_spl(const std::vector& audio) { } Prediction process_file(const std::string& path, - GunshotClassifier& classifier) { + GunshotClassifier& classifier, + FeatureExtractor& extractor) { Prediction result; result.file_path = path; result.true_label = get_parent_folder_name(path); @@ -71,7 +73,6 @@ Prediction process_file(const std::string& path, return result; } - FeatureExtractor extractor(sr, 2048, 512, 64, 0.0f, 8000.0f, 0.97f); Eigen::MatrixXf mel = extractor.MelSpectrogram(audio[0]); auto [label, confidence] = classifier.Predict(mel); @@ -217,12 +218,23 @@ int main(int argc, char** argv) { } std::cout << "Found " << files.size() << " WAV file(s)." << std::endl; + FeatureExtractor extractor(16000, 2048, 512, 64, 0.0f, 8000.0f, 0.97f); + std::vector results; results.reserve(files.size()); + double total_ms = 0.0; for (const auto& f : files) { - results.push_back(process_file(f, classifier)); + auto t0 = std::chrono::steady_clock::now(); + results.push_back(process_file(f, classifier, extractor)); + auto t1 = std::chrono::steady_clock::now(); + total_ms += std::chrono::duration(t1 - t0).count(); } + std::cout << "\nTotal inference time: " << std::fixed << std::setprecision(2) + << total_ms << " ms" + << " | Avg per file: " << (files.empty() ? 0.0 : total_ms / files.size()) + << " ms" << std::endl; + print_report(results); return 0; } diff --git a/src/drone-software/src/acoustic/third_party/kiss_fft/kiss_fft.c b/src/drone-software/src/acoustic/third_party/kiss_fft/kiss_fft.c deleted file mode 100644 index aba63e0..0000000 --- a/src/drone-software/src/acoustic/third_party/kiss_fft/kiss_fft.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 2003-2010, Mark Borgerding. All rights reserved. - * This file is part of KISS FFT - https://github.com/mborgerding/kissfft - * - * SPDX-License-Identifier: BSD-3-Clause - * See COPYING file for more information. - */ - -#include -#include "_kiss_fft_guts.h" -/* The guts header contains all the multiplication and addition macros that are defined for - fixed or floating point complex numbers. It also delares the kf_ internal functions. - */ - -static void kf_bfly2( - kiss_fft_cpx * Fout, - const size_t fstride, - const kiss_fft_cfg st, - int m - ) -{ - kiss_fft_cpx * Fout2; - kiss_fft_cpx * tw1 = st->twiddles; - kiss_fft_cpx t; - Fout2 = Fout + m; - do{ - C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); - - C_MUL (t, *Fout2 , *tw1); - tw1 += fstride; - C_SUB( *Fout2 , *Fout , t ); - C_ADDTO( *Fout , t ); - ++Fout2; - ++Fout; - }while (--m); -} - -static void kf_bfly4( - kiss_fft_cpx * Fout, - const size_t fstride, - const kiss_fft_cfg st, - const size_t m - ) -{ - kiss_fft_cpx *tw1,*tw2,*tw3; - kiss_fft_cpx scratch[6]; - size_t k=m; - const size_t m2=2*m; - const size_t m3=3*m; - - - tw3 = tw2 = tw1 = st->twiddles; - - do { - C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4); - - C_MUL(scratch[0],Fout[m] , *tw1 ); - C_MUL(scratch[1],Fout[m2] , *tw2 ); - C_MUL(scratch[2],Fout[m3] , *tw3 ); - - C_SUB( scratch[5] , *Fout, scratch[1] ); - C_ADDTO(*Fout, scratch[1]); - C_ADD( scratch[3] , scratch[0] , scratch[2] ); - C_SUB( scratch[4] , scratch[0] , scratch[2] ); - C_SUB( Fout[m2], *Fout, scratch[3] ); - tw1 += fstride; - tw2 += fstride*2; - tw3 += fstride*3; - C_ADDTO( *Fout , scratch[3] ); - - if(st->inverse) { - Fout[m].r = scratch[5].r - scratch[4].i; - Fout[m].i = scratch[5].i + scratch[4].r; - Fout[m3].r = scratch[5].r + scratch[4].i; - Fout[m3].i = scratch[5].i - scratch[4].r; - }else{ - Fout[m].r = scratch[5].r + scratch[4].i; - Fout[m].i = scratch[5].i - scratch[4].r; - Fout[m3].r = scratch[5].r - scratch[4].i; - Fout[m3].i = scratch[5].i + scratch[4].r; - } - ++Fout; - }while(--k); -} - -static void kf_bfly3( - kiss_fft_cpx * Fout, - const size_t fstride, - const kiss_fft_cfg st, - size_t m - ) -{ - size_t k=m; - const size_t m2 = 2*m; - kiss_fft_cpx *tw1,*tw2; - kiss_fft_cpx scratch[5]; - kiss_fft_cpx epi3; - epi3 = st->twiddles[fstride*m]; - - tw1=tw2=st->twiddles; - - do{ - C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); - - C_MUL(scratch[1],Fout[m] , *tw1); - C_MUL(scratch[2],Fout[m2] , *tw2); - - C_ADD(scratch[3],scratch[1],scratch[2]); - C_SUB(scratch[0],scratch[1],scratch[2]); - tw1 += fstride; - tw2 += fstride*2; - - Fout[m].r = Fout->r - HALF_OF(scratch[3].r); - Fout[m].i = Fout->i - HALF_OF(scratch[3].i); - - C_MULBYSCALAR( scratch[0] , epi3.i ); - - C_ADDTO(*Fout,scratch[3]); - - Fout[m2].r = Fout[m].r + scratch[0].i; - Fout[m2].i = Fout[m].i - scratch[0].r; - - Fout[m].r -= scratch[0].i; - Fout[m].i += scratch[0].r; - - ++Fout; - }while(--k); -} - -static void kf_bfly5( - kiss_fft_cpx * Fout, - const size_t fstride, - const kiss_fft_cfg st, - int m - ) -{ - kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; - int u; - kiss_fft_cpx scratch[13]; - kiss_fft_cpx * twiddles = st->twiddles; - kiss_fft_cpx *tw; - kiss_fft_cpx ya,yb; - ya = twiddles[fstride*m]; - yb = twiddles[fstride*2*m]; - - Fout0=Fout; - Fout1=Fout0+m; - Fout2=Fout0+2*m; - Fout3=Fout0+3*m; - Fout4=Fout0+4*m; - - tw=st->twiddles; - for ( u=0; ur += scratch[7].r + scratch[8].r; - Fout0->i += scratch[7].i + scratch[8].i; - - scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); - scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); - - scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); - scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); - - C_SUB(*Fout1,scratch[5],scratch[6]); - C_ADD(*Fout4,scratch[5],scratch[6]); - - scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); - scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); - scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); - scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); - - C_ADD(*Fout2,scratch[11],scratch[12]); - C_SUB(*Fout3,scratch[11],scratch[12]); - - ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; - } -} - -/* perform the butterfly for one stage of a mixed radix FFT */ -static void kf_bfly_generic( - kiss_fft_cpx * Fout, - const size_t fstride, - const kiss_fft_cfg st, - int m, - int p - ) -{ - int u,k,q1,q; - kiss_fft_cpx * twiddles = st->twiddles; - kiss_fft_cpx t; - int Norig = st->nfft; - - kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p); - if (scratch == NULL){ - KISS_FFT_ERROR("Memory allocation failed."); - return; - } - - for ( u=0; u=Norig) twidx-=Norig; - C_MUL(t,scratch[q] , twiddles[twidx] ); - C_ADDTO( Fout[ k ] ,t); - } - k += m; - } - } - KISS_FFT_TMP_FREE(scratch); -} - -static -void kf_work( - kiss_fft_cpx * Fout, - const kiss_fft_cpx * f, - const size_t fstride, - int in_stride, - int * factors, - const kiss_fft_cfg st - ) -{ - kiss_fft_cpx * Fout_beg=Fout; - const int p=*factors++; /* the radix */ - const int m=*factors++; /* stage's fft length/p */ - const kiss_fft_cpx * Fout_end = Fout + p*m; - -#ifdef _OPENMP - // use openmp extensions at the - // top-level (not recursive) - if (fstride==1 && p<=5 && m!=1) - { - int k; - - // execute the p different work units in different threads -# pragma omp parallel for - for (k=0;k floor_sqrt) - p = n; /* no more factors, skip to end */ - } - n /= p; - *facbuf++ = p; - *facbuf++ = n; - } while (n > 1); -} - -/* - * - * User-callable function to allocate all necessary storage space for the fft. - * - * The return value is a contiguous block of memory, allocated with malloc. As such, - * It can be freed with free(), rather than a kiss_fft-specific function. - * */ -kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) -{ - KISS_FFT_ALIGN_CHECK(mem) - - kiss_fft_cfg st=NULL; - // check for overflow condition {memneeded > SIZE_MAX}. - if (nfft >= (SIZE_MAX - 2*sizeof(struct kiss_fft_state))/sizeof(kiss_fft_cpx)) - return NULL; - - size_t memneeded = KISS_FFT_ALIGN_SIZE_UP(sizeof(struct kiss_fft_state) - + sizeof(kiss_fft_cpx)*(nfft-1)); /* twiddle factors*/ - - if ( lenmem==NULL ) { - st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); - }else{ - if (mem != NULL && *lenmem >= memneeded) - st = (kiss_fft_cfg)mem; - *lenmem = memneeded; - } - if (st) { - int i; - st->nfft=nfft; - st->inverse = inverse_fft; - - for (i=0;iinverse) - phase *= -1; - kf_cexp(st->twiddles+i, phase ); - } - - kf_factor(nfft,st->factors); - } - return st; -} - - -void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) -{ - if (fin == fout) { - //NOTE: this is not really an in-place FFT algorithm. - //It just performs an out-of-place FFT into a temp buffer - if (fout == NULL){ - KISS_FFT_ERROR("fout buffer NULL."); - return; - } - - kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft); - if (tmpbuf == NULL){ - KISS_FFT_ERROR("Memory allocation error."); - return; - } - - - - kf_work(tmpbuf,fin,1,in_stride, st->factors,st); - memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); - KISS_FFT_TMP_FREE(tmpbuf); - }else{ - kf_work( fout, fin, 1,in_stride, st->factors,st ); - } -} - -void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) -{ - kiss_fft_stride(cfg,fin,fout,1); -} - - -void kiss_fft_cleanup(void) -{ - // nothing needed any more -} - -int kiss_fft_next_fast_size(int n) -{ - while(1) { - int m=n; - while ( (m%2) == 0 ) m/=2; - while ( (m%3) == 0 ) m/=3; - while ( (m%5) == 0 ) m/=5; - if (m<=1) - break; /* n is completely factorable by twos, threes, and fives */ - n++; - } - return n; -} diff --git a/src/drone-software/src/acoustic/third_party/kiss_fft/kiss_fft.h b/src/drone-software/src/acoustic/third_party/kiss_fft/kiss_fft.h deleted file mode 100644 index 51b6306..0000000 --- a/src/drone-software/src/acoustic/third_party/kiss_fft/kiss_fft.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2003-2010, Mark Borgerding. All rights reserved. - * This file is part of KISS FFT - https://github.com/mborgerding/kissfft - * - * SPDX-License-Identifier: BSD-3-Clause - * See COPYING file for more information. - */ - -#ifndef KISS_FFT_H -#define KISS_FFT_H - -#include -#include -#include -#include - -// Define KISS_FFT_SHARED macro to properly export symbols -#ifdef KISS_FFT_SHARED -# ifdef _WIN32 -# ifdef KISS_FFT_BUILD -# define KISS_FFT_API __declspec(dllexport) -# else -# define KISS_FFT_API __declspec(dllimport) -# endif -# else -# define KISS_FFT_API __attribute__ ((visibility ("default"))) -# endif -#else -# define KISS_FFT_API -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - ATTENTION! - If you would like a : - -- a utility that will handle the caching of fft objects - -- real-only (no imaginary time component ) FFT - -- a multi-dimensional FFT - -- a command-line utility to perform ffts - -- a command-line utility to perform fast-convolution filtering - - Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c - in the tools/ directory. -*/ - -/* User may override KISS_FFT_MALLOC and/or KISS_FFT_FREE. */ -#ifdef USE_SIMD -#ifdef HAVE_LASX -# include -# define kiss_fft_scalar __m256 -# ifndef KISS_FFT_MALLOC -# define KISS_FFT_MALLOC(nbytes) aligned_alloc(32, KISS_FFT_ALIGN_SIZE_UP(nbytes)) -# define KISS_FFT_ALIGN_CHECK(ptr) -# define KISS_FFT_ALIGN_SIZE_UP(size) ((size + 31UL) & ~0x1FUL) -# endif -# ifndef KISS_FFT_FREE -# define KISS_FFT_FREE free -# endif -#elif defined(HAVE_LSX) -# include -# define kiss_fft_scalar __m128 -# ifndef KISS_FFT_MALLOC -# define KISS_FFT_MALLOC(nbytes) aligned_alloc(16, KISS_FFT_ALIGN_SIZE_UP(nbytes)) -# define KISS_FFT_ALIGN_CHECK(ptr) -# define KISS_FFT_ALIGN_SIZE_UP(size) ((size + 15UL) & ~0xFUL) -# endif -# ifndef KISS_FFT_FREE -# define KISS_FFT_FREE free -# endif -#else -# include -# define kiss_fft_scalar __m128 -# ifndef KISS_FFT_MALLOC -# define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16) -# define KISS_FFT_ALIGN_CHECK(ptr) -# define KISS_FFT_ALIGN_SIZE_UP(size) ((size + 15UL) & ~0xFUL) -# endif -# ifndef KISS_FFT_FREE -# define KISS_FFT_FREE _mm_free -# endif -#endif -#else -# define KISS_FFT_ALIGN_CHECK(ptr) -# define KISS_FFT_ALIGN_SIZE_UP(size) (size) -# ifndef KISS_FFT_MALLOC -# define KISS_FFT_MALLOC malloc -# endif -# ifndef KISS_FFT_FREE -# define KISS_FFT_FREE free -# endif -#endif - - -#ifdef FIXED_POINT -#include -# if (FIXED_POINT == 32) -# define kiss_fft_scalar int32_t -# else -# define kiss_fft_scalar int16_t -# endif -#else -# ifndef kiss_fft_scalar -/* default is float */ -# define kiss_fft_scalar float -# endif -#endif - -typedef struct { - kiss_fft_scalar r; - kiss_fft_scalar i; -}kiss_fft_cpx; - -typedef struct kiss_fft_state* kiss_fft_cfg; - -/* - * kiss_fft_alloc - * - * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. - * - * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); - * - * The return value from fft_alloc is a cfg buffer used internally - * by the fft routine or NULL. - * - * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. - * The returned value should be free()d when done to avoid memory leaks. - * - * The state can be placed in a user supplied buffer 'mem': - * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, - * then the function places the cfg in mem and the size used in *lenmem - * and returns mem. - * - * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), - * then the function returns NULL and places the minimum cfg - * buffer size in *lenmem. - * */ - -kiss_fft_cfg KISS_FFT_API kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); - -/* - * kiss_fft(cfg,in_out_buf) - * - * Perform an FFT on a complex input buffer. - * for a forward FFT, - * fin should be f[0] , f[1] , ... ,f[nfft-1] - * fout will be F[0] , F[1] , ... ,F[nfft-1] - * Note that each element is complex and can be accessed like - f[k].r and f[k].i - * */ -void KISS_FFT_API kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); - -/* - A more generic version of the above function. It reads its input from every Nth sample. - * */ -void KISS_FFT_API kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); - -/* If kiss_fft_alloc allocated a buffer, it is one contiguous - buffer and can be simply free()d when no longer needed*/ -#define kiss_fft_free KISS_FFT_FREE - -/* - Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up - your compiler output to call this before you exit. -*/ -void KISS_FFT_API kiss_fft_cleanup(void); - - -/* - * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) - */ -int KISS_FFT_API kiss_fft_next_fast_size(int n); - -/* for real ffts, we need an even size */ -#define kiss_fftr_next_fast_size_real(n) \ - (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) - -#ifdef __cplusplus -} -#endif - -#endif