Перейти к содержанию
    

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

46 minutes ago, jcxz said:

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

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

Изменено пользователем andyp

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

image.thumb.png.2aa900037b92256e60a48fa3716aa9a7.png

1 hour ago, jcxz said:

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 hours ago, jcxz said:

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

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

 

 

5 hours ago, jcxz said:

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

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

 

3 hours ago, andyp said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, Allregia said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, andyp said:

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, Allregia said:

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, andyp said:

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты


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 спектр стал лучше

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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, меня бы это вполне устроило.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

11 hours ago, Allregia said:

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

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

16 hours ago, jcxz said:

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, FatRobot said:

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

1 minute ago, Allregia said:

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...