Vadim_d, здесь не то, что по-бразильски. Все алгоритмы давно уже придуманы, придумывать велосипед смысла не имеет, поэтому на практике дело заканчивается обкаткой уже существующих решений. Кроме того при программировании проограммист сначала отлаживает программу и реализацию существующего алгоритма, на это может уйти много времени. Поэтому тут как бы совмещение неприятного с полезным. Ну и еще есть такой момент как ресурсы проца. Многие алгоритмы откидываются сразу по причине невозможности реализации, а реализованные итак слышно и видно как они работают.
Если алгоритм известен и реализация есть, то можно и так, но из моей практики обработки одно- и двумерных сигналов процесс начинался с пробы алгоритмов в Маткаде на известных данных с оценкой времени их работы, затем отбор для следующей пробы - Си на ПК, и финал уже на целевой платформе (PowerPC), где собственно оставалось убедиться, что все работает
Вадим, у вас более правильный подход, характерный для больших или специализированных контор. В моем случае этап переноса с ПК на целевое железо нецелесообразен - во первых я один программист и транслятор алгоритмов, во вторых ПК и мой проц это несопоставимые вещи.
Добавлено через 11 минут(ы):
Возник вопрос - а что если в традиционном подавителе шумов с LMS алгоритмом использовать КИХ фильтр с симметричными коэффициентами? В этом случае нет смысла пересчитывать все коэффициенты, можно хорошо сократить затраты на вычисление. Кто-нибудь пробовал?
Последний раз редактировалось rx9cim; 29.10.2015 в 14:56.
Спасибо! Вот и я тоже не вижу смысла... Правда фильтры у меня рассчитываются по другим алгоритмам, но параметры примерно такие же. Вот 100Гц/500Гц/2400Гц (точнее их половинки, это в старом трансивере):
Английская. Давайте, я вечером нарисую, или распишу подробнее.
Пока смысла так делать не вижу, хотя некоторые алгоритмы адаптивной фильтрации скорее всего будут работать в частотной области (но это вопрос будущего - сейчас мне нужно закончить минимальный набор "железа" - остался еще синтезатор, ну и потом доделки/модернизации ).
Может я Вас не совсем правильно понял, но это все в процессе расчета определяется - нет необходимости моделировать, что-то подавать на вход модели. КИХ фильтры вроде уже изучили со всех сторон. Если же речь об адаптивных фильтрах, то как дельта функция может помочь не знаю...
Добавлено через 5 минут(ы):
У меня процесс бывает разный Если вещи очевидные, то делаются сразу на DSP процессоре, где и проверяются. Если требуется проверка, то вначале в Матлабе экперименты, а потом уже реализация в DSP (на ассемблере). Иногда (редко) проверяю реализацию на С (на РС).
Кстати некоторые вещи, надо проверять учитывая особенности нашего восприятия, и здесь реальное железо уже ничего не заменит.
Последний раз редактировалось UR3IQO; 29.10.2015 в 15:20.
Yanus,
Всегда делал модель в Матлабе или SystemVue, с учетом особенностей железа (процессора). При отработки модели изпользую тест вектор (файл с отсчетами), которий подается для обработки. Содержание вектора может быт разное - бывало, что вектором исползовался запись голоса, бывало что вектор - прямая дискретизация ефира и т.д. Благо, не обязятельно отрабатывать все в реальном времени. При проработки модели записиваю результаты в интересующих точках. Проверка с железом - тот же самый вектор, проверка результата в интересующих точках. Совпадение - бит в бит если все сделанно правильно.
Все в ветке знают, по моему, что фильтр можно проверить подачей дельта функции на входе. А при анализа сложной системы, я не представляю как вектор в виде дельта функции поможеть.
Последний раз редактировалось LZ1AO; 29.10.2015 в 16:29.
ОК. Каким образом дельта функция поможет проверить систему в которой:
Два канала АЦП - децимация /8 с фильтрацией парой КИХ фильтров - два смесителя - два КИХ ПФ с разными фазовыми х-ками - адаптивный режекторный фильтр в двух вариантах - система АРУ - ... Думаю достаточно Да, еще есть интересный вариант с RTTY декодером в конце цепочки Если мне сильно надо что-то проверить, то генерируются тестовые данные, на которых проверяется функционирование либо отдельных узлов, либо всего в целом.
Вот изобразил
Не знаю стало ли понятней. В оригинале значения оценки АКФ использовались напрямую в качестве коэффициентов фильтра (как на верхнем рисунке), я добавил умножение на оконную функцию (как на нижнем) - так работает получше (по крайней мере для моих ушей ).
Есть метод когда коэффициенты обновляются не все сразу, а частями, Вашего варианта не встречал.
АКФ постоянно пересчитывается в временном окне? У вас есть скайп или виртуальная шарманка? Какое окно используете и какая длина?
Добавлено через 42 минут(ы):
Вот мой код RTTY который так и не заработал:
#include "global.h"
#ifdef RTTY_USE
#define NZEROS 4
#define NPOLES 4
struct CommonRtty rtty_options;
extern struct common_options options;
float filter2125(float input)//для Fs=6000
{
static float xv[NZEROS+1], yv[NPOLES+1];
float GAIN = 3.920745475e+02;
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4];
xv[4] = input/ GAIN;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4];
yv[4] = (xv[0] + xv[4]) - 2 * xv[2]
+ ( -0.8623486260 * yv[0]) + ( -2.1804327121 * yv[1])
+ ( -3.2324838183 * yv[2]) + ( -2.3482564029 * yv[3]);
return(yv[4]);
}
float filter2295(float input)
{
static float xv[NZEROS+1], yv[NPOLES+1];
float GAIN = 3.920744454e+02;
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4];
xv[4] = input/ GAIN;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4];
yv[4] = (xv[0] + xv[4]) - 2 * xv[2]
+ ( -0.8623486261 * yv[0]) + ( -2.6491754531 * yv[1])
+ ( -3.8897575995 * yv[2]) + ( -2.8530773664 * yv[3]);
return(yv[4]);
}
float filter1845(float input)
{
static float xv[NZEROS+1], yv[NPOLES+1];
float GAIN = 3.920745780e+02;
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4];
xv[4] = input/ GAIN;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4];
yv[4] = (xv[0] + xv[4]) - 2 * xv[2]
+ ( -0.8623486261 * yv[0]) + ( -1.2660593717 * yv[1])
+ ( -2.3175267916 * yv[2]) + ( -1.3635055141 * yv[3]);
return(yv[4]);
}
float lowPass(float sampleIn)//50Гц для Fs=6000
{static float xvLP[3], yvLP[3];
xvLP[0] = xvLP[1]; xvLP[1] = xvLP[2];
xvLP[2] = sampleIn / 1.513365061e+03;
yvLP[0] = yvLP[1]; yvLP[1] = yvLP[2];
yvLP[2] = (xvLP[0] + xvLP[2]) + 2 * xvLP[1]
+ ( -0.9286270861 * yvLP[0]) + ( 1.9259839697 * yvLP[1]);
return yvLP[2];
}
void DigiDecoderWaitBuffe r (void)
{
volatile int tmp=0;
while (rtty_options.Start= =0);
}
float getSample(void)
{
static int TmpOld=0;
if (TmpOld!=rtty_option s.HalfOfBuffer)
{
TmpOld=rtty_options. HalfOfBuffer;
if (rtty_options.HalfOf Buffer==0)
rtty_options.ptr_src =2112;
else rtty_options.ptr_src =0;
}
else;
if (rtty_options.ptr_cn t==2112)
{
if(rtty_options.Half OfBuffer==0)
while (rtty_options.HalfOf Buffer!=1);
else
while (rtty_options.HalfOf Buffer!=0);
rtty_options.ptr_cnt =0;
}
rtty_options.ptr_cnt ++;
return rtty_options.rtty_bu ffer[rtty_options.ptr_src +rtty_options.ptr_cn t-1];
}
int demodulator (void)
{
float input;
float tmp;
float mark;
float space;
input =getSample();
if (options.Rx_Tx_mode= =1)//USB
{
//space = filter2125(input);
space = filter1845(input);
mark = filter2295(input);
}
else
{
//mark = filter2125(input);
mark = filter1845(input);
space = filter2295(input);
}
space *= space;
mark *= mark;
tmp =mark- space;
// tmp =space- mark;
//tmp= lowPass(tmp);
if (tmp > 0)
return 1;
else
return 0;
}
int getBitDPLL(void)
{
int phaseChanged = 0;
int val = 0;
while (rtty_options.DPLLBi tPhase < rtty_options.oneBitS ampleCount)
{
val = demodulator();
if (!phaseChanged && val != rtty_options.DPLLOld Val)
{
if (rtty_options.DPLLBi tPhase < rtty_options.oneBitS ampleCount/2)
rtty_options.DPLLBit Phase += rtty_options.oneBitS ampleCount/8; // early
else
rtty_options.DPLLBit Phase -= rtty_options.oneBitS ampleCount/8; // late
phaseChanged = 1;
}
rtty_options.DPLLOld Val = val;
rtty_options.DPLLBit Phase++;
}
rtty_options.DPLLBit Phase -= rtty_options.oneBitS ampleCount;
return val;
}
int getBitDPLL_2(void)
{
int bitResult;
int tmp;
tmp= demodulator();
for (int i = 0; i < (rtty_options.oneBit SampleCount-1); i++)
{ bitResult = demodulator();
}
return tmp;
}
void GetDecimate (float* input)
{
for (int i=0;i<1024;i+=rtty_o ptions.DecimationFac tor)
rtty_options.Decimat eBuffer[i/rtty_options.Decimat ionFactor]=input[i];
}
void CopyDigiModeBuffer (float* input)
{
int i=0;
GetDecimate (input);
for (i=0;i<128;i++)
{
rtty_options.rtty_bu ffer[rtty_options.ptr_dst]=rtty_options.Decima teBuffer[i];
rtty_options.ptr_dst ++;
}
if (rtty_options.ptr_ds t<2112)
{
rtty_options.HalfOfB uffer=0;
}
else
{rtty_options.HalfOf Buffer=1;
rtty_options.Start=1 ;
}
if (rtty_options.ptr_ds t>=4224)
rtty_options.ptr_dst =0;
}
void RttyInit (void)
{
rtty_options.BitsPer Sec=50.0f;//45.45f;
rtty_options.Decimat ionFactor=8;
rtty_options.oneBitS ampleCount=(int)(((f loat)SAMPLE_RATE/(float)rtty_options. DecimationFactor)/rtty_options.BitsPer Sec);
}
// this function returns only when the start bit is successfully received
void waitForStartBit(void ) {
int bitResult;
do {
bitResult = demodulator();
} while (bitResult != 0 );
for (int i = 0; i < (rtty_options.oneBit SampleCount*3/2); i++)
{ bitResult = demodulator();
}
}
static unsigned char letters[32] = {
'\0', 'E', '\n', 'A', ' ', 'S', 'I', 'U',
'\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K',
'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q',
'O', 'B', 'G', '·', 'M', 'X', 'V', '·'
};
static unsigned char figures[32] = {
'\0', '3', '\n', '-', ' ', '\'', '8', '7',
'\r', '$', '4', '\a', ',', '!', ':', '(',
'5', '+', ')', '2', 'H', '6', '0', '1',
'9', '?', '&', '·', '.', '/', '=', '·'
};
void RttyDecoder (void)
{
static int byteResultp = 0;
static int bitResult=0;
char ch;
rtty_options.byteRes ult = 0;
byteResultp = 0;
bitResult=0;
waitForStartBit();
for (byteResultp = 1, rtty_options.byteRes ult = 0; byteResultp < 7; byteResultp++)
{
//bitResult = getBitDPLL();
bitResult = getBitDPLL_2();
switch (byteResultp) {
case 6:
{if (bitResult!=1)
{ rtty_options.byteRes ult=0;
return;
}
}
break;
default:
rtty_options.byteRes ult += bitResult << (byteResultp-1);
}
}
switch (rtty_options.byteRe sult) {
case 0x1F: /* letters */
{rtty_options.Baudot LetFig = 0;
return;
}
break;
case 0x1B: /* figures */
{rtty_options.Baudot LetFig = 1;
return;
}
break;
case 0x04: /* unshift-on-space */
rtty_options.BaudotL etFig = 0;
ch= ' ';
break;
case 0x02: /* unshift-on-space */
rtty_options.BaudotL etFig = 0;
ch= ' ';
break;
default:
{
if (rtty_options.Baudot LetFig == 0)
ch = letters [rtty_options.byteRes ult];
else
ch = figures [rtty_options.byteRes ult];
rtty_options.Symbol[rtty_options.SymbolC nt]=ch;
rtty_options.SymbolC nt++;
if (rtty_options.Symbol Cnt>=32)rtty_options .SymbolCnt=0;
}
break;
}
}
#endif
здесь технологический вариант, использовал так же функции getbit_DPLL
Последний раз редактировалось rx9cim; 29.10.2015 в 21:02.
Да, оценка обновляется каждый отсчет.
В скайпе когда-то зареган был, не пользовался правда давно очень А что такое виртуальная шарманка ?У вас есть скайп или виртуальная шарманка?
Дина регулируется от 2мс до 18мс, окно Гаусса, в принципе там любое работает, звучат немного по разному.Какое окно используете и какая длина?
Вы бы как-то описали, что именно не работает?
Кстати, а почему такой странный разнос у фильтров? Должно быть 170Гц.
И еще, откуда Вы таблицу для декодирования взяли? У меня она другая:
Первые две строки это стандартная кодировка RTTY сигналов.Код:const char *Decode[4] = { " T\rO HNM\nLRGIPCVEZDBSYFXAWJ UQK", //English " 5\r9 #,.\n)4&80:=3+$?'6!/-2 71(", //Figures Case (Eng) " Т\rО ХНМ\nЛРГИПЦЖЕЗДБСЫФЬАВЙ УЯК", //Russian " 5\r9 Щ,.\n)ЧШ80:=3+$?'6Э/-2Ю 71(", //Figures Case (Rus) };
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)