/
Text
ИЗМЕРЕНИЯ
Елена Бадло, Сергей Бадло
г. Запорожье
E-mail: raxp@radioliga.com
Данный материал является заключительным в цикле статей по
виртуальным приборам, в практической части которого мы узнаем
об аспектах создания анализатора спектра и декодера DTMF сигна-
лов, а также научим наше приложение “понимать” команды с пульта.
Виртуальные приборы.
DTMF. Спектроанализатор своими руками
Используя тональный набор (DTMF), можно легко управ-
лять как приложениями компьютерной телефонии, отвечая
на запросы системы нажатием клавиш на телефоне в режи-
ме тонального набора, так и организовать помехоустойчи-
вый канал связи-управления между цехами на основе имею-
щихся телефонных или городских сетей, в частности - све-
тофорами.
Краткий экскурс...
Что же такое DTMF? DTMF (Dual Tone Multi Frequency) -
это термин тонального набора. DTMF сигнал является ком-
бинацией двух частот, высокой и низкой. Система сигналов
DTMF включает восемь тонов, подобранных так, чтобы пе-
редаваться через ТФоП (телефонную сеть общего пользо-
вания) с минимальным влиянием друг на друга.
Недостатка в готовых аппаратных реализациях кодеров-
декодеров DTMF сегодня не наблюдается. Достаточно вспом-
нить отечественные микросхемы ВЖ18/ВЖ19 (MV8870) или
множество вариантов как на обычных, так и DSP контролле-
рах [1 , 2]. А вот что касается программных визуальных реше-
ний для ПК, то дальше “демо” версий с закрытыми алгорит-
мами, исключая специализированные военные применения,
дело не дошло. Как быть? Наиболее целесообразным реше-
нием в данной ситуации видится разработка своего анали-
затора спектра. Ведь зная характер сигнала и распределе-
ние частотных гармоник по спектру, ничто не мешает осуще-
ствить его декодирование. Кроме того, область применения
подобного спектроанализатора не ограничивается одним
лишь DTMF. С его помощью можно анализировать ЛЧМ,
MFSK, фазовую модуляцию, определять интенсивность гар-
моник, параметры и вид модуляции и т.д. и т.п.
Основные требования к ПО
Следовательно, ПО спектроанализатора должно как ми-
нимум позволять оценить уровень шумов (SNR), частоты и
динамический диапазон сигналов, полученных как от аудио-
карты ПК, так и стороннего оборудования, например, с фай-
лов (дампов). Для удобства работы желательно продублиро-
вать управление программой с пульта ДУ.
Таким образом, уже можем определить основные требо-
вания к нашему анализатору спектра:
- поддержка текущих аудиоустройств в системе;
- режим осциллографа и построение спектра в реальном
времени;
- загрузка дампов *.dat “сырых” данных с внешних уст-
ройств, например с АЦП;
- анализ файлов формата WAV/MP3 в off-time;
- управление основными функциями с пульта ДУ;
- возможность распечатки графика.
Рис. 1. Комплекс “виртуальный спектроанализатор”
Практика. Разработка ПО и средства отладки
Итак, приступим к основной задаче. Для работы нам сле-
дует запастись следующим:
* среда разработки Borland Delphi 5-7
* аудио-редактор Sound Forge 8.0
1. Работа с DTMF[ 1 -3] или Для чего мы учим математику
Прежде всего, в редакторе SoundForge на вкладке "Tools/
Synthesis/DTMF-MF Tones” создадим тестовые DTMF сигна-
лы, что значительно облегчит нам процесс отладки. Соглас-
но таблице 1 сразу же введем набор массивов тонов (врез-
ка 1) и разделим "проблему” на подзадачи:
- выделить набор частот (спектр) из исходного сигнала;
- идентифицировать по двум частотам, согласно табли-
це, символ DTMF.
Вспомним курс математики [3]. Как вы знаете, перио-
дическим сигналом называют такой вид воздействия, ког-
да форма сигнала повторяется через некоторый интервал
времени Т, который называется периодом. Простейшей
Таблица 1. Набор массивов тонов DTMF
F1/F2 1209 Гц 1336 Гц 1477 Гц 1633 Гц
697 Гц 1 2 3 А
770 Гц 4 5 6 В
852 Гц 7 8 9
941 Гц * 0 # D
32
Радиолюбитель - 03/2009
ИЗМЕРЕНИЯ
Сразу же введем набор массивов тонов
врезка 1
keys = "1234567890*#abcd";
dtmfl: array[1..16]of integer =(697,697,697,770,770,770,852,852,852,941,941,941,697,770,852,941);
dtmf2: array[l..16]of integer =(1209,1336,1477,1209,1336,1477,1209,1336,1477,1336,1209,1477,1633,1633,1633,1633)
формой периодического сигнала является гармонический
сигнал или синусоида, которая характеризуется амплитудой,
фазой и периодом. Все остальные сигналы будут негармо-
ническими.
Существует общая методика исследования периодичес-
ких негармонических сигналов, основанная на разложении
сигналов в ряд Фурье. Данная методика заключается в том,
что всегда можно подобрать ряд гармонических сигналов с
такими амплитудами, частотами и начальными фазами, ал-
гебраическая сумма ординат которых в любой момент вре-
мени равна ординате исследуемого несинусоидального сиг-
нала. В общем случае, ряд Фурье записывают в виде суммы
бесконечного числа гармонических составляющих разных
частот (см. формула):
U(t) = Uo + SUM (Um * sin (k * со * t + у))
где k - номер гармоники;
kco - угловая частота k-ой гармоники;
со=2*я/Т - угловая частота первой гармоники;
V - начальная фаза сигнала;
Uo - нулевая гармоника.
Для выделения спектра в радиотехнике, как правило,
используется быстрое преобразование Фурье (БПФ). В на-
шем случае реализация БПФ будет следующей (врезка 2).
Для идентификации полученного символа DTMF из вы-
численных наборов частот нам достаточно найти 2 макси-
мальных амплитуды и сопоставить их частоты частотам
DTMF. Достоверность этого сопоставления определяется
двумя критериями:
- оба максимальных значения должны превышать уро-
вень шума в сигнале;
- незначительность отличия этих амплитуд друг от друга,
иначе принять за недостоверность.
После чего передаем набор данных в процедуру БПФ
(врезка 3) и переходим ко второй подзадаче - поиск и иден-
тификация 2-х частот в спектре (врезка 4).
Как быть с обработкой в реальном времени? Как и в
прошлой нашей статье [4], воспользуемся функцией
WavelnOpen, чтобы получить доступ к текущему аудиоуст-
ройству (врезка 5).
Проверим, как работает. Запустим на воспроизведе-
ние двутональный сигнал и осуществим декодировку DTMF
(см. спектр рис. 2, рис. 3).
2. Работа с WAV
Для отображения и декодировки звуковых файлов в
off-time нужно осуществить чтение данных из WAV-файла
РСМ формата (врезка 6).
После чего передаем полученный набор данных в нашу
процедуру БПФ и строим спектр как обычно.
3. Работа с MP3
Работа с MP3 файлами ничем не отличается от мето-
дов, что мы использовали при работе с WAV, с одним лишь
собственно разложение в ряд Фурье
врезка 2
procedure FFTQuad(ent: dword; InData, OutData: Parraysingle) ;
function inv_diskret(a: Integer): Integer;
var b: Integer;
begin
Result:= 0;
for b:= 0 to Base - 1 do
if a and (1 shl b) <> 0 then
Result:= Result or (1 shl (Base - b - 1))
end;
begin
maxbase:= 0;
repeat inc(Base);
until (ent shr Base)=1;
Zer oMemorу(OutData, ent * SizeOf(Single));
for i := 1 to ent - 1 do
begin
j := inv_diskret(i) ;
if i <= j then begin
C := InData[i];
InData[i] := IriData[j];
InData[j] := C
end
end;
for i := 1 to maxBase do begin
Ip := 1 shl i;
lp2 := ent div Ip;
lp3 : = Ip div 2 ;
StepAng := -pi / lp3;
Ang := 0;
for j:=0 to lp3-l do begin
C := Cos(Ang);
S := Sin (Ang) ;
Ang := Ang + StepAng;
kl := j;
for k := 0 to lp2 - 1 do begin
k2 := kl + lp3;
//наши квадратуры-
Re := С * InData[k2] + S * OutData [ k2 ] ;
Im := C * OutData[k2] - S * InData[k2] ;
InData[k2] := InData[kl] -Re;
OutData [k2] := OutData [kl] - Im;
InData[kl] := InData[kl] + Re;
OutData [kl] := OutData [kl] + Im;
kl := kl + Ip
end
end
end;
for i := 0 to ent - 1 do begin
InData [i] := InData [i] / ent;
OutData [i] := OutData [i] / ent
end
end;
врезка 3
FFTQuad(series4,ser2, 2048) ; //набор отсчетов - на 2048 точек
отличием - предварительно перед загрузкой их нужно кон-
вертировать в РСМ формат. Для чего воспользуемся широ-
ко известной утилитой <1ате.ехе>. Формат командной стро-
ки для работы с ней будет следующий:
lame -decode filename.mp3
lame -b320 -qO filename.wav
4. Работа с пультом ДУ
Для реализации управления с помощью любого пуль-
та ДУ используем утилиту-сервер <winlirc.exe> [5]. Прин-
цип ее работы следующий. Сервер опрашивает выбран-
ный СОМ порт на ПК и отсылает данные по протоколу TCP.
33
Радиолюбитель - 03/2009 [|
ИЗМЕРЕНИЯ
2-х проходной поиск-
врезка 4
а1: = -1000;
for i:= 0 to (ser2.YValues.Count) -1 do begin //
a: = ser2 . YValues [i] ;
f:= i / (ser2.YValues.Count/2) * (r.wSamplePerSec / 2);
Seriesl.AddXY(f ,a) ;
if a > al then begin al:= a; f1:= f end
end;
a2:= -1000;
for i:= (ser2.YValues.Count)-1 downto 0 do begin
a: = ser2 . YValues [i] ;
f:= i / (ser2.YValues.Count/2) * (r.wSamplePerSec / 2);
if (a > a2) and(aOal) then begin a2:= a; f2:= f end
end;
По нашим наборам массивов делаем выборку-
/ /ид ентификация-
dtmf_sig: = "not" ;
for i:= 1 to 16 do begin
if (dtmf2 [i] *0.98<fl) and(dtmf2 [i] *1.02>fl) and //1 амплитуда >2 // 0.98 и 1.02 это своего рода доверительный интервал
(dtmf 1 [i ] *0.98<f 2) and (dtmf 1 [i]*1.02>f2) then begin / / определяющий помехоустойчивость
dtmf_sig: = keys[i]; // и учитывающий разброс в параметрах генераторов DTMF
break
end;
if (dtrnfl [i] *0.98<fl) and(dtmfl [i] *1.02>fl) and //1 амплитуда <2
(dtmf2 [i] *0.98<f2) and(dtmf2 [i] *1.02>f2) then begin
dtmf_si g: = keys [ i ] ;
break
end;
end;
Наша программа декодирует посыл-
ки и через интерпретатор выполняет
выбранный пользователем набор ко-
манд *.
Чтобы осуществить подключение к
серверу Win Lire, воспользуемся компо-
нентом TCIientSocket из стандартной по-
ставки Delphi. Установив порт подклю-
чения равным 8765, активируем соеди-
нение и по событию приема данных
OnClientSosketRead осуществим деко-
дирование принятой команды (кнопки
пульта) (врезка 7).
Если у вас есть карточка PCI тюне-
ра, то с нее тоже можно получать ко-
манды пульта, для этого достаточно
воспользоваться универсальным мо-
дулем PCI I/O for DELPHI разработки
автора [6], но это тема уже отдельной
статьи...
обработка в реальном времени
врезка 5
Wave InOpen (Addr (hwi2) , WAVE_MAPPER, addr (header) Л integer (@ wave InProc2) , 0, CALLBACK_FUNCTION) ;
//= systimer2 =
procedure wave InProc2 (hwi: HWAVE IN; uMs g, dw Ins tance,
dwParaml,dwParam2: DWORD);stdcall;
var i: integer;
da tai6: PDatai6;
h: integer;
XScale, YScale: single;
temp: pWaveHdr;
a,al,a2, //амплитуды-
f,f1,f2: double; //частоты-
begin
if (uMsg=WIM_DATA) then begin
temp:= adr2;
if adr2= Qbufheadl then adr2:= @bufhead2
else adr2:= Qbufheadl;
if stp2 then WavelnAddBuf fer (hwi, adr2 , SizeOf (TWaveHdr)) ;
datal6:= PDatai6(temp.IpData);
inwav.Clear; outwav.Clear;
forml.series5.Clear;
forml.series6.Clear;
for i := 0 to BufSize - 1 do begin //набивка-
forml.series6.add(datal6A[i]);
inwav.add(datai6л[i])
end;
FFTQuad (inwav, outwav, 512) ;
end;
* Настройка сервера на конкретный пульт следующая: на
панели конфигурации WinLirc нажимаете кнопку “Learn” (обуче-
ние), вводите имя файла настройки пульта. Далее жмете 2 раза
ENTER. После надписи <Press a button> - любую кнопку на пуль-
те. После надписи <Please wait a second and press it again> - эту
же кнопку на пульте. После надписи <Baseline initialized> - дер-
жите, пока счетчик с 10 не опустится до 1. Далее сервер запро-
сит усреднение пакетов - нажмите и держите кнопку до получе-
ния 64 пакетов (для разных пультов - отличается), после чего
будет предложено ввести название кнопки (вводите и жмите
ENTER)...
Все остальные кнопки на пульте: нажимаете каждую кноп-
ку до тех пор, пока не будет предложено ввести ее имя (если
реакции на эту кнопку нет, нажмите другую), когда кнопки за-
кончатся - “ENTER”, затем “Hide window”. Все, файл конфигу-
рации на ваш пульт сформирован.
осуществим чтение данных из WAV- файла РСМ формата
//wav-
r:= ReadWave(s); //чтение заголовка-
r.Data.seek(0, soFromBeginning);
for i := 1 to r.Data.Size div 2 do begin
r.Data.readBuffer(W1,1);
r.Data.readBuffer (W2,1);
series3.Add(Wl); //1- канал
series4.Add(W2) //2-
end;
врезка 6
TSOP48X
DCD
RTS
GND
Рис. 4. Схема
электрическая
принципиальная
приемника ДУ
34
Радиолюбитель - 03/2009
ИЗМЕРЕНИЯ
DTMF + FFT 9 x
File: 5.wav/Fd [Hz]= 44100
Diskret
DTMF(5): Д1 = -12,09 [1335 Hz] Д2= -12,27 [775 Hz]
-50-
o?
-100-
6 10 000 20 000 30 000 40 000
Frequency, Hz
|l234567890*#abcd | |2048 fc 1 |p.10 0 S □ T □ M
Рис. 3. Отсчеты и спектр файла MP3 сигнала DTMF.
Цифра “7’
Рис. 2. Отсчеты и спектр файла MP3 сигнала DTMF.
Цифра “5”
5. Аппаратная часть или для тех, кто “дружит"’ с
паяльником
Если у вас отсутствует готовый приемник ДУ, то
его всегда можно собрать самому (см. рис. 4). Вам
понадобятся всего несколько деталей: коннектор
DB9 с корпусом, 2 резистора, 1 диод типа 1N4148,
1 конденсатор и один 5-ти вольтовый ИК приемник
TSOP любой марки или ILMS5360 от“дистанционок”
телевизоров (последний можно свободно достать на
местном радиорынке).
Внешний вид и расположение выводов** наибо-
лее распространенных ИК приемников приведены
на рис. 5, рис. 6.
Приемник ДУ собран навесным монтажом пря-
мо в корпусе коннектора на контактах разъема DB9
(см. рис. 7).
Длина соединительного шлейфа между датчи-
ком и “девайсом” не критична, но по возможности
должна быть минимальной, для исключений возмож-
ных наводок.
Интерфейс или наведем “марафет”
Для того, чтобы наша программа выглядела
профессионально, нужно “научить” ее менять
свой вид. “Как это сделать?” - спросите вы. Нет
ничего проще. Нужна скиновая система. Скин -
это растровая картинка (или набор), содержа-
щая графические элементы программы, т.е. ее
внешний вид. Создать ее (нарисовать) можно в
декодировка команд пульта
врезка 7
//---------- winlirc
function comm(var s:string):string;
var i fk fkk:integer;
begin
//1- пробел
for i:=length(s) downto 1 do begin
if (s[i]=' ") then begin
k:=i; break end
end;
//2- пробел
for i:=k-l downto 1 do begin
if (s[i]=' ") then begin
kk:=i; break end
end;
//выделение команды-
result:=copy(s,kk+l,k-kk-l)
end;
procedure tforml.ic(s: string);
begin //зададимся кнопками пульта-
if s=rl' then imagel.OnClick(nil) ;
if s=f2’ then image2.OnClick(nil);
if s='3T then image3.OnClick(nil) ;
if s=4T then image4.OnClick(nil);
if s='5T then image5.OnClick(nil) ;
if s='6' then image6.OnClick(nil);
if s='7 ' then f9.OnClick(nil);
if s='8T then sel_channel
end;
procedure TForml.CSRead(Sender: TObject; Socket: TCustoiriWinSocket) ;
var s:string;
begin
//передача на интерпретатор команд-
if Socket.Connected then s:= Socket.ReceiveText;
ic(comm(s))
end;
procedure TForml.CSError(Sender: TObj ect; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
ErrorCode:= 0 //чтоб не выскакивало сообщение об ошибке, если winlirc не запущен
end;
//---------- winlirc
** Обратите внимание! Распиновка ИК модулей может отли-
чаться.
Рис. 5. Распиновка ИК
приемника TSOP48X
GND
Рис. 6. Распиновка ИК
приемника ILMS5360
Рис. 7. Внешний вид “девайса”
35
Радиолюбитель - 03/2009
ИЗМЕРЕНИЯ
Рис. 8. Отсчеты файла MP3 сигнала DTMF. Буква “А”
загрузка скина и свойств графических элементов
врезка 8
-15
-25 т*
-35 т
-40 4
-454
proc edurе Т forml.ReadIni(IniFile: TFileName) ;
var skin: TIniFile;
i : integer;
s: string;
begin
skin:= TIniFile.Create(IniFile);
s:= extractfilepath(inifile);
for i:=0 to high(im) do
im[i].LoadFromFile(s+inttostr(i)+'.bmp');
//подгрузка скиновых элементов-
imagel.Picture.Bitmap.Assign(im[l]);
image2.Picture.Bitmap.Assign(im[3]);
image3.Picture.Bitmap.Assign(im[5]);
imaged.Picture.Bitmap.Assign(im[7]);
image5.Picture.Bitmap.Assign(im[9]);
image6.Picture.Bitmap.Assign(im[ll]);
try IMAGE7.FileName:= s+1 logo.avi1;
except end;
//расположение-
imagel.Left:= skin.Readinteger("KEY_ADC",'left',10);
imagel.Top := skin.ReadInteger("KEY_ADC",'top',72);
image2.Left:= skin.Readinteger("KEY_FILE",'left',10);
image2.Top := skin.ReadInteger(vKEY_FILE",'top',164);
image3.Left:= skin.Readinteger("KEY_FFT",'left',10);
image3.Top := skin.Readinteger("KEY_FFT",'top',253);
imaged.Left:= skin.ReadInteger("KEY_PRINT",'left',10);
imaged.Top := skin.ReadInteger("KEY_PRINT",'top',343);
image5.Left:= skin.Readinteger("KEY_HELP",'left',10);
image5.Top := skin.ReadInteger("KEY_HELP",'top',433);
image6.Left:= skin.Readinteger("KEY_EXIT",'left',10);
image6.Top := skin.Readinteger("KEY_EXIT",'top',492);
image7.Left:= skin.ReadInteger("KEY_LOGO",'left',85);
image7.Top := skin.ReadInteger("KEY_LOGO",'top',13);
finally skin.Free; Canvas.Draw(0, 0, im[0]) end
end;
-55 т1
dB -60-М
-65^
-70-э
-75ii
-80 М
-85-=-*
10 318,834
-59,976
20 000
kHz
г
30 000
40 000
1234567890*#abcd «Play DTMF
95 71
-100-И
-105^*
[ТОЧКИ; 10 00
Параметры (авто)
Рис. 9. Спектр сигнала DTMF. Буква “А”
любом графическом редакторе, будь-то Photoshop или
Corel. Кроме того, скин может содержать информацию
об абсолютном положении каждого визуального элемен-
та, что дает большую свободу пользователю по заданию
внешнего вида программы и делает ее универсальной
(врезка 8).
В результате получаем следующий интерфейс спект-
роанализатора (см. рис. 8, рис. 9).
Заключение
Итак, мы подошли к заключительной части нашей
"виртуальной трилогии”, но на этом тема виртуальных при-
боров не исчерпывается, ведь появление все новых и
новых видов сложных сигналов обуславливает разви-
тие алгоритмов и методов их измерения и декодирова-
ния, а значит, многообразие виртуалок будет только уве-
личиваться...
И пару советов напоследок. Многие собирают прием-
ники ДУ с использованием стабилизаторов КРЕН типа
78L05, забывая о том, что мощности СОМ порта недо-
статочно, чтоб их тянуть, да и все чаще их питание
RS-232 с "матери” не 5 В, а 3 В! Поэтому использование
одного диода по цепи питания для исключения бросков
отрицательного напряжения оправданно в большинстве
случаев.
Полные исходные тексты, ресурсы проекта, сервер
winlirc, а также справочные данные по ИК приемникам
(файл dtmf_res.zip) вы можете загрузить с сайта нашего
журнала:
http://www.radioliga.com (раздел "Программы”)
а также с сайта автора:
http://raxp.radioliga.com
Если тема представляет для вас интерес - пишите,
задавайте вопросы на форуме:
http://raxp.radioliga.com/forum
Ресурсы
1. AVR314: Двутональный DTMF генератор - http://www.gawTuZhtml.cgi/txVapp/micros/avi7index.htm
2. MSP430: DTMF-Controlled - http7/www.gaw.ru/html.cgi/txt/app/micros/msp430/index.htm
3. Practical Design Techniques for Sensor Signal Conditioning, Analog Devices, 1998
4. E. Бадло, С. Бадло. Виртуальные приборы. Генератор сигналов без паяльника. Радиолюбитель, 2009, №1, с. 29-31.
5. Скачать последние версии сервера - http://lirc.sourceforge.net
6. http7/raxp.radioliga.com/cnt/s.php?p=bt.zip
7. Ресурсы тестового модуля DTMF-FFT и ПО SPEKTRA - http://raxp.radioliga.com/cnt/s.php?p=dtmf_res.zip
36
Радиолюбитель - 03/2009