A GAIN QUANTIZATION METHOD IN ANALYSIS-BY-SYNTHESIS LINEAR PREDICTIVE SPEECH CODING

Abstract: A gain quantization method, in analysis-by-synthesis linear predictive speech coding, comprises the steps: determine a first gain (GAIN1) for an optimal excitation vector from a first code book; quantize the first gain (GAIN1); determine an optimal second gain (GAIN2) for an optimal excitation vector from a second code book; determine a linear prediction of the logarithm of the second gain (GAIN2) from the quantized first gain (GAIN1); and quantize the difference ( delta ) between the logarithm of the second gain and the linear prediction.

Description: A GAIN QUANTIZATION METHOD IN ANALYSIS-BY-SYNTHESIS LINEAR PREDICTIVE SPEECH CODING TECHNICAL FIELD The present invention relates to a gain quantization method in analysis-by-synthesis linear predicitive speech coding, especial¬ ly for mobile telephony. BACKGROUND OF THE INVENTION Analysis-by-synthesis linear predictive speech coders usually have a long-term predictor or adaptive code book followed by one or several fixed code books. Such speech coders are for example described in [1] - The total excitation vector in such speech coders may be described as a linear combination of code book vectors Vi, such that each code book vector V ± is multiplied by a corresponding gain g^ The code books are searched sequential- ly. Normally the excitation from the first code book is subtrac¬ ted from the target signal (speech signal) before the next code book is searched. Another method is the orthogonal search, where all the vectors in later code books are orthogonalized by the selected code book vectors. Thus, the code books are made independent and can all be searched towards the same target signal. Search methods and gain quantization for a generalized CELP coder having an arbitrary number of code books are discussed in [2] . The gains of the code books are normally quantized separately, but can also be vector quantized together. In the coder described in [3] , two fixed code books are used together with an adaptive code book. The fixed code books are searched orthogonalized. The fixed code book gains are vector quantized together with the adaptive code book gain, after transformation to a suitable domain. The best quantizer index is found by testing all possibilities in a new analysis-by-synthesis loop. A similar quantization method is used in the ACELP coder [4] , but in this case the standard code book search method is used. A method to calculate the quantization boundaries adaptively, using the selected LTP vector and, for the second code book, the selected vector from the first code book, is described in [5, 6] . In [2] a method is suggested, according to which the LTP code book gains are quantized relative to normalized code book vectors. The adaptive code book gain is quantized relative to the frame energy. The ratios g 2 /g ι , g 3 /g 2 / • • • are quantized in non- uniform quantizers. To use vector quantization of the gains, the gains must be quantized after the excitation vectors have been selected. This means that the exact gain of the first searched code books are not known at the time of the later code book searches. If the traditional search method is used, the correct target signal cannot be calculated for the later code books, and the later searches are therefore not optimal. If the orthogonal search method is used, the code book searches are independent of previous code book gains. The gains are thus quantized after the code book searches, and vector quantization may be used. However, the orthogonalization of the code books is often very complex, and it is usually not feasible, unless as in [3] , the code books are specially designed to make the orthogona- lization efficient. When vector quantization is used, the best gains are normally selected in a new analysis-by-synthesis loop. Since the gains are scalar quantities, they can be moved outside the filtering process, which simplifies the computations as compared to the analysis-by-synthesis loops in the code book searches, but the method is still much more complex than independent quantization. Another drawback is that the vector index is very vulnerable to channel errors, since an error in one bit in the index gives a completely different set of gains. In this respect independent quantization is a better choice. However, for this method more bits must be used to achieve the same performance as other quantization methods. The method with adapted quantization limits described in [5, 6] involves complex computations and is not feasible in a low complexity system as mobile telephony. Also, since the decoding of the last code book gain is dependent on correct transmission of all previous gains and vectors, the method is expected to be very sensitive to channel errors. Quantization of gain ratios, as described in [2] , is robust to channel errors and not very complex. However, the methods requires the training of a non uniform quantizer, which might make the coder less robust to other signals not used in the training. The method is also very inflexible. SUMMARY OF THE INVENTION An object of the present invention is an improved gain quantiza¬ tion method in analysis-by-synthesis linear predictive speech coding that reduces or eliminates most of the above problems. Especially, the method should have low complexity, give quantized gains that are unsensitive to channel errors and use fewer bits than the independent gain quantization method. The above objects are achieved by a method in accordance with claim 1. BRIEF DESCRIPTION OF THE DRAWINGS The invention, together with further objects and advantages thereof, may best be understood by making reference to the following description taken together with the accompanying drawings, in which: FIGURE 1 is a block diagram of an embodiment of an analysis- by-synthesis linear predictive speech coder in which the method of the present invention may be used; FIGURE 2 is a block diagram of another embodiment of an analysis-by-synthesis linear predictive speech coder in which the method of the present invention may be used; FIGURE 3 illustrates the principles of multi-pulse excita¬ tion (MPE) ; FIGURE 4 illustrates the principles of transformed binary pulse excitation (TBPE) ; FIGURE 5 illustrates the distribution of an optimal gain from a code book and an optimal gain from the next code book; FIGURE 6 illustrates the distribution between the quantized gain from a code book and an optimal gain from the next code book; FIGURE 7 illustrates the dynamic range of an optimal gain of a code book; FIGURE 8 illustrates the smaller dynamic range of a para e- ter δ that, in accordance with the present in¬ vention, replaces the gain of Figure 7; FIGURE 9 is a flow chart illustrating the method in accor¬ dance with the present invention; FIGURE 10 is an embodiment of a speech coder that uses the method in accordance with the present invention; FIGURE 11 is another embodiment of a speech coder that uses the method in accordance with the present inven- tion; and FIGURE 12 is another embodiment of a speech coder that uses the method in accordance with the present inven¬ tion. DETAILED DESCRIPTION OF THE PREFERRED EMBODIMENTS The numerical example in the following description will refer to the European GSM system. However, it is appreciated that the principles of the present invention may be applied to other cellular systems as well. Throughout the drawings the same referens designations will be used for corresponding or similar elements. Before the gain quantization method in accordance with the present invention is described, it is helpful to first describe examples of speech coders in which the invention may be used. This will now be done with reference to Fig. l and 2. Fig. 1 shows a block diagram of an example of a typical analysis- by-synthesis linear predictive speech coder. The coder comprises a synthesis part to the left of the vertical dashed center line and an analysis part to the right of said line. The synthesis part essentially includes two sections, namely an excitation code generating section 10 and an LPC synthesis filter 12. The excitation code generating section 10 comprises an adaptive code book 14, a fixed code book 16 and an adder 18. A chosen vector a τ (n) from the adaptive code book 14 is multiplied by a gain factor g IQ (Q denotes quantized value) for forming a signal p(n) . In the same way an excitation vector from the fixed code book 16 is multiplied by a gain factor g JQ for forming a signal f(n) . The signals p(n) and f(n) are added in adder 18 for forming an excitation vector ex(n) , which excites the LPC synthesis filter 12 for forming an estimated speech signal vector s (n) . In the analysis part the estimated vector §(n) is subtracted from the actual speech signal vector s(n) in an adder 20 for forming an error signal e(n) . This error signal is forwarded to a weighting filter 22 for forming a weighted error vector e w (n) . The components of this weighted error vector are squared and summed in a unit 24 for forming a measure of the energy of the weighted error vector. A minimization unit 26 minimizes this weighted error vector by choosing that combination of gain g IQ and vector from the adaptive code book 12 and that gain g JQ and vector from the fixed code book 16 that gives the smallest energy value, that is which after filtering in filter 12 best approximates the speech signal vector s(n). This optimization is divided into two steps. In the first step it is assumed that f(n) =0 and the best vector from the adaptive code book 14 and the corresponding g IQ are determined. An algorithm for determining these parameters is given in the enclosed APPENDIX. When these parameters have been determined, a vector and corresponding gain g JQ are chosen from the fixed code book 16 in accordance with a similar algorithm. In this case the determined parameters of the adaptive code book 14 are locked to their determined values. The filter parameters of filter 12 are updated for each speech signal frame (160 samples) by analyzing the speech signal frame in a LPC analyzer 28. This updating has been marked by the dashed connection between analyzer 28 and filter 12. Furthermore, there is a delay element 30 between the output of adder 18 and the adaptive code book 14. In this way the adaptive code book 14 is updated by the finally chosen excitation vector ex(n) . This is done on a subframe basis, where each frame is divided into four subframes (40 samples) . Fig. 2 illustrates another embodiment of a speech coder in which the method accordance with the present invention may be used. The essential difference between the speech coder of Fig. l and the speech coder of Fig. 2 is that the fixed code book 16 of Fig. l has been replaced by a mixed excitation generator 32 comprising the multi-pulse excitation (MPE) generator 34 and a transformed binary pulse excitation (TBPE) generator 36. These two ex¬ citations will be briefly described below. The corresponding block gains have been denoted g MQ and g TQ , respectively, in Fig. 2. The excitations from generators 34, 36 are added in an adder 38, and the mixed excitation is added to the adaptive code book excitation in adder 18. Multi-pulse excitation is illustrated in Fig. 3 and is described in detail in [7] and also in the enclosed C++ program listing. Fig. 2 illustrates 6 pulses distributed over a subframe of 40 samples (=5 ms) . The excitation vector may be described by the positions of these pulses (positions 7, 9, 14, 25, 29, 37 in the example) and the amplitudes of the pulses (AMP1-AMP6 in the example) . Methods for finding these parameters are described in [7] . Usually the amplitudes only represent the shape of the excitation vector. Therefore a block gain g MQ (see Fig. 2) is used to represent the amplification of this basic vector shape. Fig.4 illustrates the principles behind transformed binary pulse excitation which are described in detail in [8] and in the enclosed program listing. The binary pulse code book may comprise of vectors containing for example 10 components. Each vector component points either up (+1) or down (-1) as illustrated in Fig. 4. The binary pulse code book contains all possible combinations of such vectors. The vectors of this code book may be considered as the set of all vectors that point to the "corners" of a 10-dimensional "cube". Thus, the vector tips are uniformly distributed over the surface of a 10-dimensional sphere. Furthermore, TBPE contains one or several transformation matrices (MATRIX 1 and MATRIX 2 in Fig. 4) . These are precalculated matrices stored in ROM. These matrices operate on the vectors stored in the binary pulse code book to produce a set of transformed vectors. Finally, the transformed vectors are distributed on a set of excitation pulse grids. The result is four different versions of regularly spaced "stochastic" code books for each matrix. A vector from one of these code books (based on grid 2) is shown as a final result in Fig. 4. The object of the search procedure is to find the binary pulse code book index of the binary code book, the transformation matrix and the excitation pulse grid that together give the smallest weighted error. These parameters are combined with a gain g TQ (see Fig. 2) . In the speech coders illustrated in Figs. 1 and 2, the gains g IQ , STc 9 MQ anc * 9 TQ have been quantized completely independent of each other. However, as may be seen from Fig. 5 there is a strong correlation between gains of different code books. In Fig. 5 the distribution between the logarithm of a gain g-^ corresponding to an MPE code book and the logarithm of the gain g 2 corresponding to a TBPE code book is shown. Fig. 6 shows a similar diagram, however, in this case gain g x has been quantized. Furthermore, in Fig. 6 a line L has been indicated. This line, which may be found by regression analysis, may be used to predict g 2 from g 1Q , which will be further described below. The data points in Fig. 5 and 6 have been obtained from 8 000 frames. As Figs. 5 and 6 indicate, there is a strong correlation between gains belonging to different code books. By calculating a large number of quantized gains g 1Q from a first code book and corre- sponding gains (unquantized) g 2 for a second code book in corresponding frames and determining line L, this line may be used as a linear predictor, which predicts the logarithm of g 2 from the logarithm of g 1Q in accordance with the following formula: log(g 2 ) = b + c-log(g 1Q ) where g 2 represents the predicted gain g 2 . In accordance with an embodiment of the present invention, instead of quantizing g 2 the difference δ between the logarithms of the actual and predicted gain g 2 is calculated in accordance with the formula δ = log (g 2 ) - log (g 2 ) = log (g 2 ) - (b + c - log (g 1Q ) ) and thereafter quantized. Figs. 7 and 8 illustrate one advantage obtained by the above method. Fig. 7 illustrates the dynamic range of gain g 2 for 8 000 frames. Fig. 8 illustrates the corresponding dynamic range for δ in the same frames. As can be seen from Figs. 7 and 8 the dynamic range of δ is much smaller than the dynamic range of g 2 . This means that the number of quantization levels for δ can be reduced significantly, as compared to the number of quantization levels required for g 2 . To achieve good performance in the quantization, 16 levels are often used in the gain quantization. Using δ- quantization in accordance with the present invention an equivalent performance can be obtained using only 6 quantization levels, which equals a bit rate saving of 0,3 kb/s. Since the quantities b and c are predetermined and fixed quantities that are stored in the coder and the decoder, the gain g 2 may be reconstructed in the decoder in accordance with the formula ~ 2 = _g 1Q _ c -exp(b+δ Q ) where g 1Q and δ Q have been transmitted and received at the decoder. The correlation between the code book gains is highly dependent on the energy levels in the code book vectors. If the energy in the code book is varying, the vector energy could be included in the prediction to improve the performance. In [2] normalized code book vectors are used, which eliminates this problems. However, this method may be complex if the code book is not automatically normalized and has many non-zero components. Instead the factor g. may be modified to better represent the excitation energy of the previous code book before being used in the prediction. Thus, the formula for δ may be modified in accordance with: δ = log (g 2 ) - (b + c - log (E* - g 1Q ) ) where E represents the energy of the vector that has been chosen from code book 1. The excitation energy is calculated and used in the search of the code book, so no extra computations must be performed. If the first code book is the adaptive code book, the energy varies strongly, and most components are usually non-zero. Normalizing the vectors would be a computationally complex operation. However, if the code book is used without normaliza- tion, the quantized gain may be multiplied by the square root of the vector energy, as indicated above, to form a good basis for the prediction of the next code book gain. An MPE code book vector has a few non-zero pulses with varying amplitudes and signs. The vector energy is given by the sum of the squares of the pulse amplitudes. For prediction of the next code book gain, e.g. the TBPE code book gain, the MPE gain may be modified by the square root of the energy as in the case of the adaptive code book. However, equivalent performance is obtained if the mean pulse amplitude (amplitudes are always positive) is used instead, and this operation is less complex. The quantized gains g 1Q in Fig. 6 were modified using this method. The above discussed energy modification gives the following formula for g 2 at the decoder: ~ 2 = _E*-g 1Q ] c -exp(b+δ Q ) Since the excitation vectors are available also at the decoder, the energy E does not have to be transmitted, but can be recalculated at the decoder. An example algorithm, in which the first gain is an MPE gain and the second gain is a TBPE gain, is summarized below: EXAMPLE ALGORITHM LPC analysis Subframe_nr = 1...4 LTP analysis MPE analysis Search for the best vector Calculate optimal gain Quantize gain Update target vector TBPE analysis Search for the best vector Quantize gain Calculate optimal gain Calculate prediction based on logarithm of MPE pulse mean amplitude * MPE gain Calculate δ Quantize δ Calculate quantized gain State update In this algorithm the LPC analysis is performed on a frame by frame basis, while the remaining steps LTP analysis, MPE excitation, TBPE excitation and state update are performed on a subframe by subframe basis. In the algorithm the MPE and TBPE excitation steps have been expanded to illustrate the steps that are relevant for the present invention. A flow chart illustrating the present invention is given in Fig. 9. Fig. 10 illustrates a speech coder corresponding to the speech coder of Fig. 1, but provided with means for performing the present invention. A gain g 2 corresponding to the optimal vector from fixed code book 16 is determined in block 50. Gain g 2 , quantized gain g ις and the excitation vector energy E (de¬ termined in block 54) are forwarded to block 52, which calcula¬ tes δ Q and quantized gain g 2Q . The calculations are preferably performed by a microprocessor. Fig. 11 illustrates another embodiment of the present inven¬ tion, which corresponds to the example algorithm given above. In this case g 1Q corresponds to an optimal vector from MPE code book 34 with energy E, while gain g 2 corresponds to an optimal excitation vector from TBPE code book 36. Fig. 12 illustrates another embodiment of a speech coder in which a generalization of the method described above is used. Since it has been shown that there is a strong correlation between gains corresponding to two different code books, it is natural to generalize this idea by repeating the algorithm in a case where there are more than two code books. In Fig. 12 a first parameter δ is calculated in block 52 in accordance with the method described above. In this case the first code book is an adaptive code book 14, and the second code book is an MPE code book 34. However, since g 2Q is calculated for the second code book, the process may be repeated by considering the MPE code book 34 as the "first" code book and the TBPE code book 36 as the "second" code book. Thus, block 52' may calculate δ 2 and g 3Q in accordance with the same principles as described above. The difference is that two linear predictions are now required, one for g 2 and one for g 3 , with different constants "a" and "b" . In the above description it has been assumed that the linear prediction is only performed in the current subf ame. However, it is also possible to store gains that have been determined in previous subframes and include these previously determined gains in the linear prediction, since it is likely that there is a correlation between gains in a current subframe and gains in previous subframes. The constants of the linear prediction may be obtained empirically as in the above desctibed embodi¬ ment and stored in coder and decoder. Such a method would further increase the accuracy of the prediction, which would further reduce the dynamic range of δ. This would lead to either improved quality (the available quantization levels for δ cover a smaller dynamic range) or a further reduction of the number of quantization levels. Thus, by taking into account the correlations between gains, the quantization method in accordance with the present in¬ vention reduces the gain bit rate as compared to the indepen¬ dent gain quantization method. The method in accordance with the invention is also still a low complexity method, since the increase in computational complexity is minor. Furthermore, the robustness to bit errors is improved as compared to the vector quantization method. Compared to in¬ dependent quantization, the sensitivity of the gain of the first code book is increased, since it will also affect the quantization of the gain of the second code book. However, the bit error sensitivity of the parameter δ is lower than the bit error sensitivity of the second gain g 2 in independent quanti¬ zation. If this is taken into account in the channel coding, the overall robustness could actually be improved compared to independent quantization, since the bit error sensitivity of δ- quantization is more unequal, which is preferred when unequal error protection is used. A common method to decrease the dynamic range of the gains is to normalize the gains by a frame energy parameter before quantization. The frame energy parameter is then transmitted once for each frame. This method is not required by the present invention, but frame energy normalization of the gains may be used for other reasons. Frame energy normalization is used in the program listing of the APPENDIX. It will be understood by those skilled in the art that various modifications and changes may be made to the present invention without departure from the spirit and scope thereof, which is defined by the appended claims. APPENDIX This APPENDIX summarizes an algorithm for determining the best adaptive code book index i and the corresponding gain g ± in an exhaustive search. The signals are also shown in Fig. 1. ex(n) = p(n) Excitation vector (f(n) = 0) p(n) = g^a^n) Scaled adaptive code book vector §(n) = h(n)*p(n) Synthetic speech (* = convolution) h(n) = impulse response e(n) = s(n) - §(n) Error vector e w (n) = w(n)*(s(n) - s(n) ) Weighted error E = ∑[e w (n)] 2 n=0..N-l Squared weighted error N = 40 (for example) Vector length s w (n) = w(n)*s(n) Weighted speech __„(n) = w(n)*h(n) Weighted impulse response for synthesis filter min E ± = min ∑ [e Wι (n) ] 2 Search optimal index in the adaptive code book N-l dE ∑ s n) -a. in) *h w {n) -fcT ~ ° ~ * 9± = "^^ ϊ Gain for index i £ [a. in) *h w (n) ] 2 .1=0 MAIN.CC /* * class F_SpeMain * * main class for speech encoder * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * */ #include "F_SpeMain.hh" #include <iostream.h> F_SpeMain: :F_SpeMain() : F_speechSave(F_savedSpeechLength) , F_lspPrev(F_nrCoeff) , F_ltpHistory(F_historyLength) , F_weightFilterRingState(F_nrCoeff) , F_syFilterState(F_nrCoeff) { /* clear saved speech */ for (int i=0; i<F_savedSpeechLength; i++) F_speechSave[i] = 0.0; for (i = 0; i < F_nrCoeff; i++) F_lspPrev[i] = F_lsplnit[i] ; for (i=0; i<F_historyLength; i++) F_ltpHistory[i] = 0.0; for (i=0; i<F_nrCoeff; i++) F_weightFilterRingState[i] = 0.0; for (i=0; i<F_nrCoeff; i++) F_syFilterState[i] = 0.0; } /* * function F_SpeMain:main * */ void F_SpeMain: :main(const FloatVec& F_speechFrame, ShortVecfc F_analysisData) /* local variables */ FloatVec F_lspCurr(F_nrCoeff) ; ShortVec F_lspVQCodes(F_nLspTables) ; Float F_energy; Float F_accPower; Shortint F_energyCode; FloatVec F_hpSpeech(F_frameLength) ; ShortVec F_ltpLagCodes(F_nrOfSubframes) ; ShortVec F_ltpGainCodes(F_nrOfSubframes) ; ShortVec F_mpeBlockMaxCodes(F_nrOfSubframes) ; ShortVec F_mpeAmpCodes(F_nrOfSubframes) ; ShortVec F_mpeSignCodes(F_nrOfSubframes) ; ShortVec F_mpePositionCodes(F__nrOfSubframes) ; ShortVec F_tbpeGainCodes(F_nrOfSubframes) ; ShortVec F_tbpeGridCodes(F_nrOfSubframes) ; ShortVec F_tbpeMatrixCodes(F_nrOfSubframes) ; ShortVec F_tbpeIndexCodes(F_nrOfSubframes) ; F_speFrame.main(F_speechFrame, F_lspPrev, F_speechSave, F_lspCurr, F_lspVQCodes, F_energy, F_accPower, F_energyCode, F_hpSpeech) ; for (int F_subframeNr=0; F_subframeNr<F_nrOfSubframes; F_subframeNr++) { /* subframe local variables */ Float F_excNormFactor; FloatVec F_wCoeff(F_nrCoeff) ; FloatVec F_aCoeff(F nrCoeff) ; FloatVec F_wSpeechSubframe(F_subframeLength) ; FloatVec F_impulseResponse(F_subframeLength) ; FloatVec F_ltpExcitation(F_subframeLength) ; FloatVec F_wLtpResidual (F_subframeLength) ; Float F_avgMpeAmp; FloatVec F_mpeInnovation(F_subframeLength) ; FloatVec F_wMpeResidual(F_subframeLength) ; FloatVec F_tbpeInnovation(F_subframeLength) ; F_speSubPre.main(F_hpSpeech, F_subframeNr, F_lspCurr, F_lspPrev, F_energy, F_weightFilterRingState, F_excNormFactor, F_wCoeff, F_aCoeff, F_wSpeechSubframe, F_impulseResponse) ; F_speSubLtp.main(F_wSpeechSubframe, F_wCoeff, F_ltpHistory, F_wLtpResidual, F_ltpExcitation, F_ltpLagCodes [F_subframeNr] , F_ltpGainCodes[F_subframeNr] ) ; F_speSubMpe.main(F_wCoeff, F_excNormFactor, F_wLtpResidual, F_impulseResponse, F_mpeInnovation, F_mpePositionCodes[F_subframeNr] , F_mpeAmpCodes[F_subframeNr] , F__mpeSignCodes[F_subframeNr] , F_mpeBlockMaxCodes[F_subframeNr] , F__wMpeResidual, F_avgMpeAmp) ; F_speSubTbpe.main(F_wMpeResidual, F_wCoeff, F_excNormFactor, F_avgMpeAmp, F_impulseResponse, F_tbpeInnovation, F_tbpeGainCodes[F_subframeNr] , F_tbpeIndexCodes[F_subframeNr] , F_tbpeGridCodes[F_subframeNr] , F_tbpeMatrixCodes[F_subframeNr] ) ; F_speSubPost.main(F_ltpExcitation, F_tbpeInnovation, F_mpeInnovation, F_wCoeff, F_aCoeff, F_ltpHistory, F_weightFilterRingState, F_syFilterState, F accPower) ; } F_spePost.main(F_energy, F_lspCurr, F_accPower, F_energyCode, F_lspVQCodes, F_ltpGainCodes, F_ltpLagCodes, F_mpeBlockMaxCodes, F_mpeAmpCodes, F_mpeSignCodes, F_mpePositionCodes, F_tbpeGainCodes, F_tbpeIndexCodes, F_tbpeMatrixCodes, F_tbpeGridCodes, F_ltpHistory, F_syFilterState, F_lspPrev, F analysisData) ; SPE_DEF.CC /* * module F_speDef * * constant definitions for speech encoder * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * */ #include "F_speDef.hh" #include <iostream.h> #include <math.h> const Float F_tbpeDeltaQuantInit [F_nrTbpeDeltaGainLevel] = { -2.3, -2.04286, -1.78571, -1.52857, -1.27143, -1.01429, -0.757143, -0.5, }; const FloatVec F_tbpeDeltaQuantTable(F_nrTbpeDeltaGainLevel, F_tbpeDeltaQuantInit) ; const Float F_tbpeDeltaLimitInit[F_nrTbpeDeltaGainLevel-l] = { -2.17143, -1.91429, -1.65714, -1.4, -1.14286, -0.885714, -0.628571 }; const FloatVec F_tbpeDeltaLimitTable(F_nrTbpeDeltaGainLevel-l, F_tbpeDeltaLimitInit) ; SUB_MPE.CC /* * class F_SpeSubMpe * * Multipulse innovation analysis * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * */ #include "F_SpeSubMpe.hh" #include "ShortVec.hh" #include <iostream.h> ftinclude <stdlib.h> #include <math.h> F_SpeSubMpe: :F_SpeSubMpe() /* * function F_SpeSubMpe: :main * */ void F_SpeSubMpe: :main( const FloatVec& F_wCoeff, Float F_excNormFactor, const FloatVec& F_wLtpResidual, const FloatVecfc F_impulseResponse, FloatVec& F_mpeInnovation, Shortint& F_mpePositionCode, Shortint& F_mpeAmpCode, Shortint& F_mpeSignCode, Shortint& F_mpeBlockMaxCode, FloatVec& F_wMpeResidual, Floats. F_avgMpeAmp) { /* temporary variables */ FloatVec F_autoCorr(F_subframeLength) ; FloatVec F_crossCorr(F_subframeLength) ; ShortVec F_seqPosVector(F_nMpeSeqPulses) ; FloatVec F__pulseAmp(F_nMpePulses) ; ShortVec F_mpePosVector(F_nMpePulses) ; ShortVec FjmpeAmpVector(F_nMpePulses) ; ShortVec F_mpeSignVector(F_nMpePulses) ; /* calculate autocorrelation */ F_autoCorrelate( F_impulseResponse, F_autoCorr) ; /* calculate cross correlation */ F_crossCorrelate( F_impulseResponse, F_wLtpResidual, F crossCorr) ; /* do sequential search (5 pulses) with no restrictions */ F_searchUnRestricted( F_autoCorr, F_crossCorr, F_seqPosVector) ; /* do reoptimization with respect to possible positions */ F_reoptSearch( F_autoCorr, F_crossCorr, F_impulseResponse, F_wLtpResidual, F_seqPosVector, F_mpePosVector, F__pulseAmp) ; /* quantize blockmax and pulse amplitudes */ F_openLoopQuantize( F_excNormFactor, F_pulseAmp, F_mpeAmpVector, F_mpeSignVector, F_mpeBlockMaxCode) ,- /* make innovation vector */ F_makeInnVector( F_pulseAmp, F_mpePosVector, F_mpeInnovation) ; /* order pulse position */ F_orderPositions( F_mpePosVector, F_mpeAmpVector, F_mpeSignVector) ; /* make codewords position */ F_makeCodeWords( F_mpePosVector, F_mpePositionCode, F_mpeAmpVector, F_mpeAmpCode, F_mpeSignVector, F_mpeSignCode) ; /* make new weigthed residual */ F_makeMpeResidual( F_mpeInnovation, F_wCoeff, F_wLtpResidual, F_wMpeResidual) ; /* compute average pulse amplitude */ F_avgMpeAmp = F_computeAvgAmp( F_excNormFactor, F_pulseAmp) ; /* * function F_SpeSubMpe: :F_maxMagIndex * */ Shortint F_SpeSubMpe: :F_maxMagInde ( const FloatVec& F_corrVec, const ShortVecfc F_posTaken) /* temporary variables */ Float max; Float temp; int i; Shortint maxl = 0; /* init variables */ max = -1; /* find position with greatest correlation * excluding used positions */ for (i=0; i < F_subframeLength ; i++) { temp = fabs(F_corrVec[i] ) ; if ( !F_posTaken[i] ~ ~ temp > max) { max = temp; maxl = i; > } return maxl; /* * function F_SpeSubMpe: :F_maxMagIndexRestr * */ Shortint F_SpeSubMpe: :F_maxMagIndexRestr( const FloatVec& F_corrVec, const ShortVecfc F_phaseTaken) { /* temporary variables */ Float max; Float temp; int i, j ; Shortint maxl = 0; /* init variables */ max = -1; /* find position with greatest correlation * excluding used phases */ for (i = 0; i < F_nMpePhases; i++) if ( !F_phaseTaken[i] ) for (j = i; j < F_subframeLength; j+=F_nMpePhases) { temp = fabs(F__corrVec[j] ) ; if (temp > max) { max = temp; maxl = j ; ) } return maxl; /* * function F_SpeSubMpe: :F_calc20ptAmps * * Compute optimal amplitudes for 2 selected pulses * */ void F_SpeSubMpe: :F_calc20ptAmps( const ShortVec& F_posVec, const FloatVecfc F_autoCorr, const FloatVec& F_crossCorr, FloatVecfc F_optAmp) { /* temporary variables */ FloatVec a(2) ; FloatVec c(2) ; Float den, denlnv; /* init vectors */ a[0] = F_autoCorr t0] ; a [1] = F_autoCorr [abs (F_posVec [0] -F_posVec [1] ) ] ; c[0] = F_crossCorr[F_posVec [0] ] ; c[l] = F_crossCorr [F__posVec[l] ] ; den = a[0] *a[0] -a[l]*a[l] ,- if (den == 0.0) { cerr << "MPE singular 2*2 matrix" << endl; return ; } denlnv = 1.0 /den; F_optAmp[0] = (c[0]*a[0] - c[l]*a[l]) * denlnv ,- F_optAmp[l] = (c[l]*a[0] - c[0]*a[l]) * denlnv ; * * function F_SpeSubMpe: :F_calc30ptAmps * * Compute optimal amplitudes for 3 selected pulses * */ void F_SpeSubMpe: :F_calc30ptAmps( const ShortVec& F_posVec, const FloatVec& F_autoCorr, const FloatVec& F_crossCorr, FloatVec& F_optAmp) /* temporary variables */ FloatVec a(4) ; FloatVec c(3) ; Float den, denlnv; /* init vectors */ a[0] = F autoCorr[0]; a[l] = F_autoCorr[abs(F_posVec [0] -F__ρosVec[l] )] a [2] = F_autoCorr tabs (F_posVec [0] ■ F_posVec[2] )] a [3] = F_autoCorr tabs (F_posVec[l] -F_posVec[2])] c [0] = F_crossCorr [FjposVec [0] ] c[l] = F_crossCorr [F_posVec[l] ] c [2] - F_crossCorr [F_posVec [2] j /* Kramers rule */ den = a[0]* a[0]*a[0]+a[l]*a[3]*a[2]+a[2]*a[l]*a[3]- a[l]* a[l]*a[0]-a[0]*a[3]*a[3]-a[2]*a[0]*a[2] ; if (den == 0.0) { cerr << "MPE singular 3*3 matrix" << endl; return; } denlnv = 1.0 i / / αdeenn; F_optAmp[0] = (c[0]*a[0]*a[0]+c[l]*a[3]*a[2] +c[2]*a[l]*a[3]-c[l]*a[l]*a[0] -c [0] *a [3] *a [3] -c [2] *a [0] *a [2] ) *denlnv ; F_optAmp[l] = (a[0]*c[l]*a[0]+a[l]*c[2]*a[2] +a[2]*c[0]*a[3]-a[l]*c[0]*a[0] -a[0]*c[2]*a[3]-a[2]*c[l]*a[2])ι<*denlnv; F_optAmp[2] )] ) *denlnv; * function F_SpeSubMpe: :F_calc4OptAmps * Compute optimal amplitudes for 4 selected pulses (Cholesky decomposition) 7 void F_SpeSubMpe: :F_calc40ptAmps ( const ShortVec& F_posVec, const FloatVec& F_autoCorr, const FloatVec& F_crossCorr, FloatVec& F_optAmp) { /* temporary variables 7 Shortint i, j , k; Float sum, tmp; FloatVec v(4*4) ; FloatVec w(4*4) ; FloatVec d(4) FloatVec y(4) FloatVec c(4) FloatVec a(4*4) /* init vectors */ for (i=0; i < 4; i++) for (j=0; j <= i; j++) { a[i*4+j] = F_autoCorr [abs (F_posVec [i] -F_posVec [ j ] ) ] a[j*4+i] = a[i*4+j] ; for (i=0 ; i < 4; i++) c[i] = F_crossCorr [F_posVec [i] ] ; /* triangular decomposition */ for (j = 0; j < 4; j++) { sum = a[j*4+j] ; for (k = 0; k < j; k++) { tmp = v[j*4+k] ; sum = sum - tmp * tmp * d [k] ; } if (fabs (sum) < 1.0e-14) { cerr << "MPE singular 4*4 matrix" << endl; for (k = 0; k < 4; k++) F_optAmp[k] = 0; break ; } d[j] = sum; for (i = j + 1; i < 4; i++) { sum = a[i*4+j] ; for (k = 0; k < j ; k++) sum = sum - v[i*4+k] * w[j*4+k] ; w[i*4+j] = sum; v[i*4+j] = sum / d[j] ; /* invert the matrix, and get the solution recursively */ for (i = 0; i < 4; i++) { sum = c [i] ; for (j = 0; j < i; j++) sum = sum - v[i*4+j] * y[j] ; y[i] = sum; /* finally, collect the results */ for (i = 4 - 1; i >= 0; i--) { sum = y[i] / d[i] ; for (j = i + 1; j < 4; j++) sum = sum - v[j*4+i] *F_optAmp [j] ; F_optAmp[i] = sum; } /* * function F_SpeSubMpe: :F_updateCrossCorr * */ void F_SpeSubMpe: :F_updateCrossCorr( const FloatVec& F_autoCorr, const Shortint F_pos, const Float F_gain, FloatVec& F crossCorrUpd) { /* temporary variables */ int i; int temp; /* update crosscorrelation vector */ temp = -F_mpeTruncLen + F_pos + 1; if (temp < 0) temp = 0; for (i = temp; i < F_pos; i++) F_crossCorrUpd [i] = F_crossCorrUpd [i] - F_gain*F_autoCorr[F_pos-i] ; temp = F_pos+F_mpeTruncLen; if (temp > F_subframeLength) temp = F_subframeLength; for (i = F_pos ,- i < temp; i++) F_crossCorrUpd [i] = F_crossCorrUpd [i] - F_gain* F_autoCorr [ i - F_pos ] ; * * function F_SpeSubMpe: :F_autoCorrelate * */ void F_SpeSubMpe: :F_autoCorrelate( const FloatVec& F_impulseResponse, FloatVecfc F autoCorr) { / ♦ temporary variables */ int i, j ; /* calculate autocorrelation vector */ for (i=0; i < F peTruncLen; i++) { F_autoCorr[i] = 0.0; for (j=i; j < F_mpeTruncLen; j++) F_autoCorr[i] = F_autoCorr[i] + F_impulseResponse[j] *F_impulseResponse[j-i] ; }; for (i=F_mpeTruncLen; i < F_subframeLength; i++) F autoCorr[i] = 0.0; } / * * function F_SpeSubMpe: :F_crossCorrelate * */ void F_SpeSubMpe: :F_crossCorrelate( const FloatVec& F_impulseResponse, const FloatVecfc F_wSpeechSubframe, FloatVecδ. F crossCorr) { /* temporary variables */ int i, j, lastpos; /* calculate crosscorrelation vector */ for (i=0; i < F_subframeLength; i++) { F_crossCorr [i] = 0 . 0 ; lastpos = i+F_mpeTruncLen; if (lastpos > F_subframeLength) lastpos = F_subframeLength; for (j=i; j < lastpos; j++) F_crossCorr[i] = F_crossCorr[i] + F_wSpeechSubframe[j] *F_impulseResponse[j-i] ; /* * function F_SpeSubMpe: :F_searchUnRestricted * * Search 5 pulses with no respect to possible positions * */ void F_SpeSubMpe: :F_searchUnRestricted( const FloatVecδ. F_autoCorr, const FloatVecfc F_crossCorr, ShortVecfc F_seqPosVector) { /* temporary variables */ FloatVec F_crossCorrUpd(F_subframeLength) ; FIoatVec F_pulseAmp(F_nMpeSeqPulses-1) ; ShortVec F_posTaken(F_subframeLength) ; int pulse; int i; int pos; /* search init */ for (i=0; i < F_subframeLength; i++) F_posTaken[i] = 0; for (i=0; i < F_subframeLength; i++) F_crossCorrUpd[i] = F_crossCorr[i] ,- /* get first position */ pos = F_maxMagIndex(F_crossCorr, F_posTaken) ; F_seqPosVector[0] = pos; F_posTaken[pos] = ι ; /* update crosscorrelation vector */ F_updateCrossCorr(F_autoCorr, pos, F_crossCorr [pos] /F_autoCorr [0] , F_crossCorrUpd) ; /* get positions 2 through 5 */ for (pulse=l ; pulse < F_nMpeSeqPulses; pulse++) { /* get position with maximum value */ pos = F_maxMagIndex(F_crossCorrUpd, F_posTaken) ; F_seqPosVector[pulse] = pos; F_posTaken[pos] = 1; if (pulse != (F_nMpeSeqPulses-l) ) { /* calculate optimal amplitudes for * selected positions */ switch (pulse+1) { case 2 : F_calc20ptAmps(F_seqPosVector, F_autoCorr, F_crossCorr, F_pulseAmp) ; break; case 3: F_calc3OptAmps(F_seqPosVector, F_autoCorr, F_crossCorr, F_pulseAmp) ; break; case 4: F_calc40ptAmps(F_seqPosVector, F_autoCorr, F_crossCorr, F_pulseAmp) ; break; }; /* update crosscorrelation vector */ for (i=0; i < F_subframeLength; i++) F_crossCorrUpd[i] = F_crossCorr[i] ; for (i=0; i < pulse+1; i++) F_updateCrossCorr(F_autoCorr, F_seqPosVector[i] , F_pulseAmp[i] , F_crossCorrUpd) ; /* * function F_SpeSubMpe: :F_searchRestricted * * search 3 pulses with restriction to possible positions * */ void F_SpeSubMpe: :F_searchRestricted( const FloatVec& F_autoCorr, const FloatVecfc F_crossCorr, ShortVec& F_posVec, ShortVec& F_phaseTaken, FloatVec& F_pulseAmp) /* temporary variables */ FloatVec F_crossCorrUpd(F_subframeLength) ; Shortint pos; int i, pulse; /* update crosscorrelation vector */ for (i=0; i < F_subframeLength; i++) F_crossCorrUpd[i] = F_crossCorr[i] ; F_updateCrossCorr(F_autoCorr, F_posVec[0] , F_pulseAmp[0] , F_crossCorrUpd) ; /* search pulse 2 and 3 */ for (pulse = 1; pulse < F__nMpePulses; pulse++) { pos = F_maxMagIndexRestr(F_crossCorrUpd, F_phaseTaken) ,- F_phaseTaken[pos % F_nMpePhases] = 1; F_posVec[pulse] = pos; /* calculate optimal amplitudes for selected positions*/ switch (pulse+1) { case 2 : F_calc20ptAmps(F_posVec, F_autoCorr, F_crossCorr, F_pulseAmp) ; break; case 3: F_calc3OptAmps(F_posVec, F_autoCorr, F_crossCorr, F_pulseAmp) ; break; } if (pulse != (F_nMpePulses-l) ) { /* update crosscorrelation vector */ for (i=0; i < F_subframeLength; i++) F_crossCorrUpd[i] = F_crossCorr[i] ; for (i=0; i < pulse+1; i++) F_updateCrossCorr(F_autoCorr, F_posVec [i] , F_pulseAmp [i] , F_crossCorrUpd) ; /* * function F_SpeSubMpe: :F_calcMpePredErr * * Calculate prediction error of candidate mpe pulse vector * */ Float F_SpeSubMpe: :F_calcMpePredErr( const ShortVec& F_posVec, const FloatVecfc F_pulseAmp, const FloatVec& F_impulseResponse, const FloatVec& F wTarget) { /* temporary variables */ int pos, start, stop, i; FloatVec error(F_subframeLength) ; Float errorEnergy; /* init error vector */ for (i = 0; i < F_subframeLength; i++) error[i] = F_wTarget [i] ; /* subtract from target a linear combination of * shifted impulse responses */ for(pos = 0; pos < F_nMpePulses; pos++) { start = F posVec[pos] ; stop = start+F_mpeTruncLen; if (stop > F_subframeLength) stop = F_subframeLength• for (i = start; i < stop; i++) error[i] = error[i] - F_pulseAmp[pos] *F_impulseResponse[i-start] ; /* compute energy in resulting errorvector */ errorEnergy = 0; for (i = 0; i < F_subframeLength; i++) errorEnergy = errorEnergy + error[i] *error[i] ; return errorEnergy; /* * function F_SpeSubMpe: :F_reoptSearch * * Do new search with start positions equal to * the previous found 5 positions * */ void F_SpeSubMpe: :F_reoptSearch( const FloatVecfc F_autoCorr, const FloatVecfc F_crossCorr, const FloatVec& F_impulseResponse, const FloatVecfc F_wTarget, const ShortVec& F_seqPosVector, ShortVec& F_mpePosVector, FloatVecfc F_mpePulseAmp) /* updates posEnc and fpulseGain with the best * encodable alternative uses idealPos and * idealPulseGains as starting points * for several sequential searches */ /* temporary variables */ int start, i; Float error, minError,- ShortVec F_phaseTaken(F_nMpePhases) ; ShortVec F_tempPosVec(F_nMpePulses) ; FloatVec F_tempPulseAmp(F_nMpePulses) ; /* init variables */ minError = 1.0e30; /* search for the best out of 5 pulse position * combinations */ for(start = 0; start < F_nMpeSeqPulses; start++) { /* compute first amplitude */ F_tempPulseAmp[0] = F_crossCorr[F_seqPosVector[start] ] /F_autoCorr[0] ; /* reset taken-position vector */ for (i = 0 ; i < F_nMpePhases; i++) F_phaseTaken[i] = 0; /* reserve the phase corresponding to * seqPosVector[start] */ F__phaseTaken[F_seqPosVector[start] % F_nMpePhases] = 1; F_tempPosVec[0] = F_seqPosVector[start] ; F_searchRestricted( F_autoCorr, F_crossCorr, F_tempPosVec, F__phaseTaken, F_tempPulseAmp) ; error = F_calcMpePredErr(F_tempPosVec, F_tempPulseAmp, F_impulseResponse, F_wTarget) ; if(minError > error) { minError = error; for (i = 0; i < F_nMpePulses; i++) { F_mpePulseAmp [i] = F_tempPulseAmp [i] ; F_mpePosVector [i] = F_tempPosVec [i] ; } /* * function F_SpeSubMpe: :openLoopQuantize * */ void F_SpeSubMpe: :F_openLoopQuantize( const Floats. F_excNormFactor, FloatVec& F_pulseAmp, ShortVecS. F_mpeAmpVector, ShortVecS. F_mpeSignVector, Shortint& F_mpeBlockMaxCode) { /* temporary variables */ Float blockMax; Float idealBlockMax; Float blockMaxNorm; Float normPulseAmp; int pulse; Float temp; /* get blockmax value */ blockMax = 0.0; for (pulse=0 ; pulse < F_nMpePulses,- pulse++) { temp = fabs(F_pulseAmp[pulse] ) ; if (temp > blockMax) blockMax = temp; } idealBlockMax = blockMax; /* quantize blockmax */ blockMaxNorm = blockMax / F_excNormFactor; if (blockMaxNorm > F_mpeBlockMaxQLimits [F_nMpeBlockMaxQLevels - 2]) F_mpeBlockMaxCode = F_nMpeBlockMaxQLevels - 1; else { F_mpeBlockMaxCode=0; while (blockMaxNorm > F_mpeBlockMaxQLimits [F_mpeBlockMaxCode] ) F_mpeBlockMaxCode++; blockMax = F_mpeBlockMaxQLevels [F_mpeBlockMaxCode] * F_excNormFactor; /* quantize pulse amplitudes */ for (pulse = 0; pulse < F_nMpePulses; pulse++) { normPulseAmp = fabs(F_pulseAmp[pulse] ) /blockMax; if (normPulseAmp > F_mpeAmpQLimits[F_nMpeAmpQLevels - 2]) ' F_mpeAmpVector[pulse] = F_nMpeAmpQLevels - 1; else { F_mpeAmpVector[pulse] = 0; while (normPulseAmp > FjmpeAmpQLimits [F_mpeAmpVector[pulse] ] ) F__mpeAmpVector[pulse] ++; if (F_pulseAmp[pulse] > 0.0) { F_mpeSignVector[pulse] = 1; F_pulseAmp[pulse] = F_mpeAmpQLevels [F_mpeAmpVector[pulse] ] * blockMax; } else { F_mpeSignVector[pulse] = 0; FjpulseAmp[pulse] = -1.0 * F_mpeAmpQLevels [F_mpeAmpVector[pulse] ] * blockMax; } } * * function F_SpeSubMpe: :F_makeInnVector * */ void F_SpeSubMpe: :F_makeInnVector( const FloatVecfc F_pulseAmp, const ShortVecSc F_mpePosVector, FloatVecfc F_mpeInnovation) /* temporary variables */ int i; /* create innovation vector */ for (i=0; i < F_subframeLength; i++) F_mpeInnovation[i] = 0.0; for (i = 0; i < F_nMpePulses; i++) F_mpeInnovation[F_mpePosVector[i] ] = F__pulseAmp[i] ; '* * function F_SpeSubMpe: :F_orderPositions * */ void F_SpeSubMpe: :F_orderPositions( ShortVecS. F_mpePosVector, ShortVec& F_mpeAmpVector, ShortVec& F_mpeSignVector) { /* temporary variables */ ShortVec tempPosVector(F_nMpePulses) ; ShortVec tempAmpVector(F_nMpePulses) ; ShortVec tempSignVector(F_nMpePulses) ; int maxVal, maxPhase; int maxl = 0; int i, j ; /* Create temporary vectors */ for (i = 0; i < F_nMpePulses; i++) { tempPosVector[i] = F_mpePosVector[i] ; tempAmpVector[i] = F_mpeAmpVector[i] ; tempSignVector[i] = F_mpeSignVector[i] ; /* fix ordering, the position phases are ordered * decreasingly */ for (i = 0; i < F_nMpePulses; i++) { maxVal = -1; maxPhase = -1; for (j = 0; j < F_nMpePulses; j++) { if ( (tempPosVector[j] % F_nMpePhases) > maxPhase ~ ~ tempPosVector[j] != -10) { maxPhase = tempPosVector[j] % F_nMpePhases; maxVal = tempPosVector[j] ; maxl = j ; . } /* exclude found vector from search */ tempPosVector[maxl] = -10; /* order pulses */ F_mpePosVector[i] = maxVal; F_mpeAmpVector[i] = tempAmpVector[maxl] ; F_mpeSignVector[i] = tempSignVector[maxl] ; /* * function F_SpeSubMpe:F_makeCodeWords * */ void F_SpeSubMpe: :F_makeCodeWords( const ShortVecS. F_mpePosVector, Shortint& F_mpePositionCode, const ShortVecS. F_mpeAmpVector, ShortintS. F_mpeAmpCode, const ShortVecS. F_mpeSignVector, Shortint5. F_mpeSignCode) { /* temporary variables */ int i, phaselndex; /* code position vector into 13 bits */ /* put phase indices into codeword */ phaselndex = 0; for (i = 0; i < F_nMpePulses; i++) phaselndex += (1 << (F_mpePosVector[i] % F_nMpePhases) ) ; FjmpePositionCode = F_mpePhaseCodeTable[phaselndex] ; /* put group indices */ for (i = F_nMpePulses-l; i >= 0; i--) { FjmpePositionCode <<= F_nMpeGroupBits; FjmpePositionCode |= FjmpePosVector[i] /F_nMpePhases; /* code Mpe signs */ F npeSignCode = 0; for (i = 0; i < F nMpePulses ; i++) F_mpeSignCode T= (F_mpeSignVector[i] << i) ; /* code Mpe amps */ F_mpeAmpCode = 0; for (i = 0; i < F_nMpePulses ; i++) F_mpeAmpCode |= (F_mpeAmpVector[i] << i*F_mpeAmpBits) ; * * function F_SpeSubMpe: :F_makeMpeResidual * */ void F_SpeSubMpe: :F_makeMpeResidual ( const FloatVecS- Fjmpelnnovation, const FloatVecs. F wCoeff, const FloatVecS FjwLtpResidual, FloatVecSc FjwMpeResidual) /* temporary variables */ int i, m; Float signal; FloatVec state(F nrCoeff) ; /* set zero state */ for (i=0; i < FjnrCoeff; i++) state[i] = 0.0; /* calculate new target for subsequent TBPE search */ for (i=0; i < FjsubframeLength; i++) { signal = F_mpeInnovation[i] ; for (m=F_nrCoeff-l; m>0; m--) { signal -= FjwCoeff[m] *state[m] ; state[m] = state[m-1] ; } signal -= FjwCoeff[0] *state[0] ; state[0] = signal; FjwMpeResidual [i] = FjwLtpResidual [i] -signal; * * function F_SpeSubMpe: :F_computeAvgAmp * */ Float F_SpeSubMpe: :F_computeAvgAmp( Float F_excNormFactor, const FloatVecS. F_pulseAmp) /* temporary variables */ Float temp; int i; /* compute average pulse amplitude */ temp = 0; for (i = 0; i < F_nMpePulses ; i++) temp = temp + fabs(F_pulseAmp[i] ) ; temp = temp/(F_nMpePulses*F_excNormFactor) ; return temp; SUB_TBPE.CC /* * class F_SpeSubTbpe * * Transformed Binary Pulse Excited codebook * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * */ #include "F_SpeSubTbpe.hh" #include <iostream.h> #include <math.h> F_SpeSubTbpe: :F_SpeSubTbpe() /* * function F_SpeSubTbpe: :main * */ void F_SpeSubTbpe: :main(const FloatVecfc FjwMpeResidual, const FloatVecs. F_wCoeff, const Floats. F_excNormFactor, const Float- F_avgMpeAmp, const FloatVecs. F_impulseResponse, FloatVec& F_tbpeInnovation, ShortintS- F_tbpeGainCode, ShortintS. F_tbpeIndexCode, ShortintS. F_tbpeGridCode, ShortintS. F tbpeMatrixCode) { Float F_optGain = F_search(FjwMpeResidual, FjwCoeff, F_impulseResponse, F_tbpeInnovation, F_tbpeIndexCode, F_tbpeGridCode, F_tbpeMatrixCode) ; Float F_tbpeGain; F_gainQuant( F_excNormFactor, F_avgMpeAmp, F_optGain, F_tbpeGainCode, F_tbpeGain) ; for(Shortint i = 0; i < F_subframeLength; i++) F_tbpeInnovation[i] = F_tbpeInnovation[i] * F_tbpeGain; } /* * function F_SpeSubTbpe: :F_crossCorr * */ void F_SpeSubTbpe: :F_crossCorr(const FloatVecs. vl, const FloatVecs. v2, FloatVecs. F corr) { for (Shortint i = 0; i < F_subframeLength; i++) { Float ace = 0.0; for (Shortint j = i ; j < F_subf rameLength; j ++) ace += vl [j ] * v2 [j - i] ; F corr [i] = ace; } " /* * function F_SpeSubTbpe: :F_crossCorrOfTransfMatrix * */ void F_SpeSubTbpe: :F_crossCorrOfTransfMatrix(const FloatVecs. vl, const Shortint gri const Shortint matrix, FloatVecs. F_crossCorr) for (Shortint m = 0; m < F_nrTbpePulses; m++) { Float ace = 0.0; for (Shortint n = 0; n < FjnrTbpePulses; n++) ace += vl[grid + n * F_tbpeGridSpace] * F_tbpeTransfTable[ (m+matrix * FjnrTbpePulses) * FjnrTbpePulses + n] ; F crossCorr[m] = ace; > > " /* * function F_SpeSubTbpe: :F_zeroStateFilter * */ void F_SpeSubTbpe: :F_zeroStateFilter(const FloatVecs. in, const FloatVecSi F_denCoeff, FloatVecSi out) { /* zero state search filter */ FloatVec F_state(FjnrCoeff) ; for (int i=0; i < FjnrCoeff; i++) F_state[i] = 0.0; for (i = 0; i < F_subframeLength; i++) { Float signal = in[i] ; for (Shortint m = F_nrCoeff-l; m > 0; m--) { signal -= F_denCoeff[m] * F_state[m] ; F state[m] = F_state[m-1] ; } " signal -= F_denCoef f [0] * F_state [0] ; F_state [0] = signal ; out [i] = signal ; /* * function F_SpeSubTbpe: :F_construct * */ void F_SpeSubTbpe: :F_constrxιct(const Shortint index, const Shortint grid, const Shortint matrix, FloatVecSi vec) /* zero result vector */ for (int i=0; i < F_subframeLength; i++) vec[i] = 0.0; for (Shortint j=0; j < FjnrTbpePulses; j++) { Float sum = 0.0; Shortint itemp = index; for (Shortint i=0; i < FjnrTbpePulses; i++) { if (itemp Si 1) sum += F_tbpeTransfTable[ (i+matrix*FjnrTbpePulses)*F_nrTbpePulses+j] ; else sum -= F_tbpeTransfTable[ (i+matrix*FjnrTbpePulses) *F_nrTbpePulses+j] ; itemp >>= 1; vec[grid + j * F tbpeGridSpace] = sum; ) - } : /* * function F_SpeSubTbpe: :F_calcPower * */ void F_SpeSubTbpe: :F_calcPower(const FloatVecSi F_in, FloatSi F_power) F_power = 0.0; for (int i=0; i<F_subframeLength; i++) F po er += F in[i]*F in[i]; } /* * function F_SpeSubTbpe: :F_calcCorr * */ void F_SpeSubTbpe: :F_calcCorr(const FloatVecSi F_cross, const FloatVecSi F_signVector, FloatSi F corr) F_corr = 0.0; for (int i=0; i<F_nrTbpePulses; i++) F_corr += F_cross [i] *F_signVector [i] ; /* * function F_SpeSubTbpe: :F_decision * */ void F_SpeSubTbpe: :F_decision(const Float F_corr, const Float F power, const Shortint F_index, const Shortint F_grid, const Shortint F_matrix, FloatSi F_bestCorr, FloatSi F_bestPower, ShortintSi F_bestlndex, ShortintS F_bestGrid, ShortintSi F_bestMatrix, ShortintSc F_updated) { F_updated = 0; if (F_corr * F_corr * F bestPower > F bestCorr * F bestCorr * F_power) { F_bestCorr = F_corr,- F_bestPower = Fjpower; F_bestIndex = F_index; F bestGrid = F_grid; F_bestMatrix = Fj atrix; F_updated = 1; * function F_SpeSubTbpe: :F_search F_zeroStateFilter 8 F_calcPower 8 F_calcCorr 8 F_decision 8 F_crossCorr 1 F_crossCorrOfTransfMatrix 8 F construct 9 7 Float F_SpeSubTbpe: :F_search(const FloatVecSi F_wMpeResidual, const FloatVecSi F_wCoeff, const FloatVecSi F_impulseResponse, FloatVecSi F_tbpeInnovation, ShortintSi F_tbpeIndexCode, ShortintSi F_tbpeGridCode, ShortintSi F_tbpeMatrixCode) FloatVec F_filtered(F_subframeLength) ; /* compute correlation between impulse response and speech */ FloatVec F_corrIS(F_subframeLength) ; F_crossCorr(F_wMpeResidual, F_impulseResponse, F_corrIS) ; /* test for all grids and all matrices */ Float F_bestCorr = 0.0; Float F_bestPower = 1.0; F_tbpeIndexCode = 0; F_tbpeGridCode = 0; F_tbpeMatrixCode = 0; for (Shortint Fjmatrix = 0; Fjmatrix < FjnrTbpeMatrices; F_matrix++) for (Shortint F_grid = 0; F_grid < F_nrTbpeGrids; F_grid++) { /* calculate cross correlations */ FloatVec F_cross(F_nrTbpePulses) ,- F_crossCorrOfTransfMatrix(F_corrIS, F_grid, Fjmatrix, F_cross) ; /* approximate the pulses with sign of cross correlation */ Shortint F_index = 0; FloatVec F_signVector(FjnrTbpePulses) ; for (int i = 0; i < F_nrTbpePulses; i++) F_signVector[i] = -1.0; for (i = 0; i < FjnrTbpePulses; i++) if (F_cross[i] > 0) { F_signVector[i] = 1; F_index |= (l<<i) ; /* construct filtered excitation vector */ F_construct(F_index, F_grid, Fjmatrix, F_tbpeInnovation) F_zeroStateFilter(F_tbpeInnovation, F_wCoeff,F_filtered) /* compute power and correlations */ Float F_power; Float F_corr; F_calcPower(F_filtered, F_power) ; F_calcCorr(F_cross, F_signVector, F_corr) ; /* make decision */ Shortint F_updated; F decision(F corr, F_power, F_index, F_grid, Fjmatrix, F_bestCorr, F_bestPower, F_tbpeIndexCode, F_tbpeGridCode, F_tbpeMatrixCode, F updated) ; } F_construct(F_tbpeIndexCode, F_tbpeGridCode, F_tbpeMatrixCode, F_tbpeInnovation) ,- return F bestCorr/F bestPower; /* * function F_SpeSubTbpe: :F_gainQuant * */ void F_SpeSubTbpe: :F_gainQuant( const FloatSi F_excNormFactor, const FloatSi F_avgMpeAmp, const FloatSi F_optGain, ShortintSi F_tbpeGainCode, FloatSi F tbpeGain) { Float F_logGain; if (F_optGain>0) /* sanity check */ F_logGain = log(F_optGain) ; else { F_logGain = F_tbpeDeltaQuantTable[0] ; cerr << "ERROR: F_SpeSubTbpe: :F_gainQuant: F_optGain <= 0" << endl; } Float F_predGain; if ( (F_excNormFactor>0) SiSc (F_avgMpeAmp>0) ) /* sanity check */ F_predGain = log(F_excNormFactor)+ F_tbpeDeltaPredCoeff*log(F_avgMpeAmp) ; else { F_predGain = F_tbpeDeltaQuantTable[0] ; cerr << "ERROR: F_SpeSubTbpe: :F_gainQuant: F_excNormFactor <= 0 or F avgMpeAmp <= 0" << endl; } Float F_delta = F_logGain - F_predGain; F_tbpeGainCode = F_quantize(F_delta) ; F_tbpeGain = exp(F_predGain + F_tbpeDeltaQuantTable[F_tbpeGainCode] ) ; function F_SpeSubTbpe: :F_quantize */ Shortint F SpeSubTbpe: :F_quantize(const Float value) { Shortint i = 0; if (value > F_tbpeDeltaLimitTable[F_nrTbpeDeltaGainLevel - 2]) i = FjnrTbpeDeltaGainLevel - 1; else while (value > F_tbpeDeltaLimitTable[i] ) i++; return i; } MAIN . HH /* * class F_SpeMain * * main class for speech encoder * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * */ #ifndef F_SpeMain_h #define F_SpeMain_h #include "F_speDef.hh" #include "F_SpeFrame.hh" #include "F_SpeSubPre.hh" #include "F_SpeSubLtp.hh" #include "F_SpeSubMpe.hh" #include "F_SpeSubTbpe.hh" #include "F_SpeSubPost.hh" #include "F_SpePost.hh" class F_SpeMain { public: F_SpeMain() ; /* in, first samples */ /* constructor void main( const FloatVecSc F_speechFrame, /* in, 16 bit speech frame */ ShortVecSc F_analysisData) ; /* out, analysis data frame */ /* main routine */ private: F_SpeFrame F_speFrame; /* frame processing */ F_SpeSubPre F_speSubPre; /* subframe pre processing */ F_SpeSubLtp F_speSubLtp; /* LTP analysis */ F_SpeSubMpe F_speSubMpe; /* MPE analysis */ F_SpeSubTbpe F_speSubTbpe; /* TBPE analysis */ F_SpeSubPost F_speSubPost; /* subframe post processing */ F_SpePost F_spePθSt; /* post processing */ FloatVec F_speechSave; /* speech saved between * * frames */ FloatVec F_lspPrev; /* previous LSP parameters */ FloatVec F_ltpHistory; /* LTP history */ FloatVec FjweightFilterRingState; /* Weighting filter * ringing states */ FloatVec F_syFilterState; /* Synthesis filter states */ }; #endif SPE_DEF.HH /* * module F_speDef * * constant definitions for speech encoder * */ ttifndef F_speDef_h #define F_speDef_h #include "typedefs.h" #include "FloatVec.hh" #include "ShortVec.hh" #include "LongVec.hh" const Float F_tbpeDeltaPredCoeff = 1.03; /* Delta prediction coefficient */ extern const FloatVec F_tbpeDeltaQuantTable; /* Quantizer table for TBPE delta gain */ extern const FloatVec F_tbpeDeltaLimitTable; /* Limits for gain delta quantizer*/ #endif SUBjMPE.HH /* * class F_SpeSubMpe * * Multipulse innovation analysis * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * */ ttifndef F_SpeSubMpe_h #define F_SpeSubMpe_h #include "F_speDef.hh" class F_SpeSubMpe { public: F_SpeSubMpe() ; /* constructor */ void main( const FloatVecSi F_wCoeff, Float F_excNormfactor, const FloatVecSi F_wLtpResidual, const FloatVecSi F_impulseResponse, FloatVecSi FjmpeInnovation, ShortintSi FjmpePositionCode, ShortintSi FjpeAmpCode, ShortintSc FjmpeSignCode, ShortintSi FjmpeBlockMaxCode, FloatVecSi FjwMpeResidual, FIoat ~ F_avgMpeAmp) ,- /* Main routine for module F_SpeSubMpe Shortint FjmaxMaglndex( const FloatVecSc F_corrVec, /* in */ const ShortVecSi F_posTaken) ; /* in */ /* Search for pulse position with max correlation so far */ Shortint Fj axMaglndexRestr( const FloatVecSi F_corrVec, /* in */ const ShortVecSi F_phaseTaken) ; /* in */ /* Search for pulse position with max correlation so far */ void F_calc20ptAmps( const ShortVecSi F_posVec, /* in */ const FloatVecSc F_autoCorr, /* in */ const FloatVecSi F_crossCorr, /* in */ FloatVecSi F_optAmp) ; /* out */ /* Solve for 2 optimal amplitudes */ void F_calc30ptAmps( const ShortVecSi F posVec, /* in */ const FloatVecSi F_autoCorr, /* in */ const FloatVecSi F_crossCorr, /* in */ FloatVecSi F_optAmp) ; /* out */ /* Solve for 3 optimal amplitudes */ void F_calc40ptAmps( const ShortVecSi F_posVec, /* in */ const FloatVecSi F_autoCorr, /* in */ const FloatVecSi F_crossCorr, /* in */ FloatVecSi F_optAmp) ; /* out */ /* Solve for 4 optimal amplitudes */ void F_updateCrossCorr( const FloatVecSi F_autoCorr, const Shortint F_pos, const Float F_gain, FloatVecSi F_crossCorrUpd) ; /* Update crosscorrelation vector void F_autoCorrelate( const FloatVecSi F_impulseResponse, /* in */ FloatVecSi F_autoCorr) ; /* out */ /* Compute autocorrelation vector of impulse response */ void F_crossCorrelate( const FloatVecSi F_impulseResponse, /* in */ const FloatVecSi F_wLtpResidual, /* in */ FloatVecSi F_crossCorr) ; /* out */ /* Compute crosscorrelation between input speech * and impulse response */ void F_searchUnRestricted( const FloatVecSi F_autoCorr, /* in */ const FloatVecSi F_crossCorr, /* in */ ShortVecS F_seqPosVector) ; /* out */ /* Search for 5 pulses with no restrictions regarding * possible positions */ void F_searchRestricted( const FloatVecSc F_autoCorr, /* in */ const FloatVecSi F_crossCorr, /* in */ ShortVecSi F_posVec, /* in */ ShortVecSi F_phaseTaken, /* in */ FloatVecSi FjpulseAmp) ; /* in */ /* Search for 3 pulses with restrictions regarding * possible positions */ Float F_calcMpePredErr( const ShortVecSi F_posVec, /* in */ const FloatVecSi F_jpulseAmp, /* in */ const FloatVecSi F_impulseResponse, /* in */ const FloatVecSi FjwTarget) ; /* in */ /* Calculate the prediction gain of the candidate * mpe vector */ void F reoptSearch( const FloatVecSi F_autoCorr, /* in */ const FloatVecSi F_crossCorr, /* in */ const FloatVecSi F_impulseResponse, /* in */ const FloatVecSi F_wTarget, /* in */ const ShortVecSi F_seqPosVector, /* in */ ShortVecSi FjmpePosVector, /* out */ FloatVecSi FjmpePulseAmp) ; /* out /* Find the position combination that gives * the best prediction gain */ void F_openLoopQuantize( const FloatSi F_excEnergy, FloatVecSi FjpulseAmp, ShortVecSi FjmpeAmpVector, ShortVecSi FjmpeSignVector, ShortintSi FjmpeBlockMaxCode) ; /* Calculate blockMax and openloop quantize * blockmax and pulses */ void Fj akelnnVector( const FloatVecSi F_pulseAmp, /* in */ const ShortVecSi FjmpePosVector, /* in */ FloatVecSi Fjmpelnnovation) ; /* out * / /* Make innovation vector */ void F_orderPositions( ShortVecSi FjmpePosVector, /* in/out */ ShortVecSi FjmpeAmpVector, /* in/out */ ShortVecSi FjmpeSignVector) ; /* in/out */ /* Order positions (optimum position encoding) */ void FjmakeCodeWords( const ShortVecSi FjmpePosVector, /* in */ ShortintSi FjmpePositionCode, /* out */ const ShortVecSi FjmpeAmpVector, /* in */ ShortintSi FjmpeAmpCode, /* out */ const ShortVecSi FjmpeSignVector, /* in */ ShortintSi FjmpeSignCode) ; /* out */ /* Construct codewords */ void FjmakeMpeResidual( const FloatVecSi Fjmpelnnovation, /* in */ const FloatVecSi F_wCoeff, /* in */ const FloatVecSi F_wLtpResidual, /* in */ FloatVecSi FjwMpeResidual) ,- /* out */ /* Make new weigthed residual with MPE contribution * removed */ Float F_computeAvgAmp( Float F_excNormFactor, /* in */ const FloatVecSi F_pulseAmp) ; /* in */ /* Compute average multipulse amplitude */ }; ttendif SUBJTBPE.HH /* * class F_SpeSubTbpe * * Transformed Binary Pulse Excited codebook * * COPYRIGHT (C) 1995 ERICSSON RADIO SYSTEMS AB * / #ifndef F_SpeSubTbpe_h #define F_SpeSubTbpe_h #include "F_speDef.hh" ttinclude "FloatVec.hh" class F_SpeSubTbpe { public: F_SpeSubTbpe() ; /* constructor */ void F_SpeSubTbpe: :main( const FloatVecSi F_wMpeResidual, /* in, Weighted MPE * residual = */ * F_wLtpResidual with MPE*/ const FloatVecSi F_wCoeff, /* in, weighted direct form * coeff */ const FloatSi F_excNormFactor, /* in, Excitation * normalization factor */ const FloatSi F_avgMpeAmp, /* in, average MP * amplitude */ const FloatVecSi F_impulseResponse, /* in, impulse response for * the search filter */ FloatVecSi F_tbpeInnovation, /* out, TBPE innovation, * quantized gain included*/ ShortintSi F_tbpeGainCode, /* out, TBPE gain code */ ShortintSi F_tbpeIndexCode, /* out, TBPE pulse * sign code */ ShortintSi F_tbpeGridCode, /* out, TBPE grid code */ ShortintSc F_tbpeMatrixCode) ;/* out, TBPE transform * matrix code */ /* Main routin for TBPE codebook search */ void F_crossCorr( const FloatVecSi vl, /* in, Target vector 1 */ const FloatVecSi v2, /* in, Target vector 2 */ FloatVecSc F corr) ; /* out, Cross correlated * vector */ /* Calculate cross correlation */ void F_crossCorrOfTransfMatrix( const FloatVecSi vl, /* in, Target vector */ const Shortint grid, /* in, The grid number */ const Shortint matrix, /* in, The matrix number */ FloatVecSc F_crossCorr) ; /* out, Cross correlated * vector */ /* Calculate cross correlation for the * transformation matrix */ void F_zeroStateFilter( const FloatVecSi in, /* in, Vector to be * filtered */ const FloatVecSi F_denCoeff, /* in, Direct form * coefficient */ FloatVecSi out); . /* out, Filtered vector */ /* Zero state filter with coefficients F_denCoeff */ void F_construct( const Shortint index, /* in, Index code */ const Shortint grid, /* in, Grid code*/ const Shortint matrix, /* in, Matrix code */ FloatVecSi vec) ; /* out, Constructed * excitation */ /* Construct a excitation vector */ void F_calcPower( const FloatVecSi F_in, /* in, input vector */ FloatSi F__power) ; /* out, power of input * vector */ /* Calculate power of input vector */ void F_calcCorr( const FloatVecSi F_cross, /* in, cross corr of * transf matrix */ const FloatVecSi F_signVector, /* in, vector of signs */ FloatSi F_corr) ; /* out, correlation of * input vectors */ /* Calculate power of input vector */ void F_decision( const Float F_corr, const Float F_power, const Shortint F_index, const Shortint F_grid, const Shortint Fjmatrix, FloatSc F_bestCorr, FloatSc F_bestPower, ShortintSc F_tbpeIndexCode, index */ ShortintSi F_tbpeGridCode, /* in/out, saved best grid*/ ShortintSi F_tbpeMatrixCode, /* in/out, saved best * matrix */ ShortintSi F_updated) ; /* out, TRUE if parameters * has been updated, * used for testing only */ /* Make decision */ Float F_search( const FloatVecSi FjwMpeResidual, /* in, Weighted MPE residual = FjwLtpResidual * with MPE innovation removed */ const FloatVecSi FjwCoeff, /* in, Weighted direct form coeffs */ const FloatVecSi F_impulseResponse, /* in, impulse response for the search filter*/ FloatVecSc F_tbpeInnovation, /* out, TBPE innovation, quantized gain included */ ShortintSi F_tbpeIndexCode, /* out, TBPE pulse sign code */ ShortintSc F_tbpeGridCode, /* out, TBPE grid code */ ShortintSc F_tbpeMatrixCode) ; /* out, TBPE transform matrix code */ /* search for best index, * approximate index with sign of correlation, * examine all grids and matrices * return optimal innovation, gainCode, index, grid, matrix */ void F_gainQuant( const FloatSi F_excNormFactor, /* in, Excitation normalization factor */ const FloatSi F_avgMpeAmp, /* in, average MP amplitude */ const FloatSi F_optGain, /* in, optimal TBPE gain */ ShortintSi F_tbpeGainCode, /* out, TBPE gain code */ FloatSc F_tbpeGain) ; /* out, TBPE gain */ /* Predict and quantize TBPE gain */ Shortint F_quantize( const Float value) ; /* in, value to be quantized */ /* Quantize TBPE gain */ }; #endif REFERENCES [1] P. Kroon, E. Deprettere, "A class of Analysis-by-Synthesis predictive coders for high quality speech coding at rates between 4.6 and 16 kbit/s.", IEEE Jour. Sel. Areas Com., Vol. SAC-6, No. 2, Feb. 1988 [2] N. Moreau, P. Dymarski, "Selection of Excitation Vectors for the CELP Coders", IEEE transactions on speech and audio processing, Vol. 2, No 1, Part 1, Jan. 1994 [3] I. A. Gerson, M. A. Jasiuk, "Vector Sum Excited Linear Prediction (VSELP) ", Advances in Speech Coding, Ch. 7, Kluwer Academic Publishers, 1991 [4] R. Salami, C. Laflamme, J. Adoul, "ACELP speech coding at 8 kbit/s with a 10 ms frame: A candidate for CCITT." IEEE Workshop on Speech Coding for telecommunications, Sainte-Adele, 1993 [5] P. Hedelin, A. Bergstrόm, "Amplitude Quantization for CELP Excitation Signals", IEEE ICASSP -91, Toronto [6] P. Hedelin, "A Multi-Stage Perspective on CELP Speech Coding", IEEE ICASSP -92, San Francisco [7] B. Atal, J. Remde, "A new model of LPC excitation for producing natural-- sounding speech at low bit rates", IEEE ICASSP-82, Paris, 1982. [8] R . Salami , "Binary pulse excitation: A novel approach to low com¬ plexity CELP coding", Kluwer Academic Pub., Advances in speech coding, 1991.

Claims: CLAIMS 1. A gain quantization method for excitations in analysis-by- synthesis linear predictive speech coding, comprising the steps of: determining an optimal first gain for an optimal first vector from a first code book; quantizing said optimal first gain; determining an optimal second gain for an optimal second vector from a second code book; determining a first linear prediction of the logarithm of said optimal second gain from at least said quantized optimal first gain; and quantizing a first difference between the logarithm of said optimal- second gain and said first linear prediction. 2. The method of claim 1, wherein said first linear prediction includes the logarithm of the product of said quantized optimal first gain and a measure of the square root of the energy of said optimal first vector. 3. The method of claim 2, wherein said first code book is an adaptive code book and said second code book is a fixed code book. 4. The method of claim 2, wherein said first code book is a multi-pulse excitation code book and said second code book is a transformed binary pulse excitation code book. 5. The method of claim 3 or 4, wherein said measure comprises the square root of the sum of the squares of the components of said optimal first vector. 6. The method of claim 4, wherein said measure comprises the average pulse amplitude of said optimal first vector. 7. The method of claim 1, comprising the further steps of: determining and quantizing said optimal second gain from said quantized first difference; determining an optimal third gain for an optimal third vector from a third code book; determining a second linear prediction of the logarithm of said optimal third gain from at least said quantized optimal second gain; and quantizing a second difference between the logarithm of said optimal third gain and said second linear prediction. 8. The method of claim 7, wherein said first code book is an adaptive code book, said second code book is a multi-pulse excitation code book and said third code book is a transformed binary pulse excitation code book. 9. The method of claim 1, wherein said first linear prediction also includes quantized gains from previously determined excita¬ tions. 10. The method of claim 7, wherein said first and second linear predictions also include quantized gains from previously determined excitations.

Inventors: TIMNER YLVA, TIMNER, YLVA
Applicants: ERICSSON TELEFON AB L M, TIMNER YLVA, TELEFONAKTIEBOLAGET LM ERICSSON (PUBL), TIMNER, YLVA
Application year: 1996
Main classification: G10L9
IPC codes: G10L19, H03M7