Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Декодирование DTFM [D3, D5, Win95/98, WinXP]


Страницы:   1 2

Вадим ©   (2004-05-22 17:34:00) 

Здравствуйте. Задача стоит такая. На линейный вход приходит последовательность цифр в виде DTFM. Необходимо в реальном времени преобразовывать это снова в цифры. DTFM представляет собой смесь двух частот (одной нижней и одной верхней) из следующего ряда: 697, 770, 852, 941 (нижние), 1209, 1336, 1477 и 1633 Гц (верхние). Что позволяет закодировать 16 символов: 1, 2, 3, A, 4, 5, 6, B, 7, 8, 9, C, *, 0, #, D. Таким образом, проблема сводится к тому, чтобы обнаружить наличие или отсутствие данных частот во входном сигнале, но как это сделать не представляю… В обсуждении темы fft.dll ( http://www.delphimaster.ru/cgi-bin/forum.pl?id=1082816087&n=7) видел процедуру, делающую БПФ, и по этому ( http://www.delphikingdom.com/asp/answer.asp?IDAnswer=5489) адресу было что-то подобное, но как этим воспользоваться до меня не доходит. Либо есть более простой выход?


MegaVoltik   (2004-05-31 10:26:00) [21]

А чем вас аппаратный декодер не устраивает то? Сигнал всё равно от куда то братся должен? Если качественно определять то жедаетельно АЦП ставить. А если АЦП не ставить а просто компаратор как в АОНах то я думаю для такого входного сигнала есть свои специальные методы. Сходи на http://www.telesys.ru/teleconf.shtmlтам помогут :)


Evgeny V   (2004-05-29 05:27:00) [22]

Извини Вадим, я и правда ввел тебя в заблуждение,
давно этим уже не занимался и подзабыл. Сорри. И так нам надо
посчитать энергию при выбранных частотах. En=Acos^2+ASin^2,
где Acos - косинусные и Asin -синусные коэффициенты (Re и Im).
Acos=Sum(buf[i])*Cos(2*pi*Freq*i/N) и Asin=Sum(buf[i])*Sin(2*pi*Freq*i/N) где i меняется oт 0 до N-1,
вот исправленный код с прорисовкой графиков сигнала и двух значений энергий для частот 1000 и 750
Графики рисую в Tchart, Series выбран Line или FastLine.

procedure TForm1.Button3Click(Sender: TObject);
var
i,j: integer;
EnX: array [0..63] of double;
EnY: array [0..63] of double;
EnX1: array [0..63] of double;
EnY1: array [0..63] of double;
Acos1000,Asin1000,Acos750,Asin750:double;
Freq1000: double;
Freq750,t1,t2,t3,t4:double;
En1000,En750:double;
buf: array [0..3999] of double;
begin
Freq1000:=1000;
Freq750:=750;
Chart1.Series[0].Clear;
Chart1.Series[1].Clear;
Chart1.Series[2].Clear;
j:=0;

for i:=0 to 63 do
  begin
  EnX[i]:=0;
  EnY[i]:=0;
  EnX1[i]:=0;
  EnY1[i]:=0;
  end;
for i:=0 to 999 do
buf [i]:= 0;// сигнала нет
for i:=0 to 2000 do
  buf [i+1000]:= sin (2*pi*i*Freq1000/8000); //с 1000 точки сигнал 1000
for i:=0 to 999 do
 buf [i+3000]:= sin (2*pi*i*Freq750/8000); //с 3000 тысячной точки сигнал 750
ACos1000:=0;
ASin1000:=0;
ACos750:=0;
ASin750:=0;

for i:=0 to 3999 do// внутри цикла у нас неявный подцикл по массивам En из 64 итераций
begin
j:=j mod 8000;
ACos1000:=ACos1000-EnX[i mod 64]; // вычитаем из значения коэффициента косинуса значения прошлого подцикла
ASin1000:=ASin1000-EnY[i mod 64];// // вычитаем из значения коэффициента синуса значения прошлого подцикла

EnX[i mod 64]:=buf[i]*Cos(2*pi*Freq1000*j/8000.0);// вычисляем значение в текущей точке
EnY[i mod 64]:=buf[i]*Sin(2*pi*Freq1000*j/8000.0);
ACos1000:=ACos1000+EnX[i mod 64];// cуммируем значения для получения значения коэффициента косинуса
ASin1000:=ASin1000+EnY[i mod 64];// cуммируем значения для получения значения коэффициента синуса
t1:=ACos1000*ACos1000;// квадрат
t2:=ASin1000*ASin1000;// квадрат
En1000:=Sqrt((t1*t1+t2*t2))/64;// находим значение энергии для заданной частоты
//корень квадратный и деление на  64 не нужно, сделано только для удобства отображения на графике,
//большие значения получаются

/ все то же для другой частоты
ACos750:=ACos750-EnX1[i mod 64];
ASin750:=ASin750-EnY1[i mod 64];
EnX1[i mod 64]:=buf[i]*Cos(2*pi*Freq750*j/8000.0);
EnY1[i mod 64]:=buf[i]*Sin(2*pi*Freq750*j/8000.0);
ACos750:=ACos750+EnX1[i mod 64];
ASin750:=ASin750+EnY1[i mod 64];
t3:=ACos750*ACos750;
t4:=ASin750*ASin750;
En750:=Sqrt((t3*t3+t4*t4))/64;
Inc(j);
Chart1.Series[0].AddY( buf[i],'',clRed);// показываем сигнал
Chart1.Series[1].AddY( En1000/50,'',clGreen);// значения энергии частоты 1000
// на 50 делю тоже только для смотрибельности на грфике
Chart1.Series[2].AddY( En750/50,'',clBlue);// значения энергии частоты 750
Edit1.Text:=IntToStr(i);// просто показываю сколько точек пробежал
if (i mod 1000) =0 then
AppLication.ProcessMessages;// даю возможность прорисоваться графику и эдиту
end;
end;
Тебе прийдется еще решать проблему с определением сигнала вообще, помнишь porog?
В линии все равно шумы есть и энергии сигнала будут присутствовать, но меньшими значениями,
поэтому их надо сравнивать с пороговым значением, его я подбирал экспериментально.
Для радио у меня получилась формула Sum(Abs(buf[i])*0.5 > Max(sqrt(En)/N)  - i от 0 до N-1,
Может и тебе она подойдет, поиграйся с коэффициентом, не 0.5, а может другой.
Потом при смене частотной посылки возможны кратковременные появления энергий
"ложных" частот, так что суди о наличии частоты по нескольким опредлениям энергии,
например за 5 подциклов по 64 вычисления. Будут вопросы пиши, лучше наверное на почту.
evgeny_v@rambler.ru. Удачи, извини еще раз за ошибку в предыдущих постах.


Вадим   (2004-05-28 12:33:00) [23]

To KilkennyCat: Не такой уж и проостой. Ведь внешние устройства нужно програмно обслуживать. Я с COM-портом кое-как разобрался, да и то не до конца, а тут ещё LPT! Так зачем городить огород, если можно всё решить толькопрограммным путём.
To Evgeny V. Сделал так:

{$N+}
Uses
   CRT;

var
i,j: integer;
EnX: array [0..63] of double;
EnY: array [0..63] of double;
An, Freq: double;
buf: array [0..3999] of double;
begin
ClrScr;
j:=0;
An:=0;
for i:=0 to 63 do
   begin
   EnX[i]:=0;
   EnY[i]:=0;
   end;
for i:=0 to 3999 do
   buf [i]:= sin (2*pi*i*500/4000); //- опять же 1000 Гц
       for i:=0 to 999 do
       buf [i+3000]:= sin (2*pi*i*93.75/1000); //- как бы в конце появилось 750 Гц

begin
writeln;
Freq:=750;
for i:=0 to 3999 do
begin
j:=j mod 8000;
An:=An-EnX[i mod 64]*EnX[i mod 64]-EnY[i mod 64]*EnY[i mod 64];
EnX[i mod 64]:=buf[i]*Cos(2*pi*Freq*j/8000.0);
EnY[i mod 64]:=buf[i]*Sin(2*pi*Freq*j/8000.0);
An:=An+EnX[i mod 64]*EnX[i mod 64]+EnY[i mod 64]*EnY[i mod 64];
Inc(j);
end;
writeln;
writeln (An:5:3);
end;
end.

Всё равно An у меня принимает одно и то же значение (32.000) при любых раскладах. Оно меняется толькоесли последние 64 элемента "буфера" заполнить нулями - тогда An=0, если последние 32, то An=16.000. "Нужную" частоту вставлял не только в конце, но и в середине (с 2000 элемента) - эффект тот-же. ???
А почитат исходники по нужной теме всегда поучительно, тем более разобраться в них! Ещё раз спасибо.


Evgeny V   (2004-05-28 05:46:00) [24]

Ошибки нет, дело в том что энергия не появится сразу, и в начале у тебя все инициализировано 0 и с первого буфера An будет расти медленно, ты сделай буфер на секунду, и в нем только на 100 миллисикунд заполни значения частотой, например в середине, тогда будет видно изменения. Про j когда будешь бежать по буферу более чем 64 выборки, 12000 например, то j не будет равно i

for i:=0 to N-1 do
begin
j:=j mod 8000;
An:=An-EnX[i mod 64]*EnX[i mod 64]-EnY[i mod 64]*EnY[i mod 64];
EnX[i mod 64]:=buf[i]*Cos(2*pi*Freq*j/8000.0);
EnY[i mod 64]:=buf[i]*Sin(2*pi*Freq*j/8000.0);
An:=An+EnX[i mod 64]*EnX[i mod 64]+EnY[i mod 64]*EnY[i mod 64];
write (i,' ',EnX[i mod 64]:5:3,' '); - это кстати не очень наглядный коэффициент, энергия должна сильно меняться
write (i,' ',EnX[i mod 64]:5:3,' '); - аналогично
Inc(j);
end;
writeln;
writeln (An:5:3);
end;
N -cделай побольше,ну пусть 4000, и тысячу значений в нем например заполни синусом нужной частоты. Посмотри результат тогда, если не получится, пришлю тебе прогу и исходник, где я  делаю похожие вещи. Удачи, пиши, можешь на мыло в моей анкете.


KilkennyCat   (2004-05-28 05:10:00) [25]

Наиболее простой способ обойдется в 50 рублей, час работы паяльником.... микруха декодера DTMF -> LPT


Вадим   (2004-05-27 22:30:00) [26]

To Evgeny V. Извиняюсь, что долго думал, но так уж получилось. Вот что я делал, чтобы "поиграться":

{$N+}
Uses
   CRT;

var
i,j: integer;
EnX: array [0..63] of double;
EnY: array [0..63] of double;
An, Freq: double;
buf: array [0..63] of double;
begin
ClrScr;
j:=0;
for i:=0 to 63 do
   begin
   Enx[i]:=0;
   Eny[i]:=0;
   buf [i]:= sin (2*pi*i*8/64);//- в ручную заполняю буфер из расчета - входящяя 1000 и дескридитация 8000 Герц
   write (i,' ',buf[i]:5:3,' ');//- посмотреть, чем заполнил
   end;
begin
writeln;
An:=0;
Freq:=1000;
for i:=0 to 63 do
begin
j:=j mod 8000;
An:=An-EnX[i]*EnX[i]-EnY[i]*EnY[i];
EnX[i]:=buf[i]*Cos(2*pi*Freq*j/8000.0);
EnY[i]:=buf[i]*Sin(2*pi*Freq*j/8000.0);
An:=An+EnX[i]*EnX[i]+EnY[i]*EnY[i];
write (i,' ',EnX[i]:5:3,' ');
Inc(j);
end;
writeln;
writeln (An:5:3);
end;
end.

Делалось это в Борланде. Так вот, какое бы значение Freq я не задавал, An остается одно и то же! Где здесь ошибка? В алгоритме ДПФ или я сделал что-то не так? И зачем былаа введена переменная j, ведь она в цикле принимает те же значения, что и i? А вообще спасибо, если это сработает, то будет то, что надо!


Jeer   (2004-05-24 15:38:00) [27]

Алгоритм Герцеля (Goerzel)
http://factaee.elfak.ni.ac.yu/fu2k33/9mp.html


Evgeny V   (2004-05-24 06:21:00) [28]

В данном случае лучше дискретное преобразование фурье во скользящему окну(это точнее позволит определить момент смены сигнала), приведу пример для нахождения одной заданной частоты по N значениям, например частота дискретизации 8000, берем выборки из 64 значений( это цифра должна быть степенью 2 и достаточно большая, что бы обеспечить точность измерения частоты) и по ним делаем преобразование, шаг между частотами по спектру в этом случае 8000/64 125 герц (фактически это ширина полосы определяемой частоты, спектральной палки, точность), делаем массив выборок для мнимой и действительно части из 64 элеменотов, тогда делаем следующее (пример для одной частоты, посчитаешь сам )
EnX:array [0..63] double - сумма коэффициентов реальной части для заданной частоты
EnУ:[0..63] double - сумма коэффициентов мнимой части для заданной частоты
An:double - Энергия заданной частоты
buf:array [0..63] - твои выборки сигнала с саунда.
porog;double -  величина, с которой ты сравниваешь на наличие частоты
j:integer - циклический счетчик, местонахождение фазы измерения, свяжем его с частотой дискретизации
Freq - заданная частота
Вначале все переменные, массивы раны нулю, кроме porog и Freq, это уже задается;

Предварительно заполни массив buf - очередной порцией выборок саунда - 64 выборки, можно и больше взять число, 128, 256 и т.д, влияет на точность определения и временной интевал, за который определяем
for i:=0 to 63 do
begin
j:=j mod 8000;
An:=An-EnX[i]*EnX[i]-EnY[i]*EnY[i];// - вычитаем из суммы коэффициентов самое старое значение, на его место запишем следом новое
EnX[i]:=buf[i]*Cos(2*pi*Freq*j/8000.0);// вычислим реальную часть
EnY[i]:=buf[i]*Sin(2*pi*Freq*j/8000.0);// вычислим мнимую часть
An:=An+EnX[i]*EnX[i]+EnY[i]*EnY[i];// значение энергии в заданной точке по результату 64 выборок
Inc(j);
if An >= porog then  частота есть в сигнале
end;

Получим новые 64 выборки и повторим вычисления и так до .....

Вот весьма упрощенный алгоритм определения частоты в сигнале. Если ты не поленишься и построишь реальные графики(Tchart например весьма для этого удобен) сигнала и этих вычислений (можешь провести их для каждой частоты DTMF), то наглядно увидишь что и как, это лучше чем рассказывать, поиграйся с размером массива, можно и не 64, это дело твое, насколько помню, в DTMF частоты могут лежать довольно близко в строках или стобцах, и тебе лучше будет брать размер 128 точек или больше.


Вадим   (2004-05-23 21:54:00) [29]

Я, конечно, извиняюсь, но неужели не найдется человека, знающего как мне помочь?


Вадим   (2004-05-22 23:16:00) [30]


> Ты хотел простой выход - я тебе его подсказал

Спасибо, но давай не устраивать полемику. Я же в вопросе даже дал ссылки на сравнительно несложные алгоритмы для преобразования БПФ. Мне нужна хотя бы подсказка как ихприменить для решения моей проблемы. Либо что-нибудь болеепростое. Ещё раз повторю, буду признатален за конкретнуюпомощь или подсказу


Jel   (2004-05-22 22:16:00) [31]


> А ты сам-то видел, то, что советуешь?!

Вообще-то видел. Зря шумишь. Ты не говорил что тебе нужны бесплатные решения не весящие мегабайты. Ты хотел простой выход - я тебе его подсказал. Подходит - отлично, нет - ищи другой.
:)


Вадим   (2004-05-22 21:07:00) [32]

To Jel. А ты сам-то видел, то, что советуешь?! Там либо генераторы DTFM, либо компоненты, которые "весят" мегабайты и стоят совсем нехило! Нужен дельный совет, расчитанный на мою пока не высокую квалификацию.


Jel   (2004-05-22 17:58:00) [33]

Посмотри готовые компоненты тут
http://www.torry.net/quicksearchd.php?SID=f8370ce5e349ab4b6be3a0a0bce1fd4b&String=DTMF&Title=No


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо