The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Детектирование DTMF

Детектирование DTMF

Предыдущая  Содержание  Следующая  V*D*V

Для детектирования DTMF сигналов применяют два метода.

Первый основан на алгоритме детектирования сигналов с неизвестной начальной фазой. По этому методу вычисляются скалярные произведения входного сигнала с 2-мя образцами, один из которых сдвинут по фазе на 90 град. относительно другого. В результате получаются 2 проекции на взаимно перпендикулярные оси. Далее по формуле прямоугольного треугольника вычисляется полная амплитуда взаимного совпадения. Недостатком является необходимость иметь два массива с предварительно рассчитанными коэффициентами для синуса и косинуса для каждой частоты. Данный метод используется в АОН. Его использование там обусловлено простотой расчёта: в АОН используется только 2 значения сигнала 1 - больше нуля, 0 - меньше нуля. Таким образом, вместо умножения достаточно сделать логическое И или ИСКЛЮЧАЮЩЕЕ ИЛИ между отсчётом входного сигнала и коэффициентами.

 

Второй метод использует БИХ-фильтры 2-го порядка, настроенные на необходимые частоты. Вычисление мощности сигнала заменено на вычисление квази-мощности. Алгоритм требует меньше памяти, так как для каждой частоты используется только один наперёд рассчитанный коэффициент.

 

Ниже приведены алгоритмы, использующие оба метода для детектирования DTMF и отдельных частот. Для устранения чувствительности к амплитуде входного сигнала используется нормировка по мощности. Подобный метод можно применять, если амплитуда сигнала изменяется в широких пределах.

 

Хорошие результаты также достигаются другим способом: с помощью порога отсекаются низкие уровни, а дальше за счёт финальной проверки убеждаемся в наличии именно DTMF:

проверяем, что амплитуды сигналов  с максимальными уровнями не сильно отличаются

проверяем, что на остальных частотах сигналы существенно слабее

 

Реализация корреляционного алгоритма

/*******************************************************

* детектирование DTMF и однотональных сигналов

*

--------------

использование:

 ToneDetector td = new ToneDetector();

 if( td.initDTMF( ... ) )

 {

         td.setThreshold( 0.5f );

         ...

         for( int i = 0; i < sampleCount; i++ )

         {

                 byte code = td.process( sample[i] );

                 if( code > 0 )

                 {

                         ...

                 }

         }

 }

********************************************************

tones:

350 Hz                dialtone

440 Hz                ring, dialtone

480 Hz                ring, busy

620 Hz                busy

 

697 Hz                dtmf row 1

770 Hz                dtmf row 2

852 Hz                dtmf row 3

941 Hz                dtmf row 4

1209 Hz                dtmf col 1

1336 Hz                dtmf col 2

1477 Hz                dtmf col 3

1633 Hz                dtmf col 4

 

700 Hz                blue box 1

900 Hz                blue box 2

1100 Hz                blue box 3

1300 Hz                blue box 4

1500 Hz                blue box 5

1700 Hz                blue box 6

2400 Hz                blue box 7

2600 Hz                blue box 8

*******************************************************/

public class ToneDetector {

 /**

  * Период времени, в течение которого производится оценка.

  * Длительность символов в последовательности должна быть

  * как минимум в 2 раза больше.

  * Приемлемый диапазон: 10 ... 100 мс

  */

 private static final byte BUFFER_MS = 20;

 /**

  * мощность сигнала. параметр и вычисления с ним не нужны,

  * если минимальный уровень отсекается порогом.

  */

 private float m_inPower = 0.0f;

 //

 private float m_threshold = 0.5f;

 private boolean m_bDualTone = false;

 private int m_counter = 0;

 private int m_decodeLength = 0;

 private float[][] m_pSin = null;

 private float[][] m_pCos = null;

 private float[] m_pSinAccum = null;

 private float[] m_pCosAccum = null;

 

 public ToneDetector() {

 }

 

 boolean initDTMF( int sampleRate ) {

         int[] pFrequency = new int[8];

         pFrequency[0] = 697;

         pFrequency[1] = 770;

         pFrequency[2] = 852;

         pFrequency[3] = 941;

         pFrequency[4] = 1209;

         pFrequency[5] = 1336;

         pFrequency[6] = 1477;

         pFrequency[7] = 1633;

         boolean res = initSTMF( sampleRate, pFrequency );

         m_bDualTone = true;

         return res;

 }

 

 boolean initSTMF( int sampleRate, final int[] pFrequency ) {

         m_bDualTone = false;

         m_pSin = new float[pFrequency.length][];

         m_pCos = new float[pFrequency.length][];

         m_pSinAccum = new float[pFrequency.length];

         m_pCosAccum = new float[pFrequency.length];

         m_inPower = 0.0f;

         m_decodeLength = (int)(BUFFER_MS * sampleRate / 1000);

         m_counter = 0;

         for( int f = pFrequency.length; f-- != 0; ) {

                 m_pSin[f] = new float[m_decodeLength];

                 m_pCos[f] = new float[m_decodeLength];

                 double step = 2.0 * Math.PI * pFrequency[f] / sampleRate;

                 double t = 0;

                 for( int i = 0; i < m_decodeLength; i++ ) {

                         double angle = i * step;

                         m_pSin[f][i] = (float)Math.sin( angle );

                         m_pCos[f][i] = (float)Math.cos( angle );

                         t += m_pSin[f][i] * m_pSin[f][i];

                 }

                 m_pSinAccum[f] = 0.0f;

                 m_pCosAccum[f] = 0.0f;

         }

         return true;

 }

 /************************************************

 установить порог

 0.00 < threshold < 1.00

 ************************************************/

 void setThreshold( float threshold ) {

         // расчитываем квадрат амплитуды, поэтому

         // используем квадрат порога

         m_threshold = threshold * threshold;

 }

 //frhigh   1209  1336  1477  1633

 //frlow

 //    697   1     2     3     A

 //    770   4     5     6     B

 //    852   7     8     9     C

 //    941   *     0     #     D

 private static final byte decodeDTMF[] = {

                 '1', '2', '3', 'A',

                 '4', '5', '6', 'B',

                 '7', '8', '9', 'C',

                 '*', '0', '#', 'D' };

 

 byte process(short sample) {

         for( int f = m_pSinAccum.length; f-- != 0; ) {

                 m_pSinAccum[f] += (float)sample * m_pSin[f][m_counter];

                 m_pCosAccum[f] += (float)sample * m_pCos[f][m_counter];

                 m_inPower += (float)sample * (float)sample;// если используется мощность

         }

         if( ++m_counter < m_decodeLength ) return 0;

         m_counter = 0;

         byte code = 0;

         if( m_inPower > 0.0f ) {

                 int firstFr = 0;

                 int secondFr = 0;

                 float max = -1.0f;

                 int f = 0;

                 for( ; f < (m_pSinAccum.length / 2); f++ ) {

                         float res = m_pSinAccum[f] * m_pSinAccum[f] + m_pCosAccum[f] * m_pCosAccum[f];

                         if( max < res ) {

                                 max = res;

                                 firstFr = f;

                         }

                         m_pSinAccum[f] = 0.0f;

                         m_pCosAccum[f] = 0.0f;

                 }

                 // нормировка для сравнения с порогом

                 /// если регулировка уровня порогом

                 // 32767 - максимальное значение для 16-ти разрядного звука

                 // max = max / m_decodeLength / m_decodeLength * 4.0f / (32767 * 32767);

                 /// если используется мощность

                 // мощность образца = (sqrt(2)/2)^2 * m_decodeLength

                 max = max / m_inPower / m_decodeLength * 16.0f;

                 if( max < m_threshold ) firstFr = m_pSinAccum.length;

                 if( m_bDualTone ) max = -1.0f;

                 for( ; f < m_pSinAccum.length; f++ ) {

                         float res = m_pSinAccum[f] * m_pSinAccum[f] + m_pCosAccum[f] * m_pCosAccum[f];

                         if( max < res ) {

                                 max = res;

                                 secondFr = f;

                         }

                         m_pSinAccum[f] = 0.0f;

                         m_pCosAccum[f] = 0.0f;

                 }

                 // нормировка для сравнения с порогом

                 /// если регулировка уровня порогом

                 // 32767 - максимальное значение для 16-ти разрядного звука

                 //max = max / m_decodeLength / m_decodeLength * 4.0f / (32767 * 32767);

                 /// если используется мощность

                 // мощность образца = (sqrt(2)/2)^2 * m_decodeLength

                 max = max / m_inPower / m_decodeLength * 16.0f;

                 if( max < m_threshold ) secondFr = m_pSinAccum.length;

                 if( m_bDualTone ) {

                         /**

                          * для уменьшения вероятности ложных срабатываний здесь имеет смысл добавить

                          * дополнительные проверки:

                          * - уровни обнаруженных сигналов не должны сильно отличаться

                          * - остальные сигналы должны быть по уровню сильно меньше основных

                          */

                         if( (firstFr < m_pSinAccum.length) && (secondFr < m_pSinAccum.length) )

                                 code = decodeDTMF[secondFr - (m_pSinAccum.length / 2) +

                                                   firstFr * (m_pSinAccum.length / 2)];

                 } else {

                         /**

                          * для уменьшения вероятности ложных срабатываний здесь имеет смысл добавить

                          * дополнительную проверку:

                          * - уровень обнаруженного сигнала должен сильно превосходить остальные

                          */

                         if( secondFr < m_pSinAccum.length )

                                 code = (byte)('1' + secondFr);

                         else if( firstFr < m_pSinAccum.length )

                                 code = (byte)('1' + firstFr);

                 }

                 

                 m_inPower = 0.0f;

         }

         return code;

 }

}

Реализация алгоритма Герцеля

/*******************************************************

* детектирование DTMF и однотональных сигналов

*

* используется алгоритм Герцеля

* алгоритм модифицирован с целью уменьшения

* чувствительности к амплитуде входного сигнала

*

* использовано:

* Texas Instruments

* DTMF Tone Generation and Detection

* An Implementation Using the TMS320C54X

--------------

использование:

 ToneDetector td = new ToneDetector();

 if( td.initDTMF( ... ) )

 {

         td.setThreshold( 0.5f );

         ...

         for( int i = 0; i < sampleCount; i++ )

         {

                 byte code = td.process( sample[i] );

                 if( code > 0 )

                 {

                         ...

                 }

         }

 }

********************************************************

tones:

350 Hz                dialtone

440 Hz                ring, dialtone

480 Hz                ring, busy

620 Hz                busy

 

697 Hz                dtmf row 1

770 Hz                dtmf row 2

852 Hz                dtmf row 3

941 Hz                dtmf row 4

1209 Hz                dtmf col 1

1336 Hz                dtmf col 2

1477 Hz                dtmf col 3

1633 Hz                dtmf col 4

 

700 Hz                blue box 1

900 Hz                blue box 2

1100 Hz                blue box 3

1300 Hz                blue box 4

1500 Hz                blue box 5

1700 Hz                blue box 6

2400 Hz                blue box 7

2600 Hz                blue box 8

*******************************************************/

public class ToneDetector {

 /**

  * Период времени, в течение которого производится оценка.

  * Длительность символов в последовательности должна быть

  * как минимум в 2 раза больше.

  * Приемлемый диапазон: 10 ... 100 мс

  */

 private static final byte BUFFER_MS = 20;

 /**

  * мощность сигнала. параметр и вычисления с ним не нужны,

  * если минимальный уровень отсекается порогом.

  */

 private float m_inPower = 0.0f;

 private float m_threshold = 0.5f;// порог отсечения

 private boolean m_bSingleTone = false;// однотональный/двутональный детектор

 private int m_counter = 0;// счётчик обработанных сэмплов

 private int m_decodeLength = 0;// число сэмплов на заданную длину символа

 private float[] m_pV1 = null;// первый шаг задержки

 private float[] m_pV2 = null;// второй шаг задержки

 private float[] m_pCoeff = null;// коэффициенты Герцеля

 

 public ToneDetector() {

 }

 

 boolean initDTMF( int sampleRate ) {

         int[] pFrequency = new int[8];

         pFrequency[0] = 697;

         pFrequency[1] = 770;

         pFrequency[2] = 852;

         pFrequency[3] = 941;

         pFrequency[4] = 1209;

         pFrequency[5] = 1336;

         pFrequency[6] = 1477;

         pFrequency[7] = 1633;

         boolean res = initSTMF( sampleRate, pFrequency );

         m_bSingleTone = false;

         return res;

 }

 

 boolean initSTMF( int sampleRate, final int[] pFrequency ) {

         m_bSingleTone = true;

         m_pV1 = new float[pFrequency.length];

         m_pV2 = new float[pFrequency.length];

         m_pCoeff = new float[pFrequency.length];

         m_inPower = 0.0f;

         m_decodeLength = (int)(BUFFER_MS * sampleRate / 1000);

         m_counter = 0;

         for( int f = pFrequency.length; f-- != 0; ) {

                 m_pCoeff[f] = (float)(2.0 * Math.cos( 2.0 * Math.PI * pFrequency[f] / sampleRate));

                 m_pV1[f] = 0.0f;

                 m_pV2[f] = 0.0f;

         }

         return true;

 }

 /************************************************

 установить порог

 0.00 < threshold < 1.00

 ************************************************/

 void setThreshold( float threshold ) {

         // расчитываем квадрат амплитуды, поэтому

         // используем квадрат порога

         m_threshold = threshold * threshold;

 }

 

 //frhigh   1209  1336  1477  1633

 //frlow

 //    697   1     2     3     A

 //    770   4     5     6     B

 //    852   7     8     9     C

 //    941   *     0     #     D

 private static final byte decodeDTMF[] = {

                 '1', '2', '3', 'A',

                 '4', '5', '6', 'B',

                 '7', '8', '9', 'C',

                 '*', '0', '#', 'D' };

 

 byte process(short sample) {

         for( int f = m_pCoeff.length; f-- != 0; ) {

                 float t = m_pV1[f];

                 m_pV1[f] = (float)sample + m_pCoeff[f] * m_pV1[f] - m_pV2[f];

                 m_pV2[f] = t;

                 m_inPower += (float)sample * (float)sample;// если используется

         }

         if( ++m_counter < m_decodeLength ) return 0;

         m_counter = 0;

         byte code = 0;

         if( m_inPower > 0.0f ) {

                 int firstFr = 0;

                 int secondFr = 0;

                 float max = -1.0f;

                 int f = 0;

                 for( ; f < (m_pCoeff.length / 2); f++ ) {

                         float res = m_pV1[f] * m_pV1[f] + m_pV2[f] * m_pV2[f] -

                                                 m_pCoeff[f] * m_pV1[f] * m_pV2[f];

                         if( max < res ) {

                                 max = res;

                                 firstFr = f;

                         }

                         m_pV1[f] = 0.0f;

                         m_pV2[f] = 0.0f;

                 }

                 // нормировка для сравнения с порогом

                 /// если регулировка уровня порогом

                 // 32767 - максимальное значение для 16-ти разрядного звука

                 // max = max / m_decodeLength / m_decodeLength * 4.0f / (32767 * 32767);

                 /// если используется мощность

                 // мощность образца = (sqrt(2)/2)^2 * m_decodeLength

                 max = max / m_inPower / m_decodeLength * 16.0f;

                 if( max < m_threshold ) firstFr = m_pCoeff.length;

                 if( !m_bSingleTone ) max = -1.0f;

                 for( ; f < m_pCoeff.length; f++ ) {

                         float res = m_pV1[f] * m_pV1[f] + m_pV2[f] * m_pV2[f] -

                                                 m_pCoeff[f] * m_pV1[f] * m_pV2[f];

                         if( max < res ) {

                                 max = res;

                                 secondFr = f;

                         }

                         m_pV1[f] = 0.0f;

                         m_pV2[f] = 0.0f;

                 }

                 // нормировка для сравнения с порогом

                 /// если регулировка уровня порогом

                 // 32767 - максимальное значение для 16-ти разрядного звука

                 // max = max / m_decodeLength / m_decodeLength * 4.0f / (32767 * 32767);

                 /// если используется мощность

                 // мощность образца = (sqrt(2)/2)^2 * m_decodeLength

                 max = max / m_inPower / m_decodeLength * 16.0f;

                 if( max < m_threshold ) secondFr = m_pCoeff.length;

                 if( m_bSingleTone ) {

                         /**

                          * для уменьшения вероятности ложных срабатываний здесь имеет смысл добавить

                          * дополнительную проверку:

                          * - уровень обнаруженного сигнала должен сильно превосходить остальные

                          */

                         if( secondFr < m_pCoeff.length )

                                 code = (byte)('1' + secondFr);

                         else if( firstFr < m_pCoeff.length )

                                 code = (byte)('1' + firstFr);

                 } else {

                         /**

                          * для уменьшения вероятности ложных срабатываний здесь имеет смысл добавить

                          * дополнительные проверки:

                          * - уровни обнаруженных сигналов не должны сильно отличаться

                          * - остальные сигналы должны быть по уровню сильно меньше основных

                          */

                         if( (firstFr < m_pCoeff.length) && (secondFr < m_pCoeff.length) )

                                 code = decodeDTMF[secondFr - (m_pCoeff.length / 2) +

                                                   firstFr * (m_pCoeff.length / 2)];

                 }

                 m_inPower = 0.0f;

         }

         return code;

 }

}

 

Предыдущая  Содержание  Следующая