User Tag List

Показано с 1 по 10 из 155

Тема: Генерация синуса

Древовидный режим

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #11

    Регистрация
    08.10.2005
    Адрес
    Москва
    Сообщений
    14,380
    Спасибо Благодарностей отдано 
    1,698
    Спасибо Благодарностей получено 
    2,217
    Поблагодарили
    871 сообщений
    Mentioned
    69 Post(s)
    Tagged
    1 Thread(s)

    По умолчанию Отгадка

    Ладно, раз всем лениво, раскрою алгоритм, который весьма прост)

    В данном случае используется алгоритм генерации синуса посредством рекурсивного цифрового генератора (о чем упоминалось даже в этой теме неоднократно). Многим он больше знаком по алгоритму Герцеля:

    D0 = a1 * D1 - D2 + x,
    D2 = D1,
    D1 = D0,

    который является модификацией данного генератора с добавленным возбуждением коэффициентом x. А сам генератор в чистом виде - это:

    D0 = a1 * D1 - D2,
    D2 = D1,
    D1 = D0,
    где a1 = 2 * cos (2 * pi * частота / частота_отсчетов),
    или же a1 = 2 * cos (2 * pi * k);

    Ввиду того, что алгоритм рекурсивный, требуется большая точность (разрядность) чисел. Приемлимой точности даже 16 битами (не говоря уже о 8) на отрезке в пару сот итераций не добиться. Поэтому выбрана разрядность 24 бита.

    Далее о коэффициенте a1. Понятно, что ни о каком умножении речи быть не может. Единственный вариант - представить a1 в виде достаточно простого полинома вида 2 * (2^0 + 2^(...) + 2^(...) + ...) и т.д.
    Самым простым полиномом, удовлетворяющим периоду близкому к 256, и при этом имеющим близкий к целому числу корень 1/k - это полином 2 * (2^0 - 2^(-11)), что легко представлятся в виде сдвига вправо на 8 + 3 бит, и одного вычетания. Что я и изобразил в своем алгоритме.

    Посчитаем 1/k (число отсчетов) для данного полинома.

    a1 = 2 * (1 - 2^(-11)) = 1,9990234375

    1 / k = 1 / (arccos(a1 / 2) / (2 * pi) = 201.0536,

    что является достаточно точным, близким к целочисленному периодом.

    Если кого интересует полином для периода 256, то я тоже прикидывал его, у меня получился 2 * (2^0 - 2^(-12) - 2^(-14) + 2^(-18)), что потребует уже целых 3 сдвига и 3 сложения, усложняя код, ведь это все надо в 24-х битной арифметике сдвигать и складывать (ну, младшие части полинома можно и в 16, и даже в 12-битной).

    Посчитаем 1/k (число отсчетов) для данного полинома:

    a1 = 2 * (1 - 2^(-12) - 2^(-14) + 2^(-18)) = 1,99939727783203125

    1 / k = 1 / (arccos(a1 / 2) / (2 * pi) = 255.92,

    что уже менее точно, но все же достаточно приемлимо.

    Вот вышеприведенный уже код, но с комментариями:

    Код:
    	org	$8000
    
    	LD	B,201		; Длина таблицы синуса 201 байт
    	LD	HL,$8100	; Адрес таблицы синуса
    	EXX			;
    	
    	XOR	A		; D0/D1 = $00.00.00
    	LD	H,A		;
    	LD	L,A		;
    	
    	PUSH	HL		; D2 = -$02.00.00
            LD      IXL,-2          ;
    	
    	JR	LoopIn		; --> LoopIn
    	
    ;------------------------------- Главный цикл
    MLoop:	
    	EXX			;
    	
    	SBC	HL,BC		; A.H.L = A.H.L - LX.B.C
    	SBC	A,IXL		; (D0 = a1*D1 - D2)
    
            LD      IXL,D            ; Сохранить LX для D2 будущей итерации
    
    ;-------------------------------
    LoopIn:				
    				; D0/D1 = A.H.L
    				
    	LD	D,A		; D = A (и заодно сохранить A)
    	ADD	A,A		;
    	SBC	A,A		;
    	LD	IXH,A		; A = $00/$FF, в зависимости от знака
    	LD	A,D		; Восстановить A
    	LD	E,H		;
            LD      B,3             ; DE = (A.H.L >> 8) >> 3 = A.H.L >> 11
    RLoop:	SRA	D		;     
    	RR	E		;
    	DJNZ	RLoop		;
    	
    	POP	BC		; Восстановить D2 = LX.B.C
    	PUSH	HL		; Сохранить D1 = (A).H.L
    	
    	SBC	HL,DE		; A.H.L = A.H.L - HX.D.E 
            LD      D,A             ;
    	SBC	A,IXH		;
    	
    	ADD	HL,HL		; A.H.L = A.H.L << 1
    	ADC	A,A		; (D0 = a1 * D1)
    	
    	EXX			; Сохранить A в (HL)+
    	LD	(HL),A		; и цикл
    	INC	L		;
    	DJNZ	MLoop		;
    	
            POP     AF              ; Восстановить стек
           
    	RET			; Выход


    ---------- Post added at 15:21 ---------- Previous post was at 15:19 ----------

    Да, начальная амплитуда задается через коэффициент в D2 со знаком минус.
    Последний раз редактировалось Titus; 02.12.2013 в 15:28.

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. Качение синуса
    от Hacker VBI в разделе Программирование
    Ответов: 38
    Последнее: 08.04.2013, 00:40
  2. Генерация лабиринтов
    от TomCaT в разделе Программирование
    Ответов: 90
    Последнее: 26.06.2012, 10:59
  3. День рождения Синуса!
    от valeron в разделе Поздравления
    Ответов: 9
    Последнее: 19.05.2010, 15:31
  4. Генерация матрицы клавиатуры
    от AlexCrush в разделе Программирование
    Ответов: 5
    Последнее: 23.01.2007, 15:32

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •