реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Как сдвинуть все элементы массива на 1, Оптимизация этого процесса
azh
сообщение Dec 21 2007, 11:31
Сообщение #1


Участник
*

Группа: Новичок
Сообщений: 19
Регистрация: 17-05-07
Пользователь №: 27 781



Здравствуйте!

Кто-нибудь знает как можно оптимизировать сдвиг элементов массива на 1 (для Blackfin):
-------------------------------------------------------------------
void AddSample(short pBuffer[], short sValue, int nSize)
{
int i;
for (i = 1; i < nSize; i++)
{
pBuffer[nSize - i] = pBuffer[nSize - i - 1];
}
pBuffer[0] = sValue;
}
--------------------------------------------------------------------
Как-нибудь можно для этого использовать кольцевые буфферы или DMA память-память?
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 21 2007, 11:45
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



А может проще ничего не двигать, а лишь модифицировать указатель при обращении к массиву?
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 21 2007, 11:57
Сообщение #3


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(azh @ Dec 21 2007, 17:31) *
Кто-нибудь знает как можно оптимизировать сдвиг элементов массива на 1 (для Blackfin):
-------------------------------------------------------------------
void AddSample(short pBuffer[], short sValue, int nSize)
{
int i;
for (i = 1; i < nSize; i++)
{
pBuffer[nSize - i] = pBuffer[nSize - i - 1];
}
pBuffer[0] = sValue;
}
--------------------------------------------------------------------
Как-нибудь можно для этого использовать кольцевые буфферы или DMA память-память?

В этом процессоре (как и в любом приличном DSP) есть аппаратная поддержка кольцевых буферов, где требуемая функциональность реализуется аппаратно. Фтыкать доку на тему DAGs (Data Address Generators). Не уверен только, что требуемого результата можно добиться на ЯВУ, скорее всего придется реализовывать на асме.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
fontp
сообщение Dec 21 2007, 12:06
Сообщение #4


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(dxp @ Dec 21 2007, 14:57) *
В этом процессоре (как и в любом приличном DSP) есть аппаратная поддержка кольцевых буферов, где требуемая функциональность реализуется аппаратно. Фтыкать доку на тему DAGs (Data Address Generators). Не уверен только, что требуемого результата можно добиться на ЯВУ, скорее всего придется реализовывать на асме.


На С можно, используя библиотечную ф-ю circptr. Цитата и хелпа VDSP++ :

The following operation performs a circular buffer increment of a pointer.

void *circptr(void *ptr, long incr ,
void * base, unsigned long buflen);

Both incr and buflen are specified in bytes, since the operation deals in void pointers.

The operation is equivalent to:

ptr += incr;

if (ptr < base)

ptr += buflen;

else if (ptr >= (base+buflen))

ptr -= buflen;

An example of this built-in function is:

#include <ccblkfn.h>

void func(int *array, int n, int incr, int len)

{

int i, idx = 0;

int *ptr = array;


// scale increment and length by size

// of item pointed to.

incr *= sizeof(*ptr);

len *= sizeof(*ptr);


for (i = 0; i < n; i++) {

*ptr += incr;

ptr = circptr(ptr, incr, array, len);

}

}





--------------------------------------------------------------------------------
VisualDSP++ 5.0 C/C++
Compiler and Library Manual
for Blackfin Processors
Revision 5.0, August 2007
Go to the top of the page
 
+Quote Post
dtsar
сообщение Dec 21 2007, 18:16
Сообщение #5





Группа: Новичок
Сообщений: 11
Регистрация: 21-10-07
Пользователь №: 31 558



Цитата(azh @ Dec 21 2007, 14:31) *
Здравствуйте!

Кто-нибудь знает как можно оптимизировать сдвиг элементов массива на 1 (для Blackfin):
-------------------------------------------------------------------
void AddSample(short pBuffer[], short sValue, int nSize)
{
int i;
for (i = 1; i < nSize; i++)
{
pBuffer[nSize - i] = pBuffer[nSize - i - 1];
}
pBuffer[0] = sValue;
}
--------------------------------------------------------------------
Как-нибудь можно для этого использовать кольцевые буфферы или DMA память-память?


не совсем понятно для чего так делать.
я думаю что проще всего - ничего не сдвигать, а написатьчтение из массива на асме с кольцевым буфером.
дма тут - изврат. хотя, смотря сколько данных.
Go to the top of the page
 
+Quote Post
azh
сообщение Dec 21 2007, 18:40
Сообщение #6


Участник
*

Группа: Новичок
Сообщений: 19
Регистрация: 17-05-07
Пользователь №: 27 781



Спасибо за ответы!

В help к VDSP++ написано, что можно использовать функцию circindex(), чтобы компилятор "сказал", что этот массив нужно поместить в кольцевой буффер, но как выяснилось такой код работает в почти в 1,5 раза медленнее, чем представленный ранее. С чем это может быть связано?
Ниже приведен код с функцией circindex().
--------------------------------------------------
void AddSampleA(short pBuffer[], short sValue, int nSize)
{
int i;
short nIndex = 0;

for (i = 0; i < nSize; i++)
{
pBuffer[nSize - nIndex] = pBuffer[nSize - nIndex - 1];
nIndex = circindex(nIndex, 1, FFT_SIZE);
}
pBuffer[0] = sValue;
}
--------------------------------------------------
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 21 2007, 22:37
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



А зачем вообще нужно сдвигать буфер? Почему нельзя его оставить как есть и для извлечения значений буфера ограничится всего лишь вызовом подобной функции?
Код
short GetBufVal(short *pBuffer, unsigned idx, unsigned nSize)
{ if (idx<nSize) return(*(short *)(pBuffer+idx));
  else return(*(short *)(pBuffer+(nSize-idx)));
}
Go to the top of the page
 
+Quote Post
shasik
сообщение Dec 22 2007, 06:20
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 319
Регистрация: 3-09-05
Из: Беларусь, Новополоцк
Пользователь №: 8 188



Цитата(rezident @ Dec 22 2007, 00:37) *
А зачем вообще нужно сдвигать буфер? Почему нельзя его оставить как есть и для извлечения значений буфера ограничится всего лишь вызовом подобной функции?
Код
short GetBufVal(short *pBuffer, unsigned idx, unsigned nSize)
{ if (idx<nSize) return(*(short *)(pBuffer+idx));
  else return(*(short *)(pBuffer+(nSize-idx)));
}


Абсолютно согласен. Использовать "навороченные" программы для данной задачи явно лишнее. Лучше работать с указателями. Пусть N - длина массива, begin - его начало, тогда элемент будем брать по адресу (i+begin) mod N, т.е. то же что предложил rezident. Просто если длина массива является степенью двойки, то алгоритм rezident'а можно оптимизировать - использовать операцию логического &. Все работает шустро и очень даже красиво. Думаю понятно, что в этом случае сдвиг масиива на k элементов выглядит как begin += k.
Go to the top of the page
 
+Quote Post
fontp
сообщение Dec 22 2007, 10:26
Сообщение #9


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(azh @ Dec 21 2007, 21:40) *
Спасибо за ответы!

В help к VDSP++ написано, что можно использовать функцию circindex(), чтобы компилятор "сказал", что этот массив нужно поместить в кольцевой буффер, но как выяснилось такой код работает в почти в 1,5 раза медленнее, чем представленный ранее. С чем это может быть связано?
Ниже приведен код с функцией circindex().
--------------------------------------------------
void AddSampleA(short pBuffer[], short sValue, int nSize)
{
int i;
short nIndex = 0;

for (i = 0; i < nSize; i++)
{
pBuffer[nSize - nIndex] = pBuffer[nSize - nIndex - 1];
nIndex = circindex(nIndex, 1, FFT_SIZE);
}
pBuffer[0] = sValue;
}


--------------------------------------------------


Вообще-то линии задержки (для фильтрации и прочее) строятся не так. Никакого цикла для сдвига не должно быть. Положение последнего отсчёта в кольцевом буфере сдвигается при каждом обращении к "функции" и этот указатель возвращается (на самом деле для эффективности никакой функции не должно быть или она должна быть как минимум за-инлайнена). Вам не нужно сдвигать весь буфер в памяти, вместо этого сдвигается адрес начала (последнего во времени отсчёта) буфера

Для примера - fir фильтр делается как-то так

int16 BufBase[N];
int16 *BufPtr=BufBase;
static int16 FIR(int16 *H, int16 *BufBase, int N)
{
int i;
register int16 *bp = BufPtr;
register int16 *hp = H;
register int32 sumFIR;

sumFIR = 0;
for (i = 0; i < N; i++) {
sumFIR = L_mac(sumFIR,*bp,*hp++);
bp= (int16 *) circptr(bp, +2, BufBase, 2*N);
}
sumFIR = sature(sumFIR >> 16);
BufPtr = bp;
return sumFIR;
}


По циклу входных данных выполняется

*BufPtr = DataIn;
BufPtr=circptr(BufPtr, +2, BufBase, 2*N);
DataOut=FIR(H, BufBase, N);

Здесь нет двойного цикла, связанного со сдвигом буфера задержки. Единственный цикл выполняет фильтрацию. Аналогично и с circindex

Кроме того должна быть включена оптимизация, иначе кольцевые буферы не используются функциями circindex и circptr
Go to the top of the page
 
+Quote Post
azh
сообщение Dec 22 2007, 11:19
Сообщение #10


Участник
*

Группа: Новичок
Сообщений: 19
Регистрация: 17-05-07
Пользователь №: 27 781



На самом деле, сдвиг всех элементов массива это только часть задачи (извиняюсь, что не сказал об этом сразу). Вся задача выглядит так:
1. Добавить очередной отчет с АЦП в буффер (на место первого элемента буффера, при этом все остальные элементы сдвинуть на 1, и последний "вытолкнуть" из буффера)
2. Посчитать ДПФ для этого буффера

Относительно оптимизации, почему-то время выполнения остается тем же самым (+0.01%), даже если использовать функцию circptr() и включить оптимизацию.
Go to the top of the page
 
+Quote Post
fontp
сообщение Dec 22 2007, 12:52
Сообщение #11


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(azh @ Dec 22 2007, 14:19) *
На самом деле, сдвиг всех элементов массива это только часть задачи (извиняюсь, что не сказал об этом сразу). Вся задача выглядит так:
1. Добавить очередной отчет с АЦП в буффер (на место первого элемента буффера, при этом все остальные элементы сдвинуть на 1, и последний "вытолкнуть" из буффера)
2. Посчитать ДПФ для этого буффера

Относительно оптимизации, почему-то время выполнения остается тем же самым (+0.01%), даже если использовать функцию circptr() и включить оптимизацию.



Ещё раз, у Вас неверная парадигма. Т.е. Вы смотрите на сдвиг с неверной стороны.

Правильная парадигма состоит в том, что Вы не двигаете отсчёты в памяти, а двигете их в мозгу.
При этом, с точки зрения последующей обработки (ДПФ), буфер не начинается с первого элемента массива, а начинается с некоторого, смещающегося на 1 на каждом такте обработки. Буфер для последующей обработки тогда должен иметь кольцевую адресацию. Но за то Вы не тратите время на сдвиг

Для эффективной реализации этой парадигмы и существуют кольцевые буфера. ДПФ ничего не меняет, если Вы его реализуете сами.

Если же у Вас блочная процедура ДПФ готовая, например из стандартной библиотеки, то кольцевые буфера Вам не помогут - там (в чужой библиотечной процедуре) не реализована кольцевая адресация. Кроме того, если у Вас ДПФ не для одной частоты, то время сдвига всё равно очень мало по сравнению с временем выполнения ДПФ и можно делать тупо в лоб, сдвигая элементы в памяти. Но в этом случае никакие кольцевые буфера Вам не помогут
Go to the top of the page
 
+Quote Post
azh
сообщение Dec 22 2007, 13:58
Сообщение #12


Участник
*

Группа: Новичок
Сообщений: 19
Регистрация: 17-05-07
Пользователь №: 27 781



Большое спасибо за разъяснения! Действительно, мне сначала следовало разобраться для чего нужны кольцевые буфферы
Go to the top of the page
 
+Quote Post
vadkudr
сообщение Jan 5 2008, 04:48
Сообщение #13


Участник
*

Группа: Новичок
Сообщений: 26
Регистрация: 20-11-07
Пользователь №: 32 502



Осталось добавить, что ДПФ сдвинутой по кольцу последовательности равен ДПФ несдвинутой умноженной на exp(-j*2*pi/N*n*k)
k - пробегает 0..N-1
n - величина сдвига
N - длина последовательности
:-)
Go to the top of the page
 
+Quote Post
Николай Z
сообщение Jan 5 2008, 08:32
Сообщение #14


Местный
***

Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930



Цитата(dxp @ Dec 21 2007, 14:57) *
Не уверен только, что требуемого результата можно добиться на ЯВУ, скорее всего придется реализовывать на асме.

Вы видимо ярый ненавистник ЯВУ... biggrin.gif
На самом деле все что можно написать на ассемблере - можно написать и на любом ЯВУ причем совершенно необязательно с потерей эффективности, но зато намного структурнее и понятнее.


Цитата(vadkudr @ Jan 5 2008, 07:48) *
Осталось добавить, что ДПФ сдвинутой по кольцу последовательности равен ДПФ несдвинутой умноженной на exp(-j*2*pi/N*n*k)
k - пробегает 0..N-1
n - величина сдвига
N - длина последовательности
:-)

Вы незаметили что у товарища вовсе не сдвиг по кольцу,
а вот что:
Цитата(azh @ Dec 22 2007, 14:19) *
Вся задача выглядит так:
1. Добавить очередной отчет с АЦП в буффер (на место первого элемента буффера, при этом все остальные элементы сдвинуть на 1, и последний "вытолкнуть" из буффера)
2. Посчитать ДПФ для этого буффера

и после каждого сдвига и добавления вся последовательность изменяется.

Сообщение отредактировал Николай Z - Jan 5 2008, 08:35
Go to the top of the page
 
+Quote Post
dxp
сообщение Jan 5 2008, 10:11
Сообщение #15


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(Николай Z @ Jan 5 2008, 14:32) *
Вы видимо ярый ненавистник ЯВУ... biggrin.gif

Сия фраза ясно указывает, что либо: 1) вы ничего про меня не знаете; 2) вы просто провокатор. Второе с вероятностью 0.99. Впрочем, все уже знают, что это у вас работа такая. Меня зацепить не удастся, т.ч. направляйте усилия на более наивных участников. biggrin.gif

Цитата(Николай Z @ Jan 5 2008, 14:32) *
На самом деле все что можно написать на ассемблере - можно написать и на любом ЯВУ причем совершенно необязательно с потерей эффективности, но зато намного структурнее и понятнее.

Написана очевидная глупость. На самом деле на некоторых ЯВУ (как правило С/C++) можно иногда написать без потери эффективности по сравнению с асмом, но достигается это в подавляющем большинстве случаев за счет специальных непереносимых расширений конкретного ЯВУ в части конкретной платформы. Могу с легостью привести пример для того же Blackfin'а, где асм даст преимущество ЯВУ, но не буду этого делать - вступать в спор с виртуалами куда бОльшая глупость, нежели вышеотквоченная фраза. biggrin.gif Т.ч. цепляйте кого-нить другого. счастливо оставаться.

P.S. Можете и дальше (это уже второй случай) искать мои старые посты и пытаться меня вытащить на дискуссию, но сразу предупреждаю, этого вам не удастся. Меняйте тактику. wink.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 15th June 2025 - 15:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01517 секунд с 7
ELECTRONIX ©2004-2016