Ладно, раз всем лениво, раскрою алгоритм, который весьма прост)
В данном случае используется алгоритм генерации синуса посредством рекурсивного цифрового генератора (о чем упоминалось даже в этой теме неоднократно). Многим он больше знаком по алгоритму Герцеля:
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 со знаком минус.




Ответить с цитированием