Jump to content

    

DDS генератор

Recommended Posts

jcxz
1 минуту назад, andyp сказал:

Угу. Что там со стабильностью у такого генератора? Слыхал, что у него полюса прямиком на единичной окружности ;)

Чтобы не накапливались ошибки, достаточно каждые N сэмплов делать перезапуск, вычисляя 2 сэмпла традиционно - через sin().

Share this post


Link to post
Share on other sites

andyp
46 minutes ago, jcxz said:

Чтобы не накапливались ошибки, достаточно каждые N сэмплов делать перезапуск, вычисляя 2 сэмпла традиционно - через sin().

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

Edited by andyp

Share this post


Link to post
Share on other sites

FatRobot

Вы могли бы прикинуть SFDR для такого решения?

Для сравнения: NCO с таблицей из 2K float и линейной интерполяцией имеет SFDR > 150dB

 

image.thumb.png.2aa900037b92256e60a48fa3716aa9a7.png

1 hour ago, jcxz said:

Чтобы не накапливались ошибки, достаточно каждые N сэмплов делать перезапуск, вычисляя 2 сэмпла традиционно - через sin().

Share this post


Link to post
Share on other sites

Allregia
5 hours ago, jcxz said:

(PI / 0x80000000u) - это выражение уже считается компилятором в double с соответствующей точностью, и только результат конвертируется в float.

Я про это и сказал, что "если считается в компайл-тайм"

 

 

5 hours ago, jcxz said:

Элементарно же!  :hi:

ОК, спасибо, попробую.

 

3 hours ago, andyp said:

Тем более, что таблица залетает в кеш.

У меня не залетает, во 1-х ввиду своего размера (оно  вообще в ОЗУ не лезет, поэтому из феша, если не считать синус на ходу), во 2-х - ввиду отсусттвия кеша как такового.

Share this post


Link to post
Share on other sites

andyp
27 minutes ago, Allregia said:

У меня не залетает, во 1-х ввиду своего размера (оно  вообще в ОЗУ не лезет, поэтому из феша, если не считать синус на ходу), во 2-х - ввиду отсусттвия кеша как такового.

Ну ОК, что уж. Вообще генераторы на биквадах часто приходится стабилизировать по крайней мере по амплитуде, что по мне, так такое себе удовольствие. В моих приложениях мне такое даром не надо. Хочу, чтобы DDFSка делала мне синус нужного качества без сюрпризов на протяжении многих отсчетов.

Share this post


Link to post
Share on other sites

Allregia
1 minute ago, andyp said:

Хочу, чтобы DDFSка делала мне синус нужного качества без сюрпризов на протяжении многих отсчетов.

Аналогично :)

Я пробовал с таблицей, расчитанной в дабл флоат, резулььтат аналогичный.

Share this post


Link to post
Share on other sites

andyp
4 minutes ago, Allregia said:

Аналогично :)

Я пробовал с таблицей, расчитанной в дабл флоат, резулььтат аналогичный.

Ну конечно, это ж в общем случае работает. Я ж предупредил о marginal stability, больше не смею мешать.

Share this post


Link to post
Share on other sites

Allregia
3 minutes ago, andyp said:

Ну конечно, это ж в общем случае работает.

Я понимаю что работает, это далеко не первый мой программный DDS, но я раньше не генерировал частот, приближающихся к Fs/2.

И очень интереснол, как-же сделали в ARTA, что у них алиас намного меньшей амплитуды?

 

Share this post


Link to post
Share on other sites

andyp

Не очень понимаю, о чём разговор. Амплитудный спектр синуса - всегда две палки, симметричных относительно 0 .  С учётом периодичности спектра дискретного сигнала, компонент  окажется на частоте Fs-Fg. Fg - та частота, которую генерируете. Fs - частота дискретизации.

Share this post


Link to post
Share on other sites

GenaSPB

typedef uint32_t ncoftw_t;
typedef int32_t ncoftwi_t;
#define NCOFTWBITS 32	// количество битов в ncoftw_t
#define FTWROUND(ftw) ((uint32_t) (ftw))
#define FTWAF001(freq) (((int_fast64_t) (freq) << NCOFTWBITS) / ARMI2SRATE100)
#define FTWAF(freq) (((int_fast64_t) (freq) << NCOFTWBITS) / ARMI2SRATE)
static FLOAT_t omega2ftw_k1; // = POWF(2, NCOFTWBITS);
#define OMEGA2FTWI(angle) ((ncoftwi_t) ((FLOAT_t) (angle) * omega2ftw_k1 / (FLOAT_t) M_TWOPI))	// angle in radians -pi..+pi to signed version of ftw_t

// Convert ncoftw_t to q31 argument for arm_sin_cos_q31
// The Q31 input value is in the range [-1 0.999999] and is mapped to a degree value in the range [-180 179].
#define FTW2_SINCOS_Q31(angle) ((ncoftwi_t) (angle))
// Convert ncoftw_t to q31 argument for arm_sin_q31
// The Q31 input value is in the range [0 +0.9999] and is mapped to a radian value in the range [0 2*PI).
#define FTW2_COS_Q31(angle) ((q31_t) ((((ncoftw_t) (angle)) + 0x80000000uL) / 2))
#define FAST_Q31_2_FLOAT(val) ((q31_t) (val) / (FLOAT_t) 2147483648)


static RAMFUNC FLOAT_t getsinf(ncoftw_t angle)
{
	FLOAT_t v;
	const q31_t sinv = arm_sin_q31(FTW2_COS_Q31(angle));
	//v = FAST_Q31_2_FLOAT(sinv);	// todo: use arm_q31_to_float
	arm_q31_to_float(& sinv, & v, 1);
	return v;
}

static RAMFUNC FLOAT_t getcosf(ncoftw_t angle)
{
	FLOAT_t v;
	const q31_t cosv = arm_cos_q31(FTW2_COS_Q31(angle));
	//v = FAST_Q31_2_FLOAT(cosv);	// todo: use arm_q31_to_float
	arm_q31_to_float(& cosv, & v, 1);
	return v;
}

static RAMFUNC FLOAT32P_t getsincosf(ncoftw_t angle)
{
	FLOAT32P_t v;
	q31_t sincosv [2];
#if 1
	sincosv [0] = arm_sin_q31(FTW2_COS_Q31(angle));
	sincosv [1] = arm_cos_q31(FTW2_COS_Q31(angle));
#else
	arm_sin_cos_q31(FTW2_SINCOS_Q31(angle), & sincosv [0], & sincosv [1]);
	// at index 0 all fine
	// at index 1 with sidetones
#endif
	arm_q31_to_float(sincosv, v.ivqv, 2);
	return v;
}


static RAMDTCM ncoftw_t anglestep_lout2 = FTWAF(5600), anglestep_rout2 = FTWAF(6300);
static RAMDTCM ncoftw_t angle_lout2, angle_rout2;

static int get_lout24(void)
{
	// Формирование значения для LOUT
	//const int v = arm_sin_q31(angle_lout2 / 2) / 256;
	const int v = getcosf(angle_lout2) * INT24_MAX;
	angle_lout2 = FTWROUND(angle_lout2 + anglestep_lout2);
	return v;
}

После перехода с таблицы 90 градусов из 16385 float без апроксимации на CMSIS DSP спектр стал лучше

Edited by GenaSPB

Share this post


Link to post
Share on other sites

jcxz
8 часов назад, FatRobot сказал:

Вы могли бы прикинуть SFDR для такого решения?

Я практически не реализовывал его - не было надобности. Но вроде как если синус первых 2-х шагов рассчитан с достаточно большой точностью, то не ошибка не должна быстро накапливаться.

5 часов назад, Allregia сказал:

У меня не залетает, во 1-х ввиду своего размера (оно  вообще в ОЗУ не лезет, поэтому из феша, если не считать синус на ходу), во 2-х - ввиду отсусттвия кеша как такового.

А что у Вас за МК? Я из контекста понял, что Cortex-M4. Но разве они бывают без кеша?

Share this post


Link to post
Share on other sites

Allregia
4 hours ago, jcxz said:

Я практически не реализовывал его - не было надобности. Но вроде как если синус первых 2-х шагов рассчитан с достаточно большой точностью, то не ошибка не должна быстро накапливаться.

А что у Вас за МК? Я из контекста понял, что Cortex-M4. Но разве они бывают без кеша?

STM32F427

8 hours ago, andyp said:

Не очень понимаю, о чём разговор. Амплитудный спектр синуса - всегда две палки, симметричных относительно 0 .  С учётом периодичности спектра дискретного сигнала, компонент  окажется на частоте Fs-Fg. Fg - та частота, которую генерируете. Fs - частота дискретизации.

Это в теории, а на практике - имеем два DDS генератора, работающие на те-же ЦАП/АЦП. Оба генерируют 20кгц при 48кгц семплирования.

Оба дают алиас на 28кгц, но у первого он -90дб а у моего -20. Я тоже хочу -90, меня бы это вполне устроило.

 

Share this post


Link to post
Share on other sites

FatRobot

Скажите, какая у вас схема измерений, что при частоте отсчетов 48ksps вы видите что-то на 28kHz? Скорее всего у вас что-то с фильтром после ЦАП

11 hours ago, Allregia said:

Оба дают алиас на 28кгц, но у первого он -90дб а у моего -20. Я тоже хочу -90, меня бы это вполне устроило.

Ясно-понятно.

16 hours ago, jcxz said:

Я практически не реализовывал его - не было надобности. Но вроде как [...] с достаточно большой [...]  не должна [...]

Share this post


Link to post
Share on other sites

Allregia
3 minutes ago, FatRobot said:

Скажите, а как при частоте отсчетов 48ksps вы видите что-то на 28kHz?

Ясно-понятно.

См. выше - 48ksps это частота DDS+DAC, оцифровывается это потом АЦП на 96 или 192, потому 28 и видно :)

 

Share this post


Link to post
Share on other sites

FatRobot

фильтр после цап присутствует?

1 minute ago, Allregia said:

См. выше - 48ksps это частота DDS+DAC, оцифровывается это потом АЦП на 96 или 192, потому 28 и видно :)

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.