CMSIS-DSP: New PythonWrapper example
Jupyter notebook showing how to implement a simple kws and then convert it into an Arduino implementation.pull/19/head
parent
75cf0da8e6
commit
f74b040be0
@ -0,0 +1,162 @@
|
||||
###########################################
|
||||
# Project: CMSIS DSP Library
|
||||
# Title: appnodes.py
|
||||
# Description: Application nodes for kws example
|
||||
#
|
||||
# $Date: 16 March 2022
|
||||
# $Revision: V1.10.0
|
||||
#
|
||||
# Target Processor: Cortex-M and Cortex-A cores
|
||||
# -------------------------------------------------------------------- */
|
||||
#
|
||||
# Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
# not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
############################################
|
||||
from cmsisdsp.sdf.nodes.simu import *
|
||||
from custom import *
|
||||
import cmsisdsp.fixedpoint as fix
|
||||
import cmsisdsp as dsp
|
||||
|
||||
|
||||
# Sink node displaying the recognized word
|
||||
class Sink(GenericSink):
|
||||
def __init__(self,inputSize,fifoin):
|
||||
GenericSink.__init__(self,inputSize,fifoin)
|
||||
|
||||
|
||||
def run(self):
|
||||
i=self.getReadBuffer()
|
||||
|
||||
if i[0] == -1:
|
||||
print("Unknown")
|
||||
|
||||
if i[0] == 0:
|
||||
print("Yes")
|
||||
|
||||
return(0)
|
||||
|
||||
# Source node getting sample from NumPy buffer
|
||||
# At the end of the buffer we generate 0 samples
|
||||
class Source(GenericSource):
|
||||
def __init__(self,outputSize,fifoout,buffer):
|
||||
GenericSource.__init__(self,outputSize,fifoout)
|
||||
self._offset=0
|
||||
self._buffer=np.array(buffer)
|
||||
|
||||
def run(self):
|
||||
a=self.getWriteBuffer()
|
||||
|
||||
if self._offset + self._outputSize >= len(self._buffer):
|
||||
a[0:self._outputSize] = np.zeros(self._outputSize,dtype=np.int16)
|
||||
else:
|
||||
a[0:self._outputSize] = self._buffer[self._offset:self._offset+self._outputSize]
|
||||
self._offset = self._offset + self._outputSize
|
||||
|
||||
return(0)
|
||||
|
||||
|
||||
# Same implementation as the one in the python notebook
|
||||
def dsp_zcr_q15(w):
|
||||
m = dsp.arm_mean_q15(w)
|
||||
# Negate can saturate so we use CMSIS-DSP function which is working on array (and we have a scalar)
|
||||
m = dsp.arm_negate_q15(np.array([m]))[0]
|
||||
w = dsp.arm_offset_q15(w,m)
|
||||
|
||||
f=w[:-1]
|
||||
g=w[1:]
|
||||
k=np.count_nonzero(np.logical_and(np.logical_or(np.logical_and(f>0,g<0), np.logical_and(f<0,g>0)),g>f))
|
||||
|
||||
# k < len(f) so shift should be 0 except when k == len(f)
|
||||
# When k==len(f) normally quotient is 0x4000 and shift 1 and we convert
|
||||
# this to 0x7FFF
|
||||
status,quotient,shift_val=dsp.arm_divide_q15(k,len(f))
|
||||
if shift_val==1:
|
||||
return(dsp.arm_shift_q31(np.array([quotient]),shift)[0])
|
||||
else:
|
||||
return(quotient)
|
||||
|
||||
# Same implementation as the one in the notebook
|
||||
class FIR(GenericNode):
|
||||
def __init__(self,inputSize,outSize,fifoin,fifoout):
|
||||
GenericNode.__init__(self,inputSize,outSize,fifoin,fifoout)
|
||||
self._firq15=dsp.arm_fir_instance_q15()
|
||||
|
||||
|
||||
|
||||
|
||||
def run(self):
|
||||
a=self.getReadBuffer()
|
||||
b=self.getWriteBuffer()
|
||||
errorStatus = 0
|
||||
|
||||
blockSize=self._inputSize
|
||||
numTaps=10
|
||||
stateLength = numTaps + blockSize - 1
|
||||
dsp.arm_fir_init_q15(self._firq15,10,fix.toQ15(np.ones(10)/10.0),np.zeros(stateLength,dtype=np.int16))
|
||||
|
||||
b[:] = dsp.arm_fir_q15(self._firq15,a)
|
||||
|
||||
return(errorStatus)
|
||||
|
||||
class Feature(GenericNode):
|
||||
def __init__(self,inputSize,outSize,fifoin,fifoout,window):
|
||||
GenericNode.__init__(self,inputSize,outSize,fifoin,fifoout)
|
||||
self._window=window
|
||||
|
||||
|
||||
def run(self):
|
||||
a=self.getReadBuffer()
|
||||
b=self.getWriteBuffer()
|
||||
errorStatus = 0
|
||||
|
||||
b[:] = dsp_zcr_q15(dsp.arm_mult_q15(a,self._window))
|
||||
|
||||
return(errorStatus)
|
||||
|
||||
|
||||
|
||||
class KWS(GenericNode):
|
||||
def __init__(self,inputSize,outSize,fifoin,fifoout,coef_q15,coef_shift,intercept_q15,intercept_shift):
|
||||
GenericNode.__init__(self,inputSize,outSize,fifoin,fifoout)
|
||||
self._coef_q15=coef_q15
|
||||
self._coef_shift=coef_shift
|
||||
self._intercept_q15=intercept_q15
|
||||
self._intercept_shift=intercept_shift
|
||||
|
||||
|
||||
def run(self):
|
||||
a=self.getReadBuffer()
|
||||
b=self.getWriteBuffer()
|
||||
errorStatus = 0
|
||||
|
||||
res=dsp.arm_dot_prod_q15(self._coef_q15,a)
|
||||
|
||||
scaled=dsp.arm_shift_q15(np.array([self._intercept_q15]),self._intercept_shift-self._coef_shift)[0]
|
||||
# Because dot prod output is in Q34.30
|
||||
# and ret is on 64 bits
|
||||
scaled = np.int64(scaled) << 15
|
||||
|
||||
res = res + scaled
|
||||
|
||||
|
||||
|
||||
if res<0:
|
||||
b[0]=-1
|
||||
else:
|
||||
b[0]=0
|
||||
|
||||
return(errorStatus)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,352 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: AppNodes.h
|
||||
* Description: Application nodes for the C compute graph
|
||||
*
|
||||
* $Date: 16 March 2022
|
||||
*
|
||||
* Target Processor: Cortex-M and Cortex-A cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _APPNODES_H_
|
||||
#define _APPNODES_H_
|
||||
|
||||
#include <hal/nrf_pdm.h>
|
||||
#include "coef.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <HardwareSerial.h>
|
||||
|
||||
// When enabled, lots of additional trace is generated
|
||||
//#define DEBUG
|
||||
|
||||
// Buffer to read samples into, each sample is 16-bits
|
||||
// This is written by the PDM driver
|
||||
extern short sampleBuffer[AUDIOBUFFER_LENGTH];
|
||||
|
||||
// Number of audio samples available in the audio buffer
|
||||
extern volatile int samplesRead;
|
||||
|
||||
// Sink node. It is just printing the recognized word
|
||||
template<typename IN, int inputSize> class Sink;
|
||||
|
||||
template<int inputSize>
|
||||
class Sink<q15_t, inputSize>: public GenericSink<q15_t, inputSize>
|
||||
{
|
||||
public:
|
||||
Sink(FIFOBase<q15_t> &src):GenericSink<q15_t,inputSize>(src){};
|
||||
|
||||
int run()
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
Serial.println("==== Sink");
|
||||
#endif
|
||||
|
||||
q15_t *b=this->getReadBuffer();
|
||||
|
||||
if (b[0]==-1)
|
||||
{
|
||||
Serial.println("Unknown");
|
||||
};
|
||||
|
||||
if (b[0]==0)
|
||||
{
|
||||
Serial.println("Yes");
|
||||
};
|
||||
|
||||
return(0);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Source node. It is getting audio data from the PDM driver
|
||||
template<typename OUT, int outputSize> class Source;
|
||||
|
||||
template<int outputSize>
|
||||
class Source<q15_t,outputSize>: public GenericSource<q15_t,outputSize>
|
||||
{
|
||||
public:
|
||||
Source(FIFOBase<q15_t> &dst):GenericSource<q15_t,outputSize>(dst)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
int run(){
|
||||
|
||||
#if defined(DEBUG)
|
||||
Serial.println("==== Source");
|
||||
#endif
|
||||
q15_t *b=this->getWriteBuffer();
|
||||
|
||||
// We wait until enough samples are available.
|
||||
// In a future version we may experiment with sleeping the board
|
||||
while(samplesRead<outputSize)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
Serial.print("Sample reads ");
|
||||
Serial.println(samplesRead);
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(DEBUG)
|
||||
Serial.println("Received");
|
||||
#endif
|
||||
|
||||
// We get the samples and update the
|
||||
// sampleBuffer.
|
||||
// Since this buffer is also accessed by the IRQ, we need to disable it
|
||||
NVIC_DisableIRQ(PDM_IRQn);
|
||||
memcpy(b,sampleBuffer,sizeof(q15_t)*outputSize);
|
||||
if ((samplesRead-outputSize) > 0)
|
||||
{
|
||||
memmove(sampleBuffer,sampleBuffer+outputSize,sizeof(q15_t)*(samplesRead-outputSize));
|
||||
}
|
||||
samplesRead = samplesRead - outputSize;
|
||||
NVIC_EnableIRQ(PDM_IRQn);
|
||||
|
||||
#if defined(DEBUG)
|
||||
Serial.print("After read : Sample reads ");
|
||||
Serial.println(samplesRead);
|
||||
#endif
|
||||
|
||||
|
||||
return(0);
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<typename IN, int inputSize,typename OUT,int outputSize> class FIR;
|
||||
|
||||
|
||||
// FIR node
|
||||
template<int inputSize>
|
||||
class FIR<q15_t,inputSize,q15_t,inputSize>: public GenericNode<q15_t,inputSize,q15_t,inputSize>
|
||||
{
|
||||
public:
|
||||
FIR(FIFOBase<q15_t> &src,FIFOBase<q15_t> &dst):GenericNode<q15_t,inputSize,q15_t,inputSize>(src,dst){
|
||||
int blockSize=inputSize;
|
||||
int numTaps=10;
|
||||
int stateLength = numTaps + blockSize - 1;
|
||||
|
||||
state=(q15_t*)malloc(stateLength * sizeof(q15_t*));
|
||||
};
|
||||
|
||||
int run(){
|
||||
#if defined(DEBUG)
|
||||
Serial.println("==== FIR");
|
||||
#endif
|
||||
q15_t *a=this->getReadBuffer();
|
||||
q15_t *b=this->getWriteBuffer();
|
||||
int blockSize=inputSize;
|
||||
int stateLength = NUMTAPS + blockSize - 1;
|
||||
|
||||
arm_status status=arm_fir_init_q15(&(this->firq15),NUMTAPS,fir_coefs,state,blockSize);
|
||||
|
||||
arm_fir_q15(&(this->firq15),a,b,blockSize);
|
||||
return(0);
|
||||
};
|
||||
|
||||
arm_fir_instance_q15 firq15;
|
||||
q15_t *state;
|
||||
|
||||
};
|
||||
|
||||
/* Not available in the older CMSIS-DSP version provided with Arduino.
|
||||
So we copy the definition here */
|
||||
|
||||
arm_status arm_divide_q15(q15_t numerator,
|
||||
q15_t denominator,
|
||||
q15_t *quotient,
|
||||
int16_t *shift)
|
||||
{
|
||||
int16_t sign=0;
|
||||
q31_t temp;
|
||||
int16_t shiftForNormalizing;
|
||||
|
||||
*shift = 0;
|
||||
|
||||
sign = (numerator>>15) ^ (denominator>>15);
|
||||
|
||||
if (denominator == 0)
|
||||
{
|
||||
if (sign)
|
||||
{
|
||||
*quotient = 0x8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
*quotient = 0x7FFF;
|
||||
}
|
||||
return(ARM_MATH_NANINF);
|
||||
}
|
||||
|
||||
numerator = abs(numerator);
|
||||
denominator = abs(denominator);
|
||||
|
||||
temp = ((q31_t)numerator << 15) / ((q31_t)denominator);
|
||||
|
||||
shiftForNormalizing= 17 - __CLZ(temp);
|
||||
if (shiftForNormalizing > 0)
|
||||
{
|
||||
*shift = shiftForNormalizing;
|
||||
temp = temp >> shiftForNormalizing;
|
||||
}
|
||||
|
||||
if (sign)
|
||||
{
|
||||
temp = -temp;
|
||||
}
|
||||
|
||||
*quotient=temp;
|
||||
|
||||
return(ARM_MATH_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
// We similar to the Python implementation
|
||||
q15_t dsp_zcr_q15(q15_t *w,int blockSize)
|
||||
{
|
||||
q15_t m;
|
||||
arm_mean_q15(w,blockSize,&m);
|
||||
|
||||
// Negate can saturate so we use CMSIS-DSP function which is working on array (and we have a scalar)
|
||||
arm_negate_q15(&m,&m,1);
|
||||
arm_offset_q15(w,m,w,blockSize);
|
||||
|
||||
int k=0;
|
||||
for(int i=0;i<blockSize-1;i++)
|
||||
{
|
||||
int f = w[i];
|
||||
int g = w[i+1];
|
||||
if ((((f>0) && (g<0)) || ((f<0) && (g>0))) && g>f)
|
||||
{
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// k < len(f) so shift should be 0 except when k == len(f)
|
||||
// When k==len(f) normally quotient is 0x4000 and shift 1 and we convert
|
||||
// this to 0x7FFF
|
||||
|
||||
q15_t quotient;
|
||||
int16_t shift;
|
||||
|
||||
arm_status status=arm_divide_q15(k,blockSize-1,"ient,&shift);
|
||||
|
||||
if (shift==1)
|
||||
{
|
||||
arm_shift_q15("ient,shift,"ient,1);
|
||||
return(quotient);
|
||||
}
|
||||
else
|
||||
{
|
||||
return(quotient);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename IN, int inputSize,typename OUT,int outputSize> class Feature;
|
||||
|
||||
template<int inputSize>
|
||||
class Feature<q15_t,inputSize,q15_t,1>: public GenericNode<q15_t,inputSize,q15_t,1>
|
||||
{
|
||||
public:
|
||||
Feature(FIFOBase<q15_t> &src,FIFOBase<q15_t> &dst,const q15_t *window):
|
||||
GenericNode<q15_t,inputSize,q15_t,1>(src,dst),mWindow(window){
|
||||
};
|
||||
|
||||
int run(){
|
||||
#if defined(DEBUG)
|
||||
Serial.println("==== Feature");
|
||||
#endif
|
||||
q15_t *a=this->getReadBuffer();
|
||||
q15_t *b=this->getWriteBuffer();
|
||||
|
||||
arm_mult_q15(a,this->mWindow,a,inputSize);
|
||||
|
||||
b[0] = dsp_zcr_q15(a,inputSize);
|
||||
|
||||
return(0);
|
||||
};
|
||||
|
||||
const q15_t* mWindow;
|
||||
|
||||
};
|
||||
|
||||
template<typename IN, int inputSize,typename OUT,int outputSize> class KWS;
|
||||
|
||||
template<int inputSize>
|
||||
class KWS<q15_t,inputSize,q15_t,1>: public GenericNode<q15_t,inputSize,q15_t,1>
|
||||
{
|
||||
public:
|
||||
KWS(FIFOBase<q15_t> &src,FIFOBase<q15_t> &dst,
|
||||
const q15_t* coef_q15,
|
||||
const int coef_shift,
|
||||
const q15_t intercept_q15,
|
||||
const int intercept_shift):GenericNode<q15_t,inputSize,q15_t,1>(src,dst),
|
||||
mCoef_q15(coef_q15),
|
||||
mCoef_shift(coef_shift),
|
||||
mIntercept_q15(intercept_q15),
|
||||
mIntercept_shift(intercept_shift)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
int run(){
|
||||
#if defined(DEBUG)
|
||||
Serial.println("==== KWS");
|
||||
#endif
|
||||
q15_t *a=this->getReadBuffer();
|
||||
q15_t *b=this->getWriteBuffer();
|
||||
|
||||
q63_t res;
|
||||
arm_dot_prod_q15(this->mCoef_q15,a,inputSize,&res);
|
||||
|
||||
q15_t scaled;
|
||||
arm_shift_q15(&(this->mIntercept_q15),this->mIntercept_shift-this->mCoef_shift,&scaled,1);
|
||||
// Because dot prod output is in Q34.30
|
||||
// and ret is on 64 bits
|
||||
q63_t scaled_Q30 = (q63_t)(scaled) << 15;
|
||||
|
||||
res = res + scaled_Q30;
|
||||
|
||||
if (res<0)
|
||||
{
|
||||
b[0]=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
b[0]=0;
|
||||
}
|
||||
|
||||
|
||||
return(0);
|
||||
};
|
||||
|
||||
const q15_t* mCoef_q15;
|
||||
const int mCoef_shift;
|
||||
const q15_t mIntercept_q15;
|
||||
const int mIntercept_shift;
|
||||
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,297 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: Sched.h
|
||||
* Description: C++ support templates for the SDF scheduler
|
||||
*
|
||||
* $Date: 29 July 2021
|
||||
* $Revision: V1.10.0
|
||||
*
|
||||
* Target Processor: Cortex-M and Cortex-A cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _SCHEDGEN_H_
|
||||
#define _SCHEDGEN_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
// FIFOS
|
||||
|
||||
#ifdef DEBUGSCHED
|
||||
|
||||
template<typename T>
|
||||
struct debugtype{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct debugtype<char>{
|
||||
typedef int type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using Debug = struct debugtype<T>;
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class FIFOBase{
|
||||
public:
|
||||
virtual T* getWriteBuffer(int nb)=0;
|
||||
virtual T* getReadBuffer(int nb)=0;
|
||||
};
|
||||
|
||||
|
||||
template<typename T, int length, int isArray=0>
|
||||
class FIFO: public FIFOBase<T>
|
||||
{
|
||||
public:
|
||||
FIFO(T *buffer,int delay=0):mBuffer(buffer),readPos(0),writePos(delay) {};
|
||||
FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay) {};
|
||||
|
||||
T * getWriteBuffer(int nb) override
|
||||
{
|
||||
if (isArray==1)
|
||||
{
|
||||
return(mBuffer);
|
||||
}
|
||||
|
||||
T *ret;
|
||||
if (readPos > 0)
|
||||
{
|
||||
memcpy((void*)mBuffer,(void*)(mBuffer+readPos),(writePos-readPos)*sizeof(T));
|
||||
writePos -= readPos;
|
||||
readPos = 0;
|
||||
}
|
||||
|
||||
ret = mBuffer + writePos;
|
||||
writePos += nb;
|
||||
return(ret);
|
||||
};
|
||||
|
||||
T* getReadBuffer(int nb) override
|
||||
{
|
||||
if (isArray==1)
|
||||
{
|
||||
return(mBuffer);
|
||||
}
|
||||
|
||||
T *ret = mBuffer + readPos;
|
||||
readPos += nb;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#ifdef DEBUGSCHED
|
||||
void dump()
|
||||
{
|
||||
int nb=0;
|
||||
std::cout << std::endl;
|
||||
for(int i=0; i < length ; i++)
|
||||
{
|
||||
std::cout << (Debug<T>::type)mBuffer[i] << " ";
|
||||
nb++;
|
||||
if (nb == 10)
|
||||
{
|
||||
nb=0;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
T *mBuffer;
|
||||
int readPos,writePos;
|
||||
};
|
||||
|
||||
// GENERIC NODES
|
||||
|
||||
class NodeBase
|
||||
{
|
||||
public:
|
||||
virtual int run()=0;
|
||||
};
|
||||
|
||||
template<typename IN, int inputSize,typename OUT, int outputSize>
|
||||
class GenericNode:public NodeBase
|
||||
{
|
||||
public:
|
||||
GenericNode(FIFOBase<IN> &src,FIFOBase<OUT> &dst):mSrc(src),mDst(dst){};
|
||||
|
||||
protected:
|
||||
OUT * getWriteBuffer(){return mDst.getWriteBuffer(outputSize);};
|
||||
IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);};
|
||||
|
||||
private:
|
||||
FIFOBase<IN> &mSrc;
|
||||
FIFOBase<OUT> &mDst;
|
||||
};
|
||||
|
||||
template<typename IN, int inputSize,typename OUT1, int output1Size,typename OUT2, int output2Size>
|
||||
class GenericNode12:public NodeBase
|
||||
{
|
||||
public:
|
||||
GenericNode12(FIFOBase<IN> &src,FIFOBase<OUT1> &dst1,FIFOBase<OUT2> &dst2):mSrc(src),
|
||||
mDst1(dst1),mDst2(dst2){};
|
||||
|
||||
protected:
|
||||
OUT1 * getWriteBuffer1(){return mDst1.getWriteBuffer(output1Size);};
|
||||
OUT2 * getWriteBuffer2(){return mDst2.getWriteBuffer(output2Size);};
|
||||
IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);};
|
||||
|
||||
private:
|
||||
FIFOBase<IN> &mSrc;
|
||||
FIFOBase<OUT1> &mDst1;
|
||||
FIFOBase<OUT2> &mDst2;
|
||||
};
|
||||
|
||||
template<typename IN1, int input1Size,typename IN2, int input2Size,typename OUT, int outputSize>
|
||||
class GenericNode21:public NodeBase
|
||||
{
|
||||
public:
|
||||
GenericNode21(FIFOBase<IN1> &src1,FIFOBase<IN2> &src2,FIFOBase<OUT> &dst):mSrc1(src1),
|
||||
mSrc2(src2),
|
||||
mDst(dst){};
|
||||
|
||||
protected:
|
||||
OUT * getWriteBuffer(){return mDst.getWriteBuffer(outputSize);};
|
||||
IN1 * getReadBuffer1(){return mSrc1.getReadBuffer(input1Size);};
|
||||
IN2 * getReadBuffer2(){return mSrc2.getReadBuffer(input2Size);};
|
||||
|
||||
private:
|
||||
FIFOBase<IN1> &mSrc1;
|
||||
FIFOBase<IN2> &mSrc2;
|
||||
FIFOBase<OUT> &mDst;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename OUT, int outputSize>
|
||||
class GenericSource:public NodeBase
|
||||
{
|
||||
public:
|
||||
GenericSource(FIFOBase<OUT> &dst):mDst(dst){};
|
||||
|
||||
protected:
|
||||
OUT * getWriteBuffer(){return mDst.getWriteBuffer(outputSize);};
|
||||
|
||||
private:
|
||||
FIFOBase<OUT> &mDst;
|
||||
};
|
||||
|
||||
template<typename IN,int inputSize>
|
||||
class GenericSink:public NodeBase
|
||||
{
|
||||
public:
|
||||
GenericSink(FIFOBase<IN> &src):mSrc(src){};
|
||||
|
||||
protected:
|
||||
IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);};
|
||||
|
||||
private:
|
||||
FIFOBase<IN> &mSrc;
|
||||
};
|
||||
|
||||
|
||||
#define REPEAT(N) for(int i=0;i<N;i++)
|
||||
|
||||
// GENERIC APPLICATION NODES
|
||||
|
||||
template<typename IN,int windowSize, int overlap>
|
||||
class SlidingBuffer: public GenericNode<IN,windowSize-overlap,IN,windowSize>
|
||||
{
|
||||
public:
|
||||
SlidingBuffer(FIFOBase<IN> &src,FIFOBase<IN> &dst):GenericNode<IN,windowSize-overlap,IN,windowSize>(src,dst)
|
||||
{
|
||||
static_assert((windowSize-overlap)>0, "Overlap is too big");
|
||||
memory.resize(overlap);
|
||||
};
|
||||
|
||||
int run(){
|
||||
IN *a=this->getReadBuffer();
|
||||
IN *b=this->getWriteBuffer();
|
||||
memcpy((void*)b,(void*)memory.data(),overlap*sizeof(IN));
|
||||
memcpy((void*)(b+overlap),(void*)a,(windowSize-overlap)*sizeof(IN));
|
||||
memcpy((void*)memory.data(),(void*)(b+windowSize-overlap),overlap*sizeof(IN)) ;
|
||||
return(0);
|
||||
};
|
||||
protected:
|
||||
std::vector<IN> memory;
|
||||
|
||||
};
|
||||
|
||||
template<typename IN,int windowSize, int overlap>
|
||||
class OverlapAdd: public GenericNode<IN,windowSize,IN,windowSize-overlap>
|
||||
{
|
||||
public:
|
||||
OverlapAdd(FIFOBase<IN> &src,FIFOBase<IN> &dst):GenericNode<IN,windowSize,IN,overlap>(src,dst)
|
||||
{
|
||||
static_assert((windowSize-overlap)>0, "Overlap is too big");
|
||||
memory.resize(overlap);
|
||||
};
|
||||
|
||||
int run(){
|
||||
int i;
|
||||
IN *a=this->getReadBuffer();
|
||||
IN *b=this->getWriteBuffer();
|
||||
|
||||
for(i=0;i<overlap;i++)
|
||||
{
|
||||
memory[i] = a[i] + memory[i];
|
||||
}
|
||||
|
||||
if (2*overlap - windowSize > 0)
|
||||
{
|
||||
|
||||
memcpy((void*)b,(void*)memory.data(),(windowSize-overlap)*sizeof(IN));
|
||||
|
||||
memmove(memory.data(),memory.data()+windowSize-overlap,(2*overlap - windowSize)*sizeof(IN));
|
||||
memcpy(memory.data()+2*overlap - windowSize,a+overlap,(windowSize-overlap)*sizeof(IN));
|
||||
}
|
||||
else if (2*overlap - windowSize < 0)
|
||||
{
|
||||
memcpy((void*)b,(void*)memory.data(),overlap*sizeof(IN));
|
||||
memcpy((void*)(b+overlap),(void*)(a+overlap),(windowSize - 2*overlap)*sizeof(IN));
|
||||
|
||||
memcpy((void*)memory.data(),(void*)(a+windowSize-overlap),overlap*sizeof(IN));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((void*)b,(void*)memory.data(),overlap*sizeof(IN));
|
||||
|
||||
memcpy((void*)memory.data(),(void*)(a+overlap),overlap*sizeof(IN));
|
||||
}
|
||||
|
||||
return(0);
|
||||
};
|
||||
protected:
|
||||
std::vector<IN> memory;
|
||||
|
||||
};
|
||||
|
||||
#if !defined(CHECKERROR)
|
||||
#define CHECKERROR if (sdfError < 0) \
|
||||
{\
|
||||
break;\
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -0,0 +1,14 @@
|
||||
arduino-cli board list
|
||||
|
||||
arduino-cli config init
|
||||
|
||||
arduino-cli lib install Arduino_CMSIS-DSP
|
||||
|
||||
arduino-cli compile -b arduino:mbed_nano:nano33ble -v
|
||||
|
||||
# Bootloader COM port
|
||||
arduino-cli upload -b arduino:mbed_nano:nano33ble -p COM5
|
||||
|
||||
pip install pyserial
|
||||
|
||||
python getData.py
|
||||
@ -0,0 +1,65 @@
|
||||
#include "arm_math.h"
|
||||
#include "coef.h"
|
||||
|
||||
|
||||
const q15_t fir_coefs[NUMTAPS]={3277,3277,3277,3277,3277,3277,3277,3277,3277,3277,
|
||||
};
|
||||
|
||||
|
||||
const q15_t coef_q15[98]={-3346,-6224,-9697,-12936,-16920,-20357,-22705,-25301,-27291,-29189,
|
||||
-27827,-26920,-25001,-23132,-20190,-18492,-17783,-16639,-16174,-14871,
|
||||
-13628,-11917,-10446,-8731,-7502,-6340,-5441,-5151,-4475,-4342,
|
||||
-4000,-4071,-4295,-3900,-2454,-234,2701,6316,9346,12216,
|
||||
14414,15401,15285,13877,11377,9229,6648,4804,3306,2451,
|
||||
2082,2763,4166,5516,6320,6501,6728,6403,5883,5333,
|
||||
6515,8275,10031,11890,14189,17285,19272,19242,19158,18224,
|
||||
15625,13057,11268,9628,8184,6156,5943,8021,10310,13040,
|
||||
16011,17826,19139,20029,20433,20198,18052,15731,13999,11727,
|
||||
9499,8258,7410,6984,7233,7581,8690,9118,};
|
||||
|
||||
const q15_t intercept_q15 = -18108;
|
||||
const int coef_shift=1;
|
||||
const int intercept_shift=2;
|
||||
|
||||
const q15_t window[400]={0,2,8,18,32,51,73,99,129,163,
|
||||
202,244,290,340,395,453,515,581,651,724,
|
||||
802,883,969,1058,1151,1247,1348,1452,1559,1671,
|
||||
1786,1904,2027,2152,2282,2414,2551,2690,2833,2979,
|
||||
3129,3282,3438,3597,3760,3926,4094,4266,4441,4618,
|
||||
4799,4982,5168,5357,5549,5743,5940,6140,6342,6547,
|
||||
6754,6963,7175,7389,7605,7823,8044,8266,8491,8717,
|
||||
8946,9176,9408,9642,9877,10114,10353,10593,10834,11077,
|
||||
11321,11566,11813,12061,12309,12559,12810,13062,13314,13567,
|
||||
13821,14075,14331,14586,14842,15099,15355,15612,15869,16127,
|
||||
16384,16641,16899,17156,17413,17669,17926,18182,18437,18693,
|
||||
18947,19201,19454,19706,19958,20209,20459,20707,20955,21202,
|
||||
21447,21691,21934,22175,22415,22654,22891,23126,23360,23592,
|
||||
23822,24051,24277,24502,24724,24945,25163,25379,25593,25805,
|
||||
26014,26221,26426,26628,26828,27025,27219,27411,27600,27786,
|
||||
27969,28150,28327,28502,28674,28842,29008,29171,29330,29486,
|
||||
29639,29789,29935,30078,30217,30354,30486,30616,30741,30864,
|
||||
30982,31097,31209,31316,31420,31521,31617,31710,31799,31885,
|
||||
31966,32044,32117,32187,32253,32315,32373,32428,32478,32524,
|
||||
32566,32605,32639,32669,32695,32717,32736,32750,32760,32766,
|
||||
32767,32766,32760,32750,32736,32717,32695,32669,32639,32605,
|
||||
32566,32524,32478,32428,32373,32315,32253,32187,32117,32044,
|
||||
31966,31885,31799,31710,31617,31521,31420,31316,31209,31097,
|
||||
30982,30864,30741,30616,30486,30354,30217,30078,29935,29789,
|
||||
29639,29486,29330,29171,29008,28842,28674,28502,28327,28150,
|
||||
27969,27786,27600,27411,27219,27025,26828,26628,26426,26221,
|
||||
26014,25805,25593,25379,25163,24945,24724,24502,24277,24051,
|
||||
23822,23592,23360,23126,22891,22654,22415,22175,21934,21691,
|
||||
21447,21202,20955,20707,20459,20209,19958,19706,19454,19201,
|
||||
18947,18693,18437,18182,17926,17669,17413,17156,16899,16641,
|
||||
16384,16127,15869,15612,15355,15099,14842,14586,14331,14075,
|
||||
13821,13567,13314,13062,12810,12559,12309,12061,11813,11566,
|
||||
11321,11077,10834,10593,10353,10114,9877,9642,9408,9176,
|
||||
8946,8717,8491,8266,8044,7823,7605,7389,7175,6963,
|
||||
6754,6547,6342,6140,5940,5743,5549,5357,5168,4982,
|
||||
4799,4618,4441,4266,4094,3926,3760,3597,3438,3282,
|
||||
3129,2979,2833,2690,2551,2414,2282,2152,2027,1904,
|
||||
1786,1671,1559,1452,1348,1247,1151,1058,969,883,
|
||||
802,724,651,581,515,453,395,340,290,244,
|
||||
202,163,129,99,73,51,32,18,8,2,
|
||||
};
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: coef.h
|
||||
* Description: Parameters for the ML model and filter
|
||||
*
|
||||
* $Date: 16 March 2022
|
||||
*
|
||||
* Target Processor: Cortex-M and Cortex-A cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef COEF_H
|
||||
#define COEF_H
|
||||
|
||||
#define NUMTAPS 10
|
||||
#define AUDIOBUFFER_LENGTH 512
|
||||
|
||||
extern const q15_t fir_coefs[NUMTAPS];
|
||||
|
||||
extern const q15_t coef_q15[98];
|
||||
extern const q15_t intercept_q15 ;
|
||||
extern const int coef_shift;
|
||||
extern const int intercept_shift;
|
||||
extern const q15_t window[400];
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,118 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: kws.ino
|
||||
* Description: Very simple Yes detector
|
||||
*
|
||||
* $Date: 16 March 2022
|
||||
*
|
||||
* Target Processor: Cortex-M and Cortex-A cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <PDM.h>
|
||||
#include "arm_math.h"
|
||||
#include "coef.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
// default number of output channels
|
||||
static const char channels = 1;
|
||||
|
||||
// default PCM output frequency
|
||||
static const int frequency = 16000;
|
||||
|
||||
// Buffer to read samples into, each sample is 16-bits
|
||||
short sampleBuffer[AUDIOBUFFER_LENGTH];
|
||||
|
||||
// Number of audio samples read
|
||||
volatile int samplesRead=0;
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
|
||||
Serial.println("Starting ...");
|
||||
|
||||
// Configure the data receive callback
|
||||
PDM.onReceive(onPDMdata);
|
||||
|
||||
// Optionally set the gain
|
||||
// Defaults to 20 on the BLE Sense and 24 on the Portenta Vision Shield
|
||||
// PDM.setGain(30);
|
||||
|
||||
// Initialize PDM with:
|
||||
// - one channel (mono mode)
|
||||
// - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
|
||||
// - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
|
||||
if (!PDM.begin(channels, frequency)) {
|
||||
Serial.println("Failed to start PDM!");
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int error;
|
||||
uint32_t nb;
|
||||
|
||||
// Start the CMSIS-DSP generated synchronous scheduling
|
||||
|
||||
Serial.println("Scheduling ...");
|
||||
nb = scheduler(&error,window,coef_q15,coef_shift,intercept_q15,intercept_shift);
|
||||
Serial.println("End of scheduling");
|
||||
Serial.print("Error status = ");
|
||||
Serial.println(error);
|
||||
Serial.print("Nb iterations");
|
||||
Serial.println(nb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to process the data from the PDM microphone.
|
||||
* NOTE: This callback is executed as part of an ISR.
|
||||
* Therefore using `Serial` to print messages inside this function isn't supported.
|
||||
* */
|
||||
void onPDMdata() {
|
||||
// Query the number of available bytes
|
||||
int bytesAvailable = PDM.available();
|
||||
|
||||
// Get free remaining bytes in the buffer
|
||||
// If real time is respected, there should never be
|
||||
// any overflow.
|
||||
int remainingFreeBytes = AUDIOBUFFER_LENGTH*2 - samplesRead*2;
|
||||
|
||||
if (remainingFreeBytes >= bytesAvailable)
|
||||
{
|
||||
// Read into the sample buffer
|
||||
int nbReadBytes = PDM.read(sampleBuffer+samplesRead, bytesAvailable);
|
||||
|
||||
// 16-bit, 2 bytes per sample
|
||||
samplesRead += nbReadBytes / 2;
|
||||
}
|
||||
else if (remainingFreeBytes > 0)
|
||||
{
|
||||
// Read into the sample buffer
|
||||
int nbReadBytes = PDM.read(sampleBuffer+samplesRead, remainingFreeBytes);
|
||||
|
||||
// 16-bit, 2 bytes per sample
|
||||
samplesRead += nbReadBytes / 2;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
/*
|
||||
|
||||
Generated with CMSIS-DSP SDF Scripts.
|
||||
The generated code is not covered by CMSIS-DSP license.
|
||||
|
||||
The support classes and code is covered by CMSIS-DSP license.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "arm_math.h"
|
||||
#include "custom.h"
|
||||
#include "GenericNodes.h"
|
||||
#include "AppNodes.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
/* List of nodes */
|
||||
static NodeBase *nodeArray[7]={0};
|
||||
|
||||
/*
|
||||
|
||||
Description of the scheduling. It is a list of nodes to call.
|
||||
The values are indexes in the previous array.
|
||||
|
||||
*/
|
||||
static unsigned int schedule[151]=
|
||||
{
|
||||
6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,
|
||||
0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,
|
||||
1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,
|
||||
6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,2,3,4,5,
|
||||
};
|
||||
|
||||
/***********
|
||||
|
||||
FIFO buffers
|
||||
|
||||
************/
|
||||
#define FIFOSIZE0 160
|
||||
#define FIFOSIZE1 400
|
||||
#define FIFOSIZE2 49
|
||||
#define FIFOSIZE3 98
|
||||
#define FIFOSIZE4 98
|
||||
#define FIFOSIZE5 1
|
||||
|
||||
#define BUFFERSIZE0 160
|
||||
q15_t buf0[BUFFERSIZE0]={0};
|
||||
|
||||
#define BUFFERSIZE1 400
|
||||
q15_t buf1[BUFFERSIZE1]={0};
|
||||
|
||||
#define BUFFERSIZE2 49
|
||||
q15_t buf2[BUFFERSIZE2]={0};
|
||||
|
||||
#define BUFFERSIZE3 98
|
||||
q15_t buf3[BUFFERSIZE3]={0};
|
||||
|
||||
#define BUFFERSIZE4 98
|
||||
q15_t buf4[BUFFERSIZE4]={0};
|
||||
|
||||
#define BUFFERSIZE5 1
|
||||
q15_t buf5[BUFFERSIZE5]={0};
|
||||
|
||||
|
||||
/**************
|
||||
|
||||
Classes created for pure function calls (like some CMSIS-DSP functions)
|
||||
|
||||
***************/
|
||||
|
||||
|
||||
uint32_t scheduler(int *error,const q15_t *window,
|
||||
const q15_t *coef_q15,
|
||||
const int coef_shift,
|
||||
const q15_t intercept_q15,
|
||||
const int intercept_shift)
|
||||
{
|
||||
int sdfError=0;
|
||||
uint32_t nbSchedule=0;
|
||||
|
||||
/*
|
||||
Create FIFOs objects
|
||||
*/
|
||||
FIFO<q15_t,FIFOSIZE0,1> fifo0(buf0);
|
||||
FIFO<q15_t,FIFOSIZE1,1> fifo1(buf1);
|
||||
FIFO<q15_t,FIFOSIZE2,0> fifo2(buf2);
|
||||
FIFO<q15_t,FIFOSIZE3,1> fifo3(buf3);
|
||||
FIFO<q15_t,FIFOSIZE4,1> fifo4(buf4);
|
||||
FIFO<q15_t,FIFOSIZE5,1> fifo5(buf5);
|
||||
|
||||
/*
|
||||
Create node objects
|
||||
*/
|
||||
|
||||
SlidingBuffer<q15_t,400,240> audioWin(fifo0,fifo1);
|
||||
nodeArray[0]=(NodeBase*)&audioWin;
|
||||
|
||||
Feature<q15_t,400,q15_t,1> feature(fifo1,fifo2,window);
|
||||
nodeArray[1]=(NodeBase*)&feature;
|
||||
|
||||
SlidingBuffer<q15_t,98,49> featureWin(fifo2,fifo3);
|
||||
nodeArray[2]=(NodeBase*)&featureWin;
|
||||
|
||||
FIR<q15_t,98,q15_t,98> fir(fifo3,fifo4);
|
||||
nodeArray[3]=(NodeBase*)&fir;
|
||||
|
||||
KWS<q15_t,98,q15_t,1> kws(fifo4,fifo5,coef_q15,coef_shift,intercept_q15,intercept_shift);
|
||||
nodeArray[4]=(NodeBase*)&kws;
|
||||
|
||||
Sink<q15_t,1> sink(fifo5);
|
||||
nodeArray[5]=(NodeBase*)&sink;
|
||||
|
||||
Source<q15_t,160> src(fifo0);
|
||||
nodeArray[6]=(NodeBase*)&src;
|
||||
|
||||
/* Run several schedule iterations */
|
||||
while(sdfError==0)
|
||||
{
|
||||
/* Run a schedule iteration */
|
||||
for(unsigned long id=0 ; id < 151; id++)
|
||||
{
|
||||
unsigned int nodeId = schedule[id];
|
||||
sdfError = nodeArray[nodeId]->run();
|
||||
CHECKERROR;
|
||||
}
|
||||
nbSchedule++;
|
||||
}
|
||||
|
||||
*error=sdfError;
|
||||
return(nbSchedule);
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
|
||||
Generated with CMSIS-DSP SDF Scripts.
|
||||
The generated code is not covered by CMSIS-DSP license.
|
||||
|
||||
The support classes and code is covered by CMSIS-DSP license.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _SCHED_H_
|
||||
#define _SCHED_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern uint32_t scheduler(int *error,const q15_t *window,
|
||||
const q15_t *coef_q15,
|
||||
const int coef_shift,
|
||||
const q15_t intercept_q15,
|
||||
const int intercept_shift);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"cpu": {
|
||||
"fqbn": "arduino:mbed_nano:nano33ble",
|
||||
"name": "Arduino Nano 33 BLE",
|
||||
"port": "serial://COM6"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
|
||||
|
||||
|
||||
digraph structs {
|
||||
node [shape=plaintext]
|
||||
rankdir=LR
|
||||
edge [arrowsize=0.5]
|
||||
fontname="times"
|
||||
|
||||
|
||||
audioWin [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">audioWin<BR/>(SlidingBuffer)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
feature [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">feature<BR/>(Feature)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
featureWin [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">featureWin<BR/>(SlidingBuffer)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
fir [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">fir<BR/>(FIR)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
kws [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">kws<BR/>(KWS)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
sink [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">sink<BR/>(Sink)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
src [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">src<BR/>(Source)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
|
||||
|
||||
src:i -> audioWin:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(160)"]
|
||||
|
||||
audioWin:i -> feature:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(400)"]
|
||||
|
||||
feature:i -> featureWin:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >49</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(49)"]
|
||||
|
||||
featureWin:i -> fir:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(98)"]
|
||||
|
||||
fir:i -> kws:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(98)"]
|
||||
|
||||
kws:i -> sink:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(1)"]
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,527 @@
|
||||
#
|
||||
# Generated with CMSIS-DSP SDF Scripts.
|
||||
# The generated code is not covered by CMSIS-DSP license.
|
||||
#
|
||||
# The support classes and code is covered by CMSIS-DSP license.
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
import numpy as np
|
||||
import cmsisdsp as dsp
|
||||
from cmsisdsp.sdf.nodes.simu import *
|
||||
from appnodes import *
|
||||
from custom import *
|
||||
|
||||
DEBUGSCHED=False
|
||||
|
||||
#
|
||||
# FIFO buffers
|
||||
#
|
||||
|
||||
|
||||
FIFOSIZE0=160
|
||||
buf0=np.zeros(FIFOSIZE0,dtype=np.int16)
|
||||
|
||||
FIFOSIZE1=400
|
||||
buf1=np.zeros(FIFOSIZE1,dtype=np.int16)
|
||||
|
||||
FIFOSIZE2=49
|
||||
buf2=np.zeros(FIFOSIZE2,dtype=np.int16)
|
||||
|
||||
FIFOSIZE3=98
|
||||
buf3=np.zeros(FIFOSIZE3,dtype=np.int16)
|
||||
|
||||
FIFOSIZE4=98
|
||||
buf4=np.zeros(FIFOSIZE4,dtype=np.int16)
|
||||
|
||||
FIFOSIZE5=1
|
||||
buf5=np.zeros(FIFOSIZE5,dtype=np.int16)
|
||||
|
||||
|
||||
def scheduler(input_array,window,coef_q15,coef_shift,intercept_q15,intercept_shift):
|
||||
sdfError=0
|
||||
nbSchedule=0
|
||||
debugCounter=13
|
||||
|
||||
#
|
||||
# Create FIFOs objects
|
||||
#
|
||||
fifo0=FIFO(FIFOSIZE0,buf0)
|
||||
fifo1=FIFO(FIFOSIZE1,buf1)
|
||||
fifo2=FIFO(FIFOSIZE2,buf2)
|
||||
fifo3=FIFO(FIFOSIZE3,buf3)
|
||||
fifo4=FIFO(FIFOSIZE4,buf4)
|
||||
fifo5=FIFO(FIFOSIZE5,buf5)
|
||||
|
||||
#
|
||||
# Create node objects
|
||||
#
|
||||
audioWin = SlidingBuffer(400,240,fifo0,fifo1)
|
||||
feature = Feature(400,1,fifo1,fifo2,window)
|
||||
featureWin = SlidingBuffer(98,49,fifo2,fifo3)
|
||||
fir = FIR(98,98,fifo3,fifo4)
|
||||
kws = KWS(98,1,fifo4,fifo5,coef_q15,coef_shift,intercept_q15,intercept_shift)
|
||||
sink = Sink(1,fifo5)
|
||||
src = Source(160,fifo0,input_array)
|
||||
|
||||
while((sdfError==0) and (debugCounter > 0)):
|
||||
nbSchedule = nbSchedule + 1
|
||||
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = src.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = audioWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = feature.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = featureWin.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = fir.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = kws.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
sdfError = sink.run()
|
||||
if sdfError < 0:
|
||||
break
|
||||
|
||||
debugCounter = debugCounter - 1
|
||||
return(nbSchedule,sdfError)
|
||||
@ -0,0 +1,99 @@
|
||||
|
||||
|
||||
|
||||
digraph structs {
|
||||
node [shape=plaintext]
|
||||
rankdir=LR
|
||||
edge [arrowsize=0.5]
|
||||
fontname="times"
|
||||
|
||||
|
||||
audioWin [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">audioWin<BR/>(SlidingBuffer)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
feature [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">feature<BR/>(Feature)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
featureWin [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">featureWin<BR/>(SlidingBuffer)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
fir [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">fir<BR/>(FIR)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
kws [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">kws<BR/>(KWS)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
sink [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">sink<BR/>(Sink)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
src [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">src<BR/>(Source)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
|
||||
|
||||
src:i -> audioWin:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(160)"]
|
||||
|
||||
audioWin:i -> feature:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(400)"]
|
||||
|
||||
feature:i -> featureWin:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >49</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(49)"]
|
||||
|
||||
featureWin:i -> fir:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(98)"]
|
||||
|
||||
fir:i -> kws:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(98)"]
|
||||
|
||||
kws:i -> sink:i [headlabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
|
||||
</TD></TR></TABLE>>,taillabel=<
|
||||
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
|
||||
</TD></TR></TABLE>>,label="q15(1)"]
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue