/** * @file tiny_conv.c * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg) * @brief tiny_conv | code | source * @version 1.0 * @date 2025-04-27 * @copyright Copyright (c) 2025 * *//* DEPENDENCIES */#include"tiny_conv.h"/** * @name: tiny_conv_f32 * @brief Convolution function * * @param Signal The input signal array * @param siglen The length of the input signal array * @param Kernel The input kernel array * @param kernlen The length of the input kernel array * @param convout The output array for the convolution result * * @return tiny_error_t */tiny_error_ttiny_conv_f32(constfloat*Signal,constintsiglen,constfloat*Kernel,constintkernlen,float*convout){if(NULL==Signal||NULL==Kernel||NULL==convout){returnTINY_ERR_DSP_NULL_POINTER;}if(siglen<=0||kernlen<=0){returnTINY_ERR_DSP_INVALID_PARAM;}if(siglen<kernlen){returnTINY_ERR_DSP_INVALID_PARAM;}#if MCU_PLATFORM_SELECTED == MCU_PLATFORM_ESP32// ESP32 DSP librarydsps_conv_f32(Signal,siglen,Kernel,kernlen,convout);#elsefloat*sig=(float*)Signal;float*kern=(float*)Kernel;intlsig=siglen;intlkern=kernlen;// stage Ifor(intn=0;n<lkern;n++){size_tk;convout[n]=0;for(k=0;k<=n;k++){convout[n]+=sig[k]*kern[n-k];}}// stage IIfor(intn=lkern;n<lsig;n++){size_tkmin,kmax,k;convout[n]=0;kmin=n-lkern+1;kmax=n;for(k=kmin;k<=kmax;k++){convout[n]+=sig[k]*kern[n-k];}}// stage IIIfor(intn=lsig;n<lsig+lkern-1;n++){size_tkmin,kmax,k;convout[n]=0;kmin=n-lkern+1;kmax=lsig-1;for(k=kmin;k<=kmax;k++){convout[n]+=sig[k]*kern[n-k];}}#endifreturnTINY_OK;}/** * @name: tiny_conv_ex_f32 * @brief Extended convolution function with padding and mode options * * @param Signal The input signal array * @param siglen The length of the input signal array * @param Kernel The input kernel array * @param kernlen The length of the input kernel array * @param convout The output array for the convolution result * @param padding_mode Padding mode (zero, symmetric, periodic) * @param conv_mode Convolution mode (full, head, center, tail) * * @return tiny_error_t */tiny_error_ttiny_conv_ex_f32(constfloat*Signal,constintsiglen,constfloat*Kernel,constintkernlen,float*convout,tiny_padding_mode_tpadding_mode,tiny_conv_mode_tconv_mode){if(NULL==Signal||NULL==Kernel||NULL==convout){returnTINY_ERR_DSP_NULL_POINTER;}if(siglen<=0||kernlen<=0){returnTINY_ERR_DSP_INVALID_PARAM;}if(siglen<kernlen){returnTINY_ERR_DSP_INVALID_PARAM;}#if MCU_PLATFORM_SELECTED == MCU_PLATFORM_ESP32if(padding_mode==TINY_PADDING_ZERO&&conv_mode==TINY_CONV_FULL){dsps_conv_f32(Signal,siglen,Kernel,kernlen,convout);returnTINY_OK;}#endifintpad_len=kernlen-1;intpadded_len=siglen+2*pad_len;float*padded_signal=(float*)calloc(padded_len,sizeof(float));if(padded_signal==NULL){returnTINY_ERR_DSP_MEMORY_ALLOC;}// Fill padded signalswitch(padding_mode){caseTINY_PADDING_ZERO:// Middle copy only, left and right are zeros (calloc already zeroed)memcpy(padded_signal+pad_len,Signal,sizeof(float)*siglen);break;caseTINY_PADDING_SYMMETRIC:for(inti=0;i<pad_len;i++){padded_signal[pad_len-1-i]=Signal[i];// Mirror leftpadded_signal[pad_len+siglen+i]=Signal[siglen-1-i];// Mirror right}memcpy(padded_signal+pad_len,Signal,sizeof(float)*siglen);// Copy centerbreak;caseTINY_PADDING_PERIODIC:for(inti=0;i<pad_len;i++){padded_signal[pad_len-1-i]=Signal[(siglen-pad_len+i)%siglen];// Wrap leftpadded_signal[pad_len+siglen+i]=Signal[i%siglen];// Wrap right}memcpy(padded_signal+pad_len,Signal,sizeof(float)*siglen);// Copy centerbreak;default:free(padded_signal);returnTINY_ERR_DSP_INVALID_PARAM;}// Full convolutionintconvlen_full=siglen+kernlen-1;for(intn=0;n<convlen_full;n++){floatsum=0.0f;for(intk=0;k<kernlen;k++){sum+=padded_signal[n+k]*Kernel[kernlen-1-k];// Convolution is flip+slide}convout[n]=sum;}free(padded_signal);// Handle output modeif(conv_mode==TINY_CONV_FULL){returnTINY_OK;}else{intstart_idx=0;intout_len=0;switch(conv_mode){caseTINY_CONV_HEAD:start_idx=0;out_len=kernlen;break;caseTINY_CONV_CENTER:start_idx=(kernlen-1)/2;out_len=siglen;break;caseTINY_CONV_TAIL:start_idx=siglen-1;out_len=kernlen;break;default:returnTINY_ERR_DSP_INVALID_MODE;}// Copy the selected part to the beginningfor(inti=0;i<out_len;i++){convout[i]=convout[start_idx+i];}}returnTINY_OK;}