Метод Goetzel, инженерный подход (PDF 400KB)

advertisement
Введение
Целью является описать подход к проблеме с точки зрения инженера, без излишней
наукообразности, так чтобы, было понятно, как использовать достижения отцов
математиков нам простым инженерам. Для начала напомним некоторые базовые понятия.
Сигнал
Уровень, энергия, мощность сигнала – суть одно и то же. Считается, что сигнал имеет
мощность (уровень) 0 dB, если он выделяет 1 mW тепла на резисторе 600 Om.
Синусоидальный сигнал такой мощности будет иметь эффективное значение напряжения:
Vrms = P • R = 0.001W • 600Om = 0.7745966[V ]
Амплитуда его будет равна:
Vp = 2 • Vrms = 1.0954449[V ]
Уровень, в dB, синусоидального сигнала, имеющего амплитуду V, определяется по
формуле:
V
⎛
⎞
L = 20 • Log10⎜
⎟
⎝ 1.0954449 ⎠
Если говорят, что сигнал «А» отличается от сигнала «Б» на «L» dB, то это значит, что
L
А = К * Б, где K = 10 20
Если разность сигналов равна 6 dB, то первый сигнал больше второго примерно в 2 раза,
6
K = 10 20 = 1.995262315
Мощность (P) сигнала произвольной формы определяется как корень из суммы
квадратов выборок (измерений) сигнала (S), деленный на количество выборок (N), чем
больше N, тем точнее получится вычисление:
N −1
P=
∑S
2
n
0
N
[1]
Амплитуда (Vp) синусоидального сигнала мощностью P равна:
N −1
Vp = 2 * P =
2 * ∑ S2n
0
N
[2]
Выборка сигнала (результат единичного измерения) представляется двоичным числом
определенной разрядности. На практике широко распространено 12 битное представление
в формате 1.12, один знаковый разряд и 12 значащих разрядов.
Согласно кодированию по закону A-law (G.711) максимальный уровень (амплитуда)
сигнала составляет 3.14 dB. Число 4096 (0х1000) соответствует уровню 3.14 dB, однако
Урусов А.В.
www.butovo.com/~uav
1
оно не достижимо, реальный диапазон положительных значений 0…4095 (0хFFF). Легко
определить число соответствующее уровню 0 dB, оно будет на 3.14 dB меньше чем 4096:
S = 10
−3.14
20
• 4096 = 0.696626514 • 4096 = 2853.382202 ≈ 2853 ,
что соответствует напряжению 1.0954449 V.
Если мы сформируем внутри DSP синус амплитудой 2853(0.696626514) по A-law и
выведем его наружу, используя стандартный кодек, то на выходе получим аналоговый
сигнал с уровнем 0 dB. Однако DSP как правило имеют 16 битное представление чисел в
формате 1.15, что обеспечивает числовой диапазон вещественных чисел: от -1.0 до
0.999969482421875 с шагом 0.000030518509476 (от 0x8000 до 0x7FFF с шагом 0x0001).
Однако, если число в таком формате (fract16 для ANALOG DEVICE) передается из DSP в
HOST компьютер (PC), то для правильного перевода в формат FLOAT или DOUBLE,
необходимо это число поделить на 32768 (2^15):
volatile short int Lev;
double dLevel = Lev/32768.0;
где, Lev – это число (fract16), пришедшее из DSP.
Ниже приведен код программы для вычисления N выборок синусоидального сигнала
произвольного уровня L, с частотой квантования 8000 kHz и разрядностью представления
1.12 (A-law):
#define
#define
#define
#define
#define
M_PI
D2F(x)
DB2K(dB)
K2DB(k)
KDB0
3.141592653589793
((short int)((x>0)?(x+0.5):(x-0.5)))
(pow(10.0,(dB)/20.0))
(20*log10(k))
(DB2K(-3.14))
//pSin - pointer to output buffer
//N - number of samples
//freq - freq in Hz
//L - level in dB
//nPhase - start PHASE in degrees (0..360)
void GetSinusArb(short int* pSin, int N, int freq, double L, int
nPhase){
double dDeltaPhase = 2.0*M_PI*freq/8000.0;
double dK = 4096.0*KDB0*DB2K(L);//convert dB to coefficient
double dPh = nPhase*M_PI/180.0;
double dCurrentPhase = dPh;
for(int i=0;i<N;i++){
*pSin++ = D2F(dK*sin(dCurrentPhase));
dCurrentPhase += dDeltaPhase;
}
}
Переменная dDeltaPhase хранит приращение фазы сигнала, соответствующее
переходу от одной выборке к другой. Во избежание перегрузок L не должно превышать
3.14 dB, вычисленный таким образом сигнал можно выводить на “Sound Blaster” и далее
по назначению.
Метод Goertzel
Данный метод позволяет вычислить магнитуду (вес) искомой частоты в
анализируемом сигнале. Алгоритм вычислений подобен IIR фильтру второго порядка, при
чем выходное зачение вычисляется один раз для всех N выборок сигнала. Метод требует
Урусов А.В.
www.butovo.com/~uav
2
существенно меньшего количества вычислений (по сравнению с DFT) и не требует
предварительного накопления всех N выборок входного сигнала.
Вычисления разбиваются на два этапа: промежуточные вычисления (Q1,Q2) на N
выборках и однократное вычисление магнитуды (M). В вычислениях используется
коэффициент (Coeff), определяемый по формуле:
K = D2F(N*Freq/8000.0); //K – integer
Coeff = 2.0*cos(2*M_PI*K/N);
Q1 = Q2 = 0;
//-- get Q1 Q2 -for(int i = 0;i<N;i++){
Q = Coeff*Q1 - Q2 + Sample[i]/Kdiv;
Q2 = Q1;
Q1 = Q;
}//sample loop
//-- get MNSQR ====
M = Q2*Q2 + Q1*Q1 - Q1*Q2*Coeff;
Где:
•
•
•
•
•
•
•
•
Freq – искомая частота (Hz)
N – количество выборок
Sample – выборка (мгновенное значение) сигнала
8000 – частота выборки (квантования) в Hz
Kdiv – коэффициент ослабления входного сигнала
Coeff – коэффициент Гертцеля
K – число периодов искомой частоты, укладывающихся в N периодов частоты
квантования (должно быть близко к целому числу)
M – магнитуда частоты Freq
Необходимо выбрать такое N, чтобы K было как можно ближе к целому значению. В
Таблица 1 приводятся значения N хорошо подходящие для частоты 1000Гц, как нетрудно
заметить все значения кратны 8 (8000/1000).
N
16
24
32
40
48
56
64
72
80
88
96
104
112
120
128
136
144
152
160
Урусов А.В.
K
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Таблица 1
Coeff
F[Hz]
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
1.414214
1000
www.butovo.com/~uav
Ferr[%]
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Time[mS]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3
Ослабление (деление на Kdiv) входного сигнала необходмимо для избежания
переполненния разрядной сетки DSP, Kdiv выбирается исходя из динамического
диапазона входного сигнала.
На Рисунок 1 представлена АЧХ фильтра для частоты 1000 Гц, количество выборок
200, уровень сигнала 0 дБ и без ослабления входного сигнала. Ширина лепестков фильтра
определяется формулой:
ΔF =
Где:
•
•
Fq
[3]
N
Fq – частота квантования
N – количество выборок
8000 Hz
= 40 Hz .
200
Значение магнитуды частоты синусоидального сигнала амплитудой Vp можно
предсказать как :
Для случая на Рисунок 1 имеем ΔF =
2
⎛ Vp * N ⎞
M =⎜
⎟ [4]
⎝ 2 * Kdiv ⎠
Где:
•
•
•
Vp – амплитуда синуса
N – количество выборок
Kdiv – коэффициент ослабления входного сигнала
F=1000Hz N=200 Level=0dB Kdiv=1
Магнитуда
80
70
60
50
40
30
20
10
0
800
840
880
920
960
1000
1040
1080
1120
1160
1200
F[Hz]
Рисунок 1
На практике требуется детектирование сразу нескольких частот, при этом не всегда
удается подобрать N одинаковое для всех частот и приходится использовать различные N.
При этом значения магнитуд разных частот ( при одинаковых их мощностях) будут
Урусов А.В.
www.butovo.com/~uav
4
отличаться друг от друга. Однако можно выравнять магнитуды, например по меньшему N,
для удобства их последующего сравнения, используя корректирующий коэффициент:
2
⎛ N min ⎞
= M N *⎜
⎟ [5]
⎝ N ⎠
M norm
Где:
•
•
•
•
Mnorm – нормализованная магнитуда искомой частоты
Mn – исходная магнитуда искомой частоты
Nmin – минимальное число выборок среди всех частот
N – число выборок искомой частоты
Для сравнения уровней двух частот нет необходимости переводить магнитуды в
уровни (Vp), можно обойтись сравнением магнитуд, учитывая, что их отношение будет
равно отношению квадратов уровней:
⎛ V1
⎜⎜
⎝ V2
2
⎞
M
⎟⎟ = 1 [6]
M2
⎠
Для определения соотношения сигнал/шум можно сравнить мощность сигнала из
выражения [2] и мощность магнитуды:
VM =
2 * Kdiv
* M [7]
N
Во избежание извлечения корня квадратного, можно сравнивать квадраты мощностей,
тогда нормализованные магнитуды нескольких частот можно суммировать.
VM2 1+ M 2 =
4 * Kdiv 2
* (M 1 + M 2 ) [8]
2
N min
Прецизионное детектирование частоты
На практике, вычисленная магнитуда будет отличаться от эталонной, и невозможно
догадаться, вызвано это отклонением частоты или уровня сигнала. Чтобы гарантировано
детектировать частоту в некотором диапазоне (по частоте и уровню) можно использовать
3 фильтра с частотами меньшей, равной и большей. Например, DTMF(Q.24 NTT)
предписывает детектировать частоты с отклонением до +-1.8% и не детектировать с
отклонениями более +-3%, а также допускает отличие уровней в паре частот до 5dB.
На Рисунок 2 представлены характеристики трех фильтров для частоты 1336Гц
(боковые частоты имеют смещение 4%). Коричневым цветом обозначена характеристика
результирующего фильтра, который имеет узкую полосу (примерно 4%) и плоскую
характеристику. Выходы 3 фильтров сравниваются для получения результирующей
магнитуды. Ниже :
• M – магнитуда центра фильтра (1336Гц), а также выходная
• Mm – магнитуда фильтра -4% (1276 Гц)
• Mp – магнитуда фильтра +4%( 1396 Гц)
Урусов А.В.
www.butovo.com/~uav
5
1283
1285
1287
1289
1291
1293
1295
1297
1299
1301
1303
1305
1307
1309
1311
1313
1315
1317
1319
1321
1323
1325
1327
1329
1331
1333
1335
1337
1339
1341
1343
1345
1347
1349
1351
1353
1355
1357
1359
1361
1363
1365
1367
1369
1371
1373
1375
1377
1379
1381
1383
1385
1387
Mnsqr
if ((M >= Mm) && (M >= Mp)){
if (Mm > Mp)
M = M + (Mm + 2.25*Mp)*1.17;
else
M = M + (2.25*Mm + Mp)*1.17;
}
else
M = 0;
6000
5000
4000
3000
2000
1000
0
Freq
1336-4%
Урусов А.В.
1336
1336+4%
www.butovo.com/~uav
Corrected Mnsqr
Рисунок 2
6
Реализация для ADSP2181
Наиболее затратные фрагменты программы целесообразно писать на ассемблере, в то
время как, основная часть обычно реализуется на языке C/C++. Такой подход
обеспечивает приемлемую производительность при разумном время разработки. Ниже
приведены две подпрограммы, написанные на ассемблере с учетом соглашений о
регистрах и передаче парметров , принятых в IDE VDSP.
I0 scratch
I1 scratch
I2 preserved
I3 preserved
I4 dedicated: SP
I5 preserved
I6 scratch
I7 preserved
M0 preserved
M1 dedicated: +1
M2 dedicated: 0
M3 scratch
M4 dedicated: FP
M5 scratch
M6 dedicated: 0
M7 dedicated: -1
L7..0 = 0
Первая подпрограмма _getQ вычисляет значения промежуточных значений Q1,Q2,
вторая (_getM) – собственно магнитуду. Основные вычисления производятся
исключительно на MAC, что позволяет избежать переполнений в промежуточных
операциях. Для минимизации времени выполнения надо стараться использовать
мультиинструкции DSP, совмещающие например операцию в MAC и пересылки с
памятью.
#define KDIV 20
#define KMULT 32768/KDIV
#define CHANNEL_STRIDE 1
.section/code program;
.global _getQ,_getM;
_getQ:
//======== Get Q1,Q2 ==========
// Q = K*X + COEFF*Q1 - Q2
// I0
- pointer to sample (DM)
// I1
- pointer to Q1.Q2 (DM) ALIGN 2
// AX0 - save M0
// CNTR = amount of samples
// AR
= constant -1.0
// MX0 = coeff
// MX1 = KMULT
// MY0 = sample/Q2
// MY1 = Q1
//---- GET PARAMETRS ----------M5 = 4; MODIFY(I4+=M5);//point to first parameter
AX0 = DM(I4+=M7); CNTR = AX0;//N
MX0 = DM(I4+=M7); //coef
AX0 = DM(I4+=M7); I1 = AX0;//pointer to Q1Q2
AX0 = DM(I4+=M7); I0 = AX0;//pointer to sample
Урусов А.В.
www.butovo.com/~uav
7
//--- INIT SOME REGS -----------AX0 = M0; M0 = CHANNEL_STRIDE; // save M0
M3 = -1; L1 = 2; MX1 = KMULT;
AR = -1.0r;// 0x8000 (fract -1.0)
DIS M_MODE;//set fractional MAC mode
//---- MAIN LOOP --------------DO __end1 UNTIL CE;
MY0 = DM(I0,M0) ; //MY0 = sample
MR = MX1 * MY0 (US),
MY1 = DM(I1,M1); // KMULT*SAMPLE, MY1= Q1
MR = MR + MX0 * MY1(US),
MY0 = DM(I1,M2); // +coeff*Q1,
MY0 = Q2
MR = MR + AR * MY0 (RND), DM(I1,M3) = MY1; // + (-1.0)*Q2, Q2 = Q1
__end1:
DM(I1,M2) = MR1; //Q1 = Q
ENA M_MODE;
//---- RESTORE ...--------L1 = 0;
M0 = AX0;//restore M0
RTS;
_getQ.end:
//========= Get MNSQR ========================
_getM:
//---- GET PARAMETRS ----------I0 = AR; //pointer to Q1Q2
MY0 = AY1;//coeff
MX0 = DM(I0,M1);//Q1
MY1 = DM(I0,M1);//Q2
DIS M_MODE;
MR = MX0 * MY1(RND);
AR = MR1;
MR = MX0 * MX0(SS);
MX1 = MY1;
MR = MR + MX1 * MX1(SS);
MR = MR - AR * MY0(SU);
MR = MR (RND);
IF MV SAT MR;
ENA M_MODE;
//set fractional MAC mode
//Q1*Q2
//save Q1*Q2
//Q1*Q1
//copy Q2
//Q1*Q1 + Q2*Q2
//Q1*Q1 + Q2*Q2 - Q1*Q2*coeff
AX1 = MR1; //return value
RTS;
_getM.end:
Пример вызова подпрограмм из кода на С приведен ниже.
#pragma regs_clobbered "I0,I1,M3,M5,AX0,AR,MX0,MX1,MY0,MY1,MR,CNTR,ASTAT"
extern void getQ(int* pSample, int* pQ, unsigned int coeff, unsigned int N);
#pragma regs_clobbered "I0,M5,AX0,AR,MX0,MX1,MY0,MY1,MR,ASTAT"
extern int getM(int* pQ, unsigned int coeff);
#include "697_1209.h" //set Sample[320] signal data (int Sample[] = {0,10,…})
#pragma align 2
int Q1Q2[2];
int mnsqr;
main (){
memset(Q1Q2,0,2);
getQ(Sample,Q1Q2,55960,264);//697 hZ (1352 DSP cycles)
mnsqr = getM(Q1Q2,55960);
}
Урусов А.В.
www.butovo.com/~uav
8
//1352*12.5ns/264 = 64ns/sample
//125us/(64ns*8*3) = 81 (dtmf recievers)
При тактовой частоте DSP 80 мГц (время такта 12.5 нс)
работающих приемников DTMF может достигать 80.
число одновременно
На моей страничке Урусов А.В. можно найти программу GoerTest (Рисунок 4)
детектирования
DTMF
(эмулирующую
арифметику
DSP
AnalogDevice)
демонстрирующую описанный выше подход. Программа может работать как с файлами
семплов, так и напрямую от звукового устройства PC (требуется настройка режима
записи). Для создания тестовых файлов сигналов можно использовать мою программу
«Генератора многочастотных сигналов» MfsGen (Рисунок 3).
Рисунок 3
Генерируются две DTMF цифры (1 и 8) с наложенными сигналами Dial Tone (425Гц и
350&440Гц), DTMF частоты и уровни смещены в допустимых пределах, длительность
цифр 40 и 60 млсек.
Урусов А.В.
www.butovo.com/~uav
9
•
•
•
•
•
•
•
•
•
•
Рисунок 4
N – номер
Dg – цифра (digit)
Lev – уровень [dB] сигнала
Ovf – переполнения разрядной сетки DSP
M0-M7 – магнитуды в формате INT
V – мощность сигнала
M – мощность полезной составляющей (DTMF + DIALTONE)
MVR – отношение M/V
DgL – примерная длительность цифры [млсек]
Time – время от предыдущего события
25.05.2011
Урусов А.В.
www.butovo.com/~uav
10
Download