DSPSYSTEM Теория и практика цифровой обработки сигналов

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » DSPSYSTEM Теория и практика цифровой обработки сигналов » Алгоритмы и их программирование » передискретизация полиномами разной степени на основе фильтра Фарроу


передискретизация полиномами разной степени на основе фильтра Фарроу

Сообщений 1 страница 13 из 13

1

для начала хочу разобрать уже имеющуюся конструкцию фильтра третьей степени.

// Функция расчета кубического полинома
// на основе модифицированного фильтра Фарроу
double interp(double *y, double x){
    double a3 = (y[3]-y[0])/6.0+(y[1]-y[2])/2.0;
    double a1 = (y[3]-y[1])/2.0-a3;
    double a2 = y[3]-a3-a1-y[2];
    return x*(x*(x*a3+a2)+a1)+y[2];
}

// собственно фильтрующая конструкция

for(int i = 0; i<K; i++){
        t1[i] = (double)i/Fs1;                // текущий момент дискретизации
        int j = int((double)i*Fs0/Fs1)-2;    // пересчитываю индекс исходного сигнала
        if(j<0) j =0;                        // если индекс отрицателььный то приравниваю его к 0
        double x = (t1[i]-t0[j])*Fs0-2;        // пересчитываю значение x
        y1[i] = interp(y0+j, x);            // фильтр Фарроу
        t1[i] *= 1E3;                        // перевожу время результата ресэмплинга в мс
    }

Рассуждения будем вести относительно полинома 4-й степени

1) как я понимаю фильтрующая конструкция остаётся всегда без изменений?
2)функция же самого фильтра естественно будет расчитывать уже четыре коэффициента.
я правильно понимаю, что y0+j в принимаемых значениях означает инкремент для индекса у в функции interp?
т.е. если j = 0 то функция расчитывает коэффиценты по y0[0], y0[1], y0[2], y0[3].
если же, скажем j = 1, то функция расчитывает коэффициенты по y0[1], y0[2], y0[3], y0[4]?

3) Вы расчитываете коэффиценты исходя из того что моменты у вас [-2; -1; 0; 1]
у меня для фильтра 4-й степени моменты можно взять такие [-2; -1; -0.5; 0; 1] - справедливо?

4) вы говорите: "На практике необходимо стремиться вести пересчет шкалы времени именно в интервал от -1 до 0"
а потом вы в примере говорите что x нужно пересчитать от -2 до 1. как это объяснить?

Отредактировано Franky (2010-03-23 22:11:12)

0

2

понял что для 4-й степени лучше взять интервалы [-2; -1; 0; 1; 2]

Но всё равно смущает фраза "На практике необходимо стремиться вести пересчет шкалы времени именно в интервал от -1 до 0"

0

3

Franky написал(а):

как я понимаю фильтрующая конструкция остаётся всегда без изменений?

нет перечет времени надо вести в "середину" полинома. Например если 3 степени полином, т.е. отсчеты -2 -1 0 1, то надо время пересчитывать в интервал -1 0, если 4 степени полином, т.е. отсчеты -2 -1 0 1 2, то также время надо пересчитывать в интервал -1 0, но индекс входного сигнала пересчитываться должен будет уже так:

Код:
int j = int((double)i*Fs0/Fs1)-3;    // пересчитываю индекс исходного сигнала

соответсвенно для полинома степени Kp в общем случае можно написать так:

Код:
int j = int((double)i*Fs0/Fs1)-Kp+1;    // пересчитываю индекс исходного сигнала
Franky написал(а):

функция же самого фильтра естественно будет расчитывать уже четыре коэффициента.

у полинома 4 степени 5 коэффициентов a0 + a1*x +a2*x^2+a3*x^3+a4*x^4

Franky написал(а):

я правильно понимаю, что y0+j в принимаемых значениях означает инкремент для индекса у в функции interp?
т.е. если j = 0 то функция расчитывает коэффиценты по y0[0], y0[1], y0[2], y0[3].
если же, скажем j = 1, то функция расчитывает коэффициенты по y0[1], y0[2], y0[3], y0[4]?

нет не правильно. Рассуждаем еще раз. Есть частота дискретизации Fs0 имеем отсчеты сигнала на этой частоте и есть частота дискретизации на которую хотим произвести ресамплинг Fs1
Давайте рассчитаем i - ый отсчет на выходе ресамплинга. i-ый отсчет соответствует времени t1[i] = i/Fs1, тогда найдем наиболее близкий временной отсчет исходного сигнала он равен  i*Fs0/Fs1 и поместим его в интервал -1 0, для этого вычтем из этого индекса 2 отсчета тогда получили что j = i*Fs0/Fs1 - 2 как и в примере.

если i = 0, (рассчет первого отсчета) то получим j = -2 и в примере есть строчка которая проверяет это и не допускает отрицательного индекса

Код:
if(j<0) j =0;                        // если индекс отрицательный то приравниваю его к 0

j показывает номер исходного отсчета с которого необходимо начинать интерполяцию по 4 точкам. Если j отрицательно то начать с нулевого отсчета поскольку отрицательных индексов нет

Franky написал(а):

т.е. если j = 0 то функция рассчитывает коэффициенты по y0[0], y0[1], y0[2], y0[3].
если же, скажем j = 1, то функция рассчитывает коэффициенты по y0[1], y0[2], y0[3], y0[4]?

это правильно

Franky написал(а):

вы говорите: "На практике необходимо стремиться вести пересчет шкалы времени именно в интервал от -1 до 0"
а потом вы в примере говорите что x нужно пересчитать от -2 до 1. как это объяснить?

ну очень просто есть 4 отсчета мы по ним строим полином разумеется на краях полинома (в районе x = -2 и x = 1)  ошибки больше чем в середине (в интервале -1 0) вот эта фраза и говорит что лучше всего (точнее всего) рассчитываются значения в середине полинома чем на его краях. Для этого и пересчет весь этот затеян с вычитанием двоечек чтобы рассчет вести в середине полинома.

0

4

Вот, сегодня расчитал вручную коэффиценты фильтра для четвёртого порядка.

получилось так

// Функция расчета полинома 4-й степени
// на основе модифицированного фильтра Фарроу
double interp(double *y, double x){
    double a4 = (y[0] + y[4])/24.0 - (y[1] + y[3])/6.0 + y[2]/4.0;
    double a3 = (y[4] - y[0])/12.0 - (y[1] - y[3])/6.0;
    double a1 =  (y[3] - y[1])/2.0 - a3;
    double a2 = (y[1] + y[3])/2 - a4;
    return x*(x*(x*(x*a4+a3)+a2)+a1)+y[2];
}

// фильтрующая конструкция

for(int i = 0; i<K; i++){
        t1[i] = (double)i/Fs1;                // текущий момент дискретизации
        int j = int((double)i*Fs0/Fs1)-3;    // пересчитываю индекс исходного сигнала
        if(j<0) j =0;                        // если индекс отрицателььный то приравниваю его к 0
        double x = (t1[i]-t0[j])*Fs0-3;        // пересчитываю значение x
        y1[i] = interp(y0+j, x);            // фильтр Фарроу
        t1[i] *= 1E3;                        // перевожу время результата ресэмплинга в мс
    }

Так, теперь фильтр 1-й стпени

// Функция расчета полинома 1-й степени
// на основе модифицированного фильтра Фарроу
double interp(double *y, double x){
   
    double a1 = y[1] - y[0];
    return x*a1 + y[1];
}

// фильтрующая конструкция

for(int i = 0; i<K; i++){
        t1[i] = (double)i/Fs1;                // текущий момент дискретизации
        int j = int((double)i*Fs0/Fs1);    // пересчитываю индекс исходного сигнала
        if(j<0) j =0;                        // если индекс отрицателььный то приравниваю его к 0
        double x = (t1[i]-t0[j])*Fs0;        // пересчитываю значение x
        y1[i] = interp(y0+j, x);            // фильтр Фарроу
        t1[i] *= 1E3;                        // перевожу время результата ресэмплинга в мс
    }

ну и вторая степень

double interp(double *y, double x){
   
    double a2 = (y[0] + y[2])/2.0 + y[1];
    double a1 = (y[2] - y[0])/2.0 - y[1];
    return x*(x*a2+a1)-2*[1];
}

// фильтрующая конструкция

for(int i = 0; i<K; i++){
        t1[i] = (double)i/Fs1;                // текущий момент дискретизации
        int j = int((double)i*Fs0/Fs1)-1;    // пересчитываю индекс исходного сигнала
        if(j<0) j =0;                        // если индекс отрицателььный то приравниваю его к 0
        double x = (t1[i]-t0[j])*Fs0-1;        // пересчитываю значение x
        y1[i] = interp(y0+j, x);            // фильтр Фарроу
        t1[i] *= 1E3;                        // перевожу время результата ресэмплинга в мс
    }

Отредактировано Franky (2010-03-24 20:00:51)

0

5

я доработал ваши функции (они не совсем корректно работали). вот пример программы которая умеет делать ресамплинг при помощи фильтров фарроу порядков 1 - 4. Также она рассчитывает ошибку интерполяции при использовании фильтров фарроу с порядками от 1 до 4

Код:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define M_PI       3.14159265358979323846 

// Функция сохранения результатов анализа в текстовый файл для
// построения графиков.
void saveToTXT(double* t, double* s, int n, char* fileName){
	FILE *file = fopen(fileName, "w");
	if(!file) return;
	for(int i = 0; i < n; i++)
    fprintf(file,"%e\t%e\n",t[i],s[i]);
	fclose(file);
}

// Функция расчета полинома 1-ой степени
// на основе модифицированного фильтра Фарроу
double farrow1(double *y, double x){   
    double a1 = y[1] - y[0];
    return x*a1 + y[0];
}

// Функция расчета полинома 2-ой степени
// на основе модифицированного фильтра Фарроу
double farrow2(double *y, double x){   
    double a2 = (y[0] + y[2])/2.0 - y[1];
    double a1 = y[2]-y[1] - a2;
    return x*(x*a2+a1)+y[1];
}

// Функция расчета кубического полинома 
// на основе модифицированного фильтра Фарроу
double farrow3(double *y, double x){
	double a3 = (y[3]-y[0])/6.0+(y[1]-y[2])/2.0;
	double a1 = (y[3]-y[1])/2.0-a3;
	double a2 = y[3]-a3-a1-y[2];
	return x*(x*(x*a3+a2)+a1)+y[2];
}

// Функция расчета полинома 4-ой степени
// на основе модифицированного фильтра Фарроу
double farrow4(double *y, double x){
    double a4 = (y[0] + y[4])/24.0 - (y[1] + y[3])/6.0 + y[2]/4.0;
    double a3 = (y[4] - y[0])/12.0 + (y[1] - y[3])/6.0;
    double a2 = -(y[0] + y[4])/24.0+2.0*(y[1] + y[3])/3.0-1.25*y[2];
	double a1 =  (y[0] - y[4])/12.0+2.0*(y[3] - y[1])/3.0;
    return x*(x*(x*(x*a4+a3)+a2)+a1)+y[2];
}

// Функция ресамплинга при помощи фильтра фарроу заданного порядка
void resample(double* y0, // массив исходных данных до ресамплинга
    	  double *t0, // время исходных данных  до ресамплинга
    	  double Fs0, // частота дискретизации  до ресамплинга
    	  int N,	  // количество отсчетов    до ресамплинга
    	  double* y1, // массив данных    	после ресамплинга
    	  double* t1, // время            после ресамплинга
    	  double Fs1, // частота дискретизации  после ресамплинга
    	  int K,	  // количество отсчетов    после ресамплинга
    	  int Nfilter)// порядок фильтра фарроу от 1 до 4
{
	double dx;
	if(Nfilter == 1) dx = 0;	// соответствующая поправка для пересчета времени
	if(Nfilter == 2) dx = 1;
	if(Nfilter == 3) dx = 2;
	if(Nfilter == 4) dx = 2;

	for(int i = 0; i<K; i++){
        t1[i] = (double)i/Fs1;        	  // текущий момент дискретизации
        int j = (int)((double)i*Fs0/Fs1)-(int)dx; // пересчитываю индекс исходного сигнала
        if(j<0) j =0;            	  // если индекс отрицателььный то приравниваю его к 0
        double x = (t1[i]-t0[j])*Fs0-dx;      // пересчитываю значение x
        if(Nfilter == 1) y1[i] = farrow1(y0+j,x); // интерполяция заданным фильтром
    if(Nfilter == 2) y1[i] = farrow2(y0+j,x);
    if(Nfilter == 3) y1[i] = farrow3(y0+j,x);
    if(Nfilter == 4) y1[i] = farrow4(y0+j,x);
    }	
}


int main(){
	double Fs0  = 300;    	// исходная частота дискретизации
	double Fs1  = 2400.0;    // частота дискретизации после ресэмплинга
	
	int K = 512;        // количество отсчетов после ресэмплинга
	int N = (int)K*Fs0/Fs1;    // количество исходных отсчетов
	
	// выделяю память под исходный сигнал
	double* y0 = (double*) malloc(N*sizeof(double));
	double* t0 = (double*) malloc(N*sizeof(double));
	
	// выделяю память под результат ресэмплинга
	double* tint = (double*) malloc(K*sizeof(double));  // время после ресамплинга
	double* yint = (double*) malloc(K*sizeof(double));	// идеальный сигнал при частоте дискретизации Fs1 
	
	double* y1 = (double*) malloc(K*sizeof(double));    // результат ресамплинга 	
	double* e  = (double*) malloc(K*sizeof(double));    // ошбика при инетрполяции
	
	// формирую исходный сигнал до ресамплинга
	for(int i = 0; i<N; i++){
    t0[i] = double(i)/Fs0;
    y0[i] = cos(2*M_PI*40*t0[i]);
	} 
	saveToTXT(t0,y0, N,"исходный сигнал.txt");        //сохраняю исходный сигнал в файл

	// формирую идеальный сигнал с которым буду сравнивать ошибку
	for(int i = 0; i<K; i++){
    tint[i] = double(i)/Fs1;
    yint[i] = cos(2*M_PI*40*tint[i]);    
	}
	saveToTXT(tint,   yint, N,   "идеальный сигнал.txt");	//сохраняю идеальный сигнал в файл
	
	// ресамплнг фильтром 1 порядка
	resample(y0,t0,Fs0,N,y1,tint,Fs1,K,1);
	for(int i = 0; i<K; i++) e[i] = yint[i] - y1[i];  // ошбика равна идеальный сигнал - результат ресамплинга
	saveToTXT(tint, y1, K, "resampling1.txt");      // сохраняю результат ресамплинга в файл
	saveToTXT(tint, e, K,  "e1.txt");          // сохраняю ошибку ресамплинга в файл
	
	// ресамплнг фильтром 2 порядка
	resample(y0,t0,Fs0,N,y1,tint,Fs1,K,2);
	for(int i = 0; i<K; i++) e[i] = yint[i] - y1[i];  // ошбика равна идеальный сигнал - результат ресамплинга
	saveToTXT(tint, y1, K, "resampling2.txt");      // сохраняю результат ресамплинга в файл
	saveToTXT(tint, e, K,  "e2.txt");          // сохраняю ошибку ресамплинга в файл

	// ресамплнг фильтром 3 порядка
	resample(y0,t0,Fs0,N,y1,tint,Fs1,K,3);
	for(int i = 0; i<K; i++) e[i] = yint[i] - y1[i];  // ошбика равна идеальный сигнал - результат ресамплинга
	saveToTXT(tint, y1, K, "resampling3.txt");      // сохраняю результат ресамплинга в файл
	saveToTXT(tint, e, K,  "e3.txt");          // сохраняю ошибку ресамплинга в файл


	// ресамплнг фильтром 4 порядка
	resample(y0,t0,Fs0,N,y1,tint,Fs1,K,4);
	for(int i = 0; i<K; i++) e[i] = yint[i] - y1[i];  // ошбика равна идеальный сигнал - результат ресамплинга
	saveToTXT(tint, y1, K, "resampling4.txt");      // сохраняю результат ресамплинга в файл
	saveToTXT(tint, e, K,  "e4.txt");          // сохраняю ошибку ресамплинга в файл

	// чищу память
	free(y0);
	free(t0);

	free(yint);
	free(tint);

	free(y1);
	free(e);

	system("Pause");
	return 0;
}

0

6

Класс!!! Большущее вам спасибо. Разобрался полностью.

0

7

Ошибка.

if(Nfilter == 4) dx = 2

наверное должно быть

if(Nfilter == 4) dx = 3

... и ещё

saveToTXT(tint,   yint, N,   "идеальный сигнал.txt");

наверно должно быть

saveToTXT(tint,   yint, K,   "идеальный сигнал.txt");

Отредактировано Franky (2010-03-25 18:12:49)

0

8

нет все правильно if(Nfilter == 4) dx = 2  пересчет идет в интервал 0 1

0

9

а ещё интересно.

почему-то последний элемент в векторе ошибки всегда очень большое значение имеет (если амплитуда сигнала 1, то значение ошибки 0,9), но если этот элемент просто удалить - то всё нормально - погрешность похожа на правду.

а когда смотрю ветор ошибки для четвёртой степени, то сильно отличаются от всех остальных два последних элемента.
(странно как-то )

Почему такие всплески? Отличие на несколько порядков!!!!

1) Уважаемый, podalirius, вы упоминали, что для сравнения погрешности интерполяции чистый синус как сигнал не очень подходит. Тогда есть вопрос - какой лучше подавать сигнал.

В матлабе достаточно просто можно задать синусоиду зашумлённую гармониками, тогда возникает вопрос - как перевести массив из матлаба в си?

Единственное что приходит в голову - генератор случайных чисел. Тогда можно смоделировать Гауссов шум. Более объективно тогда порядок интерполяции оценить можно?

2) попробовал зашумить сигнал. При SNR = 40 дБ

// формирую исходный сигнал до ресамплинга
        int r;
        for(int i = 0; i<N; i++){
        r = 5 + rand() %180;
    t0[i] = double(i)/Fs0;
    y0[i] = cos(2*M_PI*f*t0[i])+ 0.01*cos(2*M_PI*r*f*t0[i]);
}

- причём эталонный сигнал имеет такуюже формулу.

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

    порядок            СКО
интерполяции
   1                       0.0039
                   
   2                       0.0040
                   
   3                       0.0042

   4                       0.0041

Вообще суть в том, что, как известно, большие порядки интерполяции приводят в конце концов к погрешности ( тобишь увеличение СКО). У меня же этого не наблюдается.

Может порядок интерполяции нужно всё-таки увеличивать? Хотя некоторые уверяют вот в чём:

"...В вашей задаче (если речь про Фурье всех гармоник) как раз Фарроу 3-го порядка и достаточен и вот почему:
1. Частота дискретизации, по-любому, из соображений точности должна накрывать сигнал так, чтобы на интервале между соседними 3-4 выборками сигнал мало отличался от 3-го порядка, т.к. иначе Вы с достаточной степенью точности этот сигнал не отфильтруете из-за вносимых искажений от гармоник более высоких порядков.
2. Т.к. исходный сигнал, всё-таки, содержит небольшой шум АЦП, к включению которого в огибающую интерполятор будет стремиться в меру своей степени, то наращивание порядка интерполяции приведёт к генерации несуществующих компонент."

Но этого не наблюдается.

Отредактировано Franky (2010-03-26 00:53:36)

0

10

во первых для исследования интерполяции эталонный сигнал должен быть полностью определен и без шума. Иначе вы будете мерить не ско ошибки интерполяции а ско шума. Вы правильно решили задать случайную частоту сигнала. Возьмите гармоник побольше и получите нормальный случайный процесс.
теперь про СКО. Из рассчета СКО надо выбросить конец интервала обработки где большие ошибки. Тогда данные будут различаться и при увеличении степени полнома с 1 по 4 ско будет падать.
При увеличении степени полинома ошибка будет падать если обработка ведется в "середине" полинома в идеальном случае при отсутствии шумов, хотя при больших порядках арифметическое округление коэффициентов полинома и наличие шумов приведет реально к росту ошибки интерполяции. Этот эффект можно наблюдать при полиномах степени выше чем 10 - 12.
Я еще подумаю как можно крайние точки рассчитать с меньшей ошибкой.

0

11

Да. На тестовых сигналах СКО с ростом порядка фильтра падает. Дело в том, что я думал, что на 4-й степени полинома СКО начнёт увеличиваться или перестанет падать. Тогда можно обосновано выбрать 3-й порядок.

А теперь возникает вопрос о том из каких критериев выбирать полином. какой лучше из соотношения
(вычислительные затраты)/(СКО)

0

12

ну это уже вам решать у вас есть все для исследования и принятия решения. Тут сложно чтото советовать ибо есть куча параметров от которых зависит решение, например разрядность вычислителя, арифметика с плавающей точкой и фиксированной, требуемое быстродействие и т.д.

0

13

Franky написал(а):

А теперь возникает вопрос о том из каких критериев выбирать полином. какой лучше из соотношения
(вычислительные затраты)/(СКО)

Я пропускал реальный сигнал (QPSK) через интерполятор и смотрел на созвездии либо MER, либо просто среднеквадратичное отклонение точки по углу от идеального положения. Делал это для разных полиномов и числа отсчётов на символ. Если ошибка вносимая интерполятором намного меньше чем ошибка вносимая шумом то ей можно пренебречь.

0


Вы здесь » DSPSYSTEM Теория и практика цифровой обработки сигналов » Алгоритмы и их программирование » передискретизация полиномами разной степени на основе фильтра Фарроу