📄 conv_cor.c
字号:
/* Copyright 2001,2002,2003 NAH6
* All Rights Reserved
*
* Parts Copyright DoD, Parts Copyright Starium
*
*/
/*LINTLIBRARY*/
/*PROTOLIB1*/
#include <math.h>
#include <stdlib.h>
#include "main.h"
#include "conv_cor.h"
#include "rint.h"
static void CalcStochConv(
float ExcVec[],
int ExVecLen,
float LPImpResp[],
int LenTruncH,
float Conv[MAX_CW_VEC_LEN]);
static void EndCorrectStoch(
float ExcVal,
float LPImpResp[],
int LenTruncH,
float Conv[]);
static void CalcCorEngStoch(
float Residual[RES_LEN],
float Conv[],
float ExcVal1,
float ExcVal2,
int First,
float *Cor,
float *Energy);
static void CompGainErrStoch(
float Energy,
float Cor,
float *Gain,
float *Error);
/**************************************************************************
*
* ROUTINE
* ConvCor
*
* FUNCTION
* Find codeword gain and error (TERNARY CODE BOOK ASSUMED!)
*
* SYNOPSIS
* ConvCor(ExcVec, ExVecLen, First, LPImpResp, LenTruncH, NegErr)
*
* formal
*
* data I/O
* name type type function
* -------------------------------------------------------------------
* ExcVec float i excitation vector (ternary codeword)
* ExcVecLen int i size of ex (dimension of codeword)
* First int i first call flag
* LPImpResp float i LPC Impulse Response
* LenTruncH int i Length to truncate impulse response
* NegErr float o negative partial squared error
*
* ConvCor float fun optimal gain for ex
*
*
*==========================================================================
*
* DESCRIPTION
*
* (The calculations below may be valid for version 3.2, but may not be
* correct for version 3.3).
*
* For each code word find its gain and error:
* a. Filter code words through impulse response
* of perceptual weighting filter (LPC filter with
* bandwidth broadening).
* b. Correlate filtered result with actual second error
* signal (e0).
* c. Compute MSPE gain and error for code book vector.
*
* Notes: Codewords may contain many zeros (i.e., ex(1)=0). The
* code book could be accessed by a pointer to nonzero samples.
* Because the code book is static, it`s silly to test its
* samples as in the code below.
*
* Proper selection of the convolution length (len) depends on
* the perceptual weighting filter's expansion factor (gamma)
* which controls the damping of the impulse response.
*
* This is one of CELP's most computationally intensive
* routines. Neglecting overhead, the approximate number of
* DSP instructions (add, multiply, multiply accumulate, or
* compare) per second (IPS) is:
*
* Code book size MIPS
* -------------- ----
* 64 1.1
* 128 2.1
* 256 4.2
* 512 (max) 8.3
*
* C: convolution (recursive truncated end-point correction)
* R: correlation
* E: energy (recursive end-point correction)
* G: gain quantization
*
* celp code book search complexity (doesn't fully exploit ternary values!):
* implicit undefined(a-z)
c
c DSP chip instructions/operation:
* integer MUL, ADD, SUB, MAC, MAD, CMP
* parameter (MUL=1) !multiply
* parameter (ADD=1) !add
* parameter (SUB=1) !subtract
* parameter (MAC=1) !multiply & accumulate
* parameter (MAD=2) !multiply & add
* parameter (CMP=1) !compare
c
c CELP algorithm parameters:
* integer L, len, K, shift, g_bits
* real p, F
* parameter (L=60) !subframe length
* parameter (len=30) !length to truncate calculations (<= L)
* parameter (p=0.77) !code book sparsity
* parameter (shift=2) !shift between code words
* parameter (K=4) !number of subframes/frame
* parameter (F=30.e-3) !time (seconds)/frame
* parameter (g_bits=5) !cbgain bit allocation
c
* integer j
* parameter (j=10)
* integer N(j), i
* real C, R, E, G, IPS
* data N/1, 2, 4, 8, 16, 32, 64, 128, 256, 512/
* print 1
*1 format(10x,'N',10x,'C',13x,'R',12x,'E',15x,'G',13x,'MIPS')
* do i = 1, j
* C = (335)*MAD + (N(i)-1)*shift*(1.-p)*len*ADD
* R = N(i)*L*MAC
* E = L*MAC + (N(i)-1)*((1.-p*p)*L*MAC + (p*p)*2*MAD)
* G = N(i)*(g_bits*(CMP+MUL+ADD) + 3*MUL+1*SUB)
* IPS = (C+R+E+G)*K/F
* print *,N(i),C*K/1.e6/F,R*K/1.e6/F,E*K/1.e6/F,G*K/1.e6/F,IPS/1.e6
* end do
* end
*
* N C R E G MIPS
* 1 8.9333333E-02 8.0000004E-03 8.0000004E-03 2.5333334E-03 0.1078667
* 2 9.1173328E-02 1.6000001E-02 1.1573013E-02 5.0666668E-03 0.1238130
* 4 9.4853334E-02 3.2000002E-02 1.8719040E-02 1.0133334E-02 0.1557057
* 8 0.1022133 6.4000003E-02 3.3011094E-02 2.0266667E-02 0.2194911
* 16 0.1169333 0.1280000 6.1595201E-02 4.0533334E-02 0.3470618
* 32 0.1463733 0.2560000 0.1187634 8.1066668E-02 0.6022034
* 64 0.2052534 0.5120000 0.2330998 0.1621333 1.112487
* 128 0.3230133 1.024000 0.4617727 0.3242667 2.133053
* 256 0.5585334 2.048000 0.9191184 0.6485333 4.174185
* 512 1.029573 4.096000 1.833810 1.297067 8.256450
*
*==========================================================================
*
* CALLED BY
*
* cbsearch
*
* CALLS
*
* gainencode2
*
*==========================================================================
*
* REFERENCES
*
* See REFERENCES in celp.c...and:
*
* Lin, Daniel, "New Approaches to Stochastic Coding of Speech
* Sources at Very Low Bit Rates," Signal Processing III: Theories
* and Applications (Proceedings of EUSIPCO-86), 1986, p.445.
*
* Xydeas, C.S., M.A. Ireton and D.K. Baghbadrani, "Theory and
* Real Time Implementation of a CELP Coder at 4.8 and 6.0 kbits/s
* Using Ternary Code Excitation," Fifth International Conference on
* Digital Processing of Signals in Communications, 1988, p. 167.
*
* Ess, Mike, "Simple Convolution on the Cray X-MP,"
* Supercomputer, March 1988, p. 35
*
* Supercomputer, July 1988, p. 24
*
***************************************************************************/
float ConvCor(
float ExcVec[],
int ExVecLen,
int First,
float LPImpResp[SF_LEN],
int LenTruncH,
float Residual[RES_LEN],
float *NegErr)
{
static float Conv[MAX_CW_VEC_LEN];
static float Energy=0.0;
float Cor;
float Gain;
if (First) {
/* For first codeword, calculate and save convolution of codeword with
truncated impulse response */
CalcStochConv(ExcVec, ExVecLen, LPImpResp, LenTruncH, Conv);
}
else {
/* End correct the convolution sum on subsequent code words */
/* First Shift */
EndCorrectStoch(ExcVec[1], LPImpResp, LenTruncH, Conv);
/* Second Shift */
EndCorrectStoch(ExcVec[0], LPImpResp, LenTruncH, Conv);
}
/* Calculate correlation and energy */
CalcCorEngStoch(Residual, Conv, ExcVec[0], ExcVec[1], First, &Cor, &Energy);
/* Compute Gain and Error */
CompGainErrStoch(Energy, Cor, &Gain, NegErr);
return Gain;
}
/*
*************************************************************************
*
* ROUTINE
* CalcStochConv
*
* FUNCTION
* Calculate and save convolution of codeword with
* truncated impulse response
*
* SYNOPSIS
* CalcStochConv(ExcVec, ExcVecLen, LPImpulseResponse, Conv)
*
* formal
*
* data I/O
* name type type function
* -------------------------------------------------------------------
* ExcVec float i excitation vector (ternary codeword)
* ExcVecLen int i excitation vector length
* LPImpResp float i LPC Impulse Response
* LenTruncH int i length to truncate impulse response
* Conv float o Convolution of codeword with impulse
* response
*
***************************************************************************
* For first code word, calculate and save convolution
* of code word with truncated (to len) impulse response:
*
* NOTES: A standard convolution of two L point sequences
* produces 2L-1 points, however, this convolution
* generates only the first L points.
*
* A "scalar times vector accumulation" method is used
* to exploit (skip) zero samples of the code words:
*
* min(L-i+1, len)
* y = SUM ex * h , where i = 1, ..., L points
* i+j-1, t j=1 i j
*
* ex |1 2 . . . L|
* h |x x len ... 2 1| = y(1)
* h |x x len ... 2 1| = y(2)
* : :
* h |x x len ... 2 1| = y(L)
*
***************************************************************************/
void CalcStochConv(
float ExcVec[],
int ExcVecLen,
float LPImpResp[],
int LenTruncH,
float Conv[MAX_CW_VEC_LEN])
{
int i, j;
/* Initialize */
for(i=0; i< SF_LEN; i++) {
Conv[i] = 0.0;
}
for(i=0; i< ExcVecLen; i++) {
if (rint((double)(ExcVec[i])) != 0.0) {
for(j=0; j<min(SF_LEN - i, LenTruncH); j++) {
Conv[i+j] += ExcVec[i] * LPImpResp[j];
}
}
}
}
/*
*************************************************************************
*
* ROUTINE
* EndCorrectStoch
*
* FUNCTION
* End correct the convolution sum
*
* SYNOPSIS
* EndCorrectStoch(ExcVal, LPImpResp, LenTruncH, Conv)
*
* formal
*
* data I/O
* name type type function
* -------------------------------------------------------------------
* ExcVal float i Excitation value
* LPImpResp float i LPC impulse response
* LenTruncH int i Length to truncate impulse response
* Conv float o Convolution sum
*
***************************************************************************
*
* End correct the convolution sum on subsequent code words:
* (Do two end corrections for a shift by 2 code book)
*
* y = 0
* 0, 0
* y = y + ex * h where i = 1, ..., L points
* i, m i-1, m-1 -m i and m = 1, ..., cbsize-1 code words
*
* NOTE: The data movements in loops "do 59 ..." and "do 69 ..."
* are performed many times and can be quite time consuming.
* Therefore, special precautions should be taken when
* implementing this. Some implementation suggestions:
* 1. Circular buffers with pointers to eliminate data moves.
* 2. Fast "block move" operation as offered on some DSPs.
*
*
***************************************************************************/
void EndCorrectStoch(
float ExcVal,
float LPImpResp[],
int LenTruncH,
float Conv[])
{
int i;
if(rint((double)(ExcVal)) != 0.0) {
/* Ternary stochastic code book (-1, 0, +1) */
if(rint((double)(ExcVal)) == 1.0) {
for(i=LenTruncH-1; i>0; i--) {
Conv[i-1] += LPImpResp[i];
}
}
else {
for(i=LenTruncH-1; i>0; i--) {
Conv[i-1] -= LPImpResp[i];
}
}
}
for(i=SF_LEN-1; i>0; i--) {
Conv[i] = Conv[i-1];
}
Conv[0] = ExcVal*LPImpResp[0];
}
/*
*************************************************************************
*
* ROUTINE
* CalcCorEngStoch
*
* FUNCTION
* Calculate correlation and energy
*
* SYNOPSIS
* CalcCorEngStoch(Residual, Conv, ExcVal1, ExcVal2, First, Cor, Energy)
*
* formal
*
* data I/O
* name type type function
* -------------------------------------------------------------------
* Residual float i Spectrum and adaptive residual
* Conv float i Convolution sum
* ExcVal1 float i First excitation vector value
* ExcVal2 float i Second excitation vector value
* First int i First subframe flag
* Cor float o Correlation
* Energy float o Energy
*
***************************************************************************
*
* Calculate correlation and energy:
* e0 = spectrum & pitch prediction residual
* y = error weighting filtered code words
*
* \/\/\/ CELP's computations are focused in this correlation \/\/\/
* - For a 512 code book this correlation takes 4 MIPS!
* - Decimation?, Down-sample & decimate?, FEC codes?
*
***************************************************************************/
void CalcCorEngStoch(
float Residual[RES_LEN],
float Conv[],
float ExcVal1,
float ExcVal2,
int First,
float *Cor,
float *Energy)
{
int i;
static float NextLastConv=0.0;
static float LastConv=0.0;
/* Initialize */
*Cor = 0.0;
/* Calculate correlation */
for(i=0; i<SF_LEN; i++) {
*Cor += Conv[i]*Residual[i];
}
/* End correct energy on subsequent code words */
if ((rint((double)(ExcVal1)) == 0.0) && (rint((double)(ExcVal2)) == 0.0) && (!First)) {
*Energy -= NextLastConv*NextLastConv + LastConv*LastConv;
}
else {
*Energy = 0.0;
for(i=0; i<SF_LEN; i++) {
*Energy += Conv[i] * Conv[i];
}
}
NextLastConv = Conv[SF_LEN-2];
LastConv = Conv[SF_LEN-1];
}
/*
*************************************************************************
*
* ROUTINE
* CompGainErrStoch
*
* FUNCTION
* Compute gain and error
*
* SYNOPSIS
* CompGainErrStoch(Energy, Cor, Gain, Error)
*
* formal
*
* data I/O
* name type type function
* -------------------------------------------------------------------
* Energy float i Energy
* Cor float i Correlation
* Gain float o Codebook Gain
* Error float o Codebook Error
*
***************************************************************************
*
* Compute gain and error:
* NOTE: Actual MSPE = e0.e0 - gain(2*cor-gain*eng)
* since e0.e0 is independent of the code word,
* minimizing MSPE is equivalent to maximizing:
* match = gain(2*cor-gain*eng)
* If unquantized gain is used, this simplifies:
* match = cor*gain
*
* Independent (open-loop) quantization of gain and match (index):
*
***************************************************************************/
void CompGainErrStoch(
float Energy,
float Cor,
float *Gain,
float *Error)
{
if(Energy <= 0.0)
*Gain = Cor;
else
*Gain = Cor/Energy;
*Error = Cor * *Gain;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -