Пошук поліноміальних наближень синусоїди


16

Я хочу наблизити синусоїду, задану , застосувавши поліномальний хвилевідник до простої хвилі трикутника , породженої функцієюsin(πx)

T(x)=14|12mod(12x+14, 1)|

де - дробова частина :mod(x,1)x

mod(x,y)y(xyxy)

Серія Тейлора може бути використана як хвильовий формувач.

S1(x)=πx2πx233!+πx255!πx277!

З огляду на наведені вище функції, S1(T(x)) отримає нам гідне наближення синусоїди. Але нам потрібно підійти до 7-ї потужності серії, щоб отримати розумний результат, а вершини трохи низькі і не матимуть нахилу рівно нуля.

Замість серії Тейлора ми могли б використовувати багаточлен хвилевідбивача, дотримуючись кількох правил.

  • Повинен пройти через -1, -1 та + 1, + 1.
  • Нахил у -1, -1 та + 1, + 1 повинен бути нульовим.
  • Повинно бути симетричним.

Проста функція, що відповідає нашим вимогам:

S2(x)=3x2x32

Графіки S2(T(x)) і sin(πx) досить близькі, але не такі близькі, як ряд Тейлора. Між піками та нульовими переходами вони помітно відхиляються. Більш важка і точна функція, що відповідає нашим вимогам:

S3(x)=x(x25)216

Це, мабуть, досить близько для моїх цілей, але мені залишається цікаво, чи існує інша функція, яка ближче наближає синусоїду і чисельно обчислює. Я досить добре розумію, як знайти функції, що відповідають трьом вищезазначеним вимогам, але я не впевнений, як іти на пошук функцій, які відповідають цим вимогам, а також найбільше відповідають синусоїді.

Які існують методи пошуку многочленів, які імітують синусоїду (коли застосовуються до трикутної хвилі)?


Для уточнення я не обов'язково шукаю лише непарно-симетричні поліноми, хоча це найбільш простий вибір.

Щось на зразок наступної функції також може відповідати моїм потребам:

S4(x)=3x2+x24+x44

Це відповідає вимогам в негативному діапазоні, і кусочне рішення може бути використане і для його застосування до позитивного діапазону; наприклад

3x2P(x,2)4P(x,4)4

де - підписана функція живлення .P

Мені також були б цікаві рішення, які використовують підписану функцію живлення для підтримки показників дробу, оскільки це дає нам ще одну «ручку для скручування», не додаючи іншого коефіцієнта.

a0x +a1P(x, p1)

Враховуючи правильні константи, це може отримати дуже гарну точність без важкості поліномів п’ятого чи сьомого порядку. Ось приклад виконання вимог, описаних тут, використовуючи деякі вибрані вручну константи: .a0=1.666¯,a1=0.666¯,p1=2.5

5x2P(x, 52)3

Насправді ці константи дуже близькі до , а , і . Підключення до них дає щось, що виглядає надзвичайно близько до синусоїди. 1-ππ2 е1π2e

π2x +(1π2)P(x,e)

Інакше кажучи, дуже близький до між 0,0 та π / 2,1. Будь-які думки про значення цього? Можливо, такий інструмент, як Octave, може допомогти виявити "найкращі" константи для цього підходу. гріх(х)xxe6sin(x)


1
Отже, яке ваше визначення терміна помилки для "ближче"? Наскільки я міг сказати, цитована серія Тейлора - це мінімальна помилка L², приблизна для кінцевого числа коефіцієнтів. (Я думаю.)
Маркус Мюллер

2
Яка, до речі, ваша мета? Насправді це може допомогти нам сказати, чому ви шукаєте формувач поліноміальних хвиль, на якій технологічній основі та які ваші основні цілі для наближення.
Маркус Мюллер

@ MarcusMüller Я готовий пожертвувати точністю серії Тейлора за щось значно дешевше, якщо це не відрізняється від синусоїди до людського вуха. Піки наближення серії Тейлора також мене турбують. Мені цікаво знайти щось "більш близьке", ніж інші дві функції, які я перерахував. Я підозрюю, що це не буде дешевше, ніж . S2
Гість

1
"Для людського вуха" тут критично :) Чому вершини "турбують" вас? Знову ж таки: дайте нам уявлення, чому / з якою метою та за яких обмежень ви це робите. Без достатнього тла ваше запитання просто занадто широке, щоб правильно відповісти!
Маркус Мюллер

1
Чому ви починаєте з трикутної хвилі? Синусогенератори прості і поширені, квадратні хвилі тривіально фільтруються до основної гармоніки тощо
Карл Віттофт

Відповіді:


10

близько десяти років тому я зробив це для неназваної компанії синтезатора музики, яка займалася науково-дослідною роботою недалеко від мого кондо у штаті Уолтем МА. (Не уявляю, хто вони.) У мене немає коефіцієнтів.

але спробуйте це:

f(x)sin(π2x)for 1x+1=π2x(a0+a1x2+a2x4)

це гарантує, що .f(x)=f(x)

Щоб гарантувати, що тодіf(x)|x=±1=0

f(x)=π2(a0+3a1x2+5a2x4)

(1)a0+3a1+5a2=0

Це перше обмеження. Щоб гарантувати, що , то|f(±1)|=1

(2)a0+a1+a2=2π

Це друге обмеження. Усунення та розв’язування рівнянь (1) і (2) для в частині (що залишається для регулювання):a 2 a 1a0a2a1

a0=52π12a1

a2=12π12a1

Тепер у вас є лише один коефіцієнт, , для кращої продуктивності:a1

f(x)=π2x((52π12a1)+a1x2(12π+12a1)x4)

Ось так я би змайстрував для найкращої роботи синусоїдального осцилятора. Я б налаштував використання вищевказаного та симетрію синусоїди приблизно і помістив рівно один цикл у буфер потужністю в дві кількості точок (скажімо, 128 мені не байдуже) і запустити FFT на цьому ідеальний цикл. x = 1a1x=1

Коробка результатів FFT 1 буде силою синуса і повинна становити приблизно . Тепер ви можете налаштувати щоб привести ваше третє гармонічне спотворення вгору та вниз. Я б почав з так що . Це в біні 3 результатів FFT. Але 5-те гармонічне спотворення (значення в кошику 5) буде наслідковим (воно піде вгору, коли третя гармоніка знизиться). Я налаштував би так, щоб сила 5-го рівня гармоніки дорівнювала 3-му рівню гармоній. Це буде приблизно -70 дБ від 1-ї гармоніки (наскільки я пам’ятаю). Це буде найприємніша звукова синусоїда з дешевого, 3-коефіцієнтного, п'ятого порядку, непарного симетричного многочлена.a 1 a 15N/2a1a01a1a15π2a01a1

Хтось ще може написати код MATLAB. Як це звучить для вас?


я точно не встигну зробити MATLABing для полювання на оптимальне щоб третя гармоніка дорівнювала 5-й гармоніці, приблизно на 70 дБ нижче основної (1-а гармоніка). комусь потрібно це зробити. вибачте. a1
Роберт Брістоу-Джонсон

Чудова відповідь, все ж перетравлюючи її. Насправді починаю цікавитись, чи потрібно це бути 3-коефіцієнтом, 5-го порядку, непарно-симетричним многочленом ... Чи може ваш f '(x) насправді бути f (x) і бути розрізненим навколо 0? Приблизний ескіз тут . Може, це має на увазі Сед? Ви все ще наздоганяєте, хлопці.
Гість

Це прекрасний підхід. Цікаво , якщо замість того , щоб брати FFT і рішення итеративно можна сформувати третього і п'ятого порядку Чебишева многочлени від вашого , то прирівнюють два і вирішити для більш 1 ? f(x)a1
Швидкий

Повинно бути, наполовину спала , коли я писав , що «ескіз» Я хотів зробити що - щось на зразок цього , але виправив пробігти ± 1 і мають нульовий нахил (можна просто взяти похідну, возитися з ним, інтегрувати його знову). Не впевнений, чи є якась перевага над п'ятим порядком, просто щось, що я ще не розглядав.
Гість

1
Це справді геніальне рішення, просто зайнявшись час, щоб зануритися. Я сподіваюся, що позначення його правильним не перешкодить комусь іншим прийти і написати код.
Гість

9

Зазвичай робиться наближення, що мінімізує деяку норму помилки, часто -норму (де максимальна помилка мінімізована) або L 2 -норму (де середня квадратична помилка мінімізована). L ∞- апроксимація проводиться за допомогою алгоритму обміну Remez . Я впевнений, що ви можете знайти якийсь відкритий код, що реалізує цей алгоритм. Однак у цьому випадку я думаю, що досить простої (дискретної) l 2 -оптимізації достатньо. Давайте розглянемо деякий код Matlab / Octave та його результати:LL2Ll2

x = область простору (0, pi / 2300); % сітки на [0, пі / 2]
x = x (:);
% перевизначена система лінійних рівнянь
% (лише з використанням непарних повноважень)
A3 = [x, x. ^ 3];
A5 = [x, x. ^ 3, x. ^ 5];
b = sin (x);
% розв’язати в сенсі l2
c3 = A3 \ b;
c5 = A5 \ b;
f3 = A3 * c3; % Наближення 3-го порядку
f5 = A5 * c5; % Наближення 5-го порядку

На наведеному нижче малюнку показані помилки апроксимації для -порядок і за 5 т ч -им узагальненим наближень. Максимальні похибки наближення складають і , відповідно.3rd5th8.8869e-031.5519e-04

введіть тут опис зображення

Оптимальні коефіцієнти є

c3 =
   0,988720369237930
  -0.144993929056091

і

c5 =
   0,99976918199047515
  -0.16582163562776930
   0,00757183954143367

Отже, наближення третього порядку

(1)sin(x)0.988720369237930x0.144993929056091x3,x[π/2,π/2]

а наближення п’ятого порядку -

(2)sin(x)0.99976918199047515x0.16582163562776930x3+0.00757183954143367x5,x[π/2,π/2]

Редагувати:

Я вивчив наближення з підписаною функцією живлення, як це запропоновано у питанні, але найкраще наближення навряд чи краще, ніж наближення третього порядку, показане вище. Функція наближення є

(3)f(x)=x1p(π2)1pxp,x[0,π/2]

де константи були обрані такими, що і f ( π / 2 ) = 0 . Потужність p була оптимізована для досягнення найменшої максимальної похибки в діапазоні [ 0 , π / 2 ] . Оптимальним значенням p було встановлено p = 2.774 . На малюнку нижче показані помилки наближення для наближення третього порядку ( 1 ) та для нового наближення ( 3f(0)=1f(π/2)=0p[0,π/2]pp=2.774(1) :(3)

enter image description here

Максимальна похибка апроксимації апроксимації є , але зауважте, що наближення третього порядку лише перевищує ту помилку, близьку до π / 2, і що здебільшого похибка наближення фактично менша, ніж одна з підписаних функцій живлення.(3)4.5e-3π/2

EDIT 2:

Якщо ви не заперечуєте поділу, ви також можете використати формулу наближення синуса Bhaskara I , яка має максимальну помилку наближення 1.6e-3:

(4)sin(x)16x(πx)5π24x(πx),x[0,π/2]

Це дуже корисно, дякую. Це перший раз, коли я використовував Octave. Я стежив за більшою частиною цього, але як ви отримали графіки помилок наближення та максимальні значення?
Гість

1
@Guest: Помилки справедливі b-f3і b-f5, відповідно. Використовуйте plotкоманду, щоб побудувати їх.
Метт Л.

1
@Guest: І максимуми, які ви отримуєте від max(abs(b-f3))і max(abs(b-f5)).
Метт Л.

@Guest: Я розігрувався з підписаною функцією живлення, але результат не суттєво кращий за наближення третього порядку, яке я мав раніше. Перевірте мою відредаговану відповідь. Що стосується складності, чи не змінило б це таке велике значення?
Метт Л.

Дякуємо, що заглянули в нього. Складність - це не велика справа, цікаво лише те, наскільки точним може бути наближення при порівняно низькій складності. Я не зовсім впевнений, як ви придумали (3), але це добре працює. Мені потрібно використовувати 2.752 замість цього p, оскільки все вище, що надсилатиме вершини понад 1 (відсікання).
Гість

7

Почніть з інакше загальної, непарної симетрії параметризованого многочлена 5-го порядку:

f(x)=a0x1+a1x3+a2x5=x(a0+a1x2+a2x4)=x(a0+x2(a1+a2x2))

Тепер ми покладаємо деякі обмеження на цю функцію. Амплітуда повинна бути 1 на вершинах, іншими словами f(1)=1 . Заміна 1 на x дає:

(1)a0+a1+a2=1

Це одне обмеження. Нахил на вершинах повинен бути нульовим, іншими словами f(1)=0 . Похідна f(x) є

a0+3a1x2+5a2x4

а підстановка 1 на x дає наше друге обмеження:

(2)a0+3a1+5a2=0

Тепер ми можемо використовувати наші два обмеження для вирішення для a1 і a2 точки зору a0 .

(3)a1=522a0a2=a032

Все , що залишилося налаштувати a0 , щоб отримати хороший припадок. Між іншим, 0 (і нахил на початку координат) закінчує тим , що лa0π2 , як ми бачимо зсюжетуфункції.

Оптимізація параметрів

Нижче наведено низку оптимізацій коефіцієнтів, в результаті яких ці відносні амплітуди гармонік порівняно з фундаментальною частотою (1-а гармоніка):

Comparison of approximations

У складній серії Фур'є :

k=ckei2πPkx,

P-P=4x=1f(x)1x1,kth

ck=1P11+P({f(x)if x<1f(x2)if x1)ei2πPkxdx.

2cos(x)=eix+eixk>02|ck|,

2|ck|=24|13({f(x)if x<1f(x2)if x1)ei2π4kxdx|=12|11f(x)eiπ2kxdx13f(x2)eiπ2kxdx|=12|11f(x)eiπ2kxdx11f(x+22)eiπ2k(x+2)dx|=12|11f(x)eiπ2kxdx11f(x)eiπ2k(x+2)dx|=12|11f(x)(eiπ2kxeiπ2k(x+2))dx|=12|eiπ2x11f(x)(eiπ2kxeiπ2k(x+2))dx|=12|11f(x)(eiπ2k(x1)eiπ2k(x+1))dx|

The above takes advantage of that |eix|=1 for real x. It is easier for some computer algebra systems to simplify the integral by assuming k is real, and to simplify to integer k at the end. Wolfram Alpha can integrate individual terms of the final integral corresponding to the terms of the polynomial f(x). For the coefficients given in Eq. 3 we get amplitude:

=|48((1)k1)(16a0(π2k210)5×(5π2k248))π6k6|

5th order, continuous derivative

We can solve for the value of a0 that gives equal amplitude 2|ck|of the 3rd and the 5th harmonic. There will be two solutions corresponding to the 3rd and the 5th harmonic having equal or opposite phases. The best solution is the one that minimizes the maximum amplitude of the 3rd and above harmonics and equivalently the maximum relative amplitude of the 3rd and above harmonics compared to the fundamental frequency (1st harmonic):

a0=3×(132375π2130832)16×(15885π216354)1.569778813,a1=522a0=79425π2654168×(15885π2+16354)0.6395576276,a2=a032=15885π216×(15885π216354)0.06977881382.

This gives the fundamental frequency at amplitude 1367961615885π616354π41.000071420 and both the 3rd and the 5th harmonic at relative amplitude 18906 or about 78.99 dB compared to the fundamental frequency. A kth harmonic has relative amplitude (1(1)k)|8177k279425|142496k6.

7th order, continuous derivative

Likewise, the optimal 7th order polynomial approximation with the same initial constraints and the 3rd, 5th, and 7th harmonic at the lowest possible equal level is:

f(x)=a0x1+a1x3+a2x5+a3x7=x(a0+a1x2+a2x4+a3x7)=x(a0+x2(a1+x2(a2+a3x2)))

a0=2a2+4a3+321.570781972,a1=4a2+6a3+120.6458482979,a2=347960025π4405395408π216×(281681925π4405395408π2+108019280)0.07935067784,a3=16569525π416×(281681925π4405395408π2+108019280)0.004284352588.

This is the best of four possible solutions corresponding to equal/opposite phase combinations of the 3rd, 5th, and 7th harmonic. The fundamental frequency has amplitude 2293523251200281681925π8405395408π6+108019280π40.9999983752, and the 3rd, 5th, and 7th harmonics have relative amplitude 11555395123.8368 dB compared to the fundamental. A kth harmonic has relative amplitude (1(1)k)|1350241k450674426k2+347960025|597271680k8 compared to the fundamental.

5th order

If the requirement of a continuous derivative is dropped, the 5th order approximation will be more difficult to solve symbolically, because the amplitude of the 9th harmonic will rise above the amplitude of the 3rd, 5th, and the 7th harmonic if those are constrained to be equal and minimized. Testing 16 different solutions corresponding to different subsets of three harmonics from {3,5,7,9} being of equal amplitude and of equal or opposite phases, the best solution is:

f(x)=a0x1+a1x3+a2x5a0=1a1a21.570034357a1=3×(2436304π22172825π4)8×(1303695π41827228π2+537160)0.6425216143a2=1303695π416×(1303695π41827228π2+537160)0.07248725712

The fundamental frequency has amplitude 10804305921303695π61827228π4+537160π20.9997773320. The 3rd, 5th, and 9th harmonics have relative amplitude 726377791.52 dB, and the 7th harmonic has relative amplitude 7260833103310027392.6 dB compared to the fundamental. A kth harmonic has relative amplitude (1(1)k)|67145k42740842k2+19555425|33763456k6.

This approximation has a slight corner at the half-cycle boundaries, because the polynomial has zero derivative not at x=±1 but at x±1.002039940. At x=1 the value of the derivative is about 0.004905799828. This results in slower asymptotic decay of the amplitudes of the harmonics at large k, compared to the 5th order approximation that has a continuous derivative.

7th order

A 7th order approximation without continuous derivative can be found similarly. The approach requires testing 120 different solutions and was automated by the Python script at the end of this answer. The best solution is:

f(x)=a0x1+a1x3+a2x5+a3x7a0=1a1a2a31.5707953785726114835a1=5×(4374085272375π66856418226992π4+2139059216768π2)16×(2124555703725π63428209113496π4+1336912010480π2155807094720)0.64590724797262922190a2=2624451163425π63428209113496π416×(2124555703725π63428209113496π4+1336912010480π2155807094720)0.079473610232926783079a3=124973864925π616×(2124555703725π63428209113496π4+1336912010480π2155807094720)0.0043617408329090447344

The fundamental frequency has amplitude 169918012823961602124555703725π83428209113496π6+1336912010480π4155807094720π21.0000024810802368487. The largest relative amplitude of the harmonics above the fundamental is 502400688077133.627 dB. compared to the fundamental. A kth harmonic has relative amplitude (1(1)k)|162299057k6+16711400131k4428526139187k2+2624451163425|4424948250624k8.

Python source

from sympy import symbols, pi, solve, factor, binomial

numEq = 3 # Number of equations
numHarmonics = 6 # Number of harmonics to evaluate

a1, a2, a3, k = symbols("a1, a2, a3, k")
coefficients = [a1, a2, a3]
harmonicRelativeAmplitude = (2*pi**4*a1*k**4*(pi**2*k**2-12)+4*pi**2*a2*k**2*(pi**4*k**4-60*pi**2*k**2+480)+6*a3*(pi**6*k**6-140*pi**4*k**4+6720*pi**2*k**2-53760)+pi**6*k**6)*(1-(-1)**k)/(2*k**8*(2*pi**4*a1*(pi**2-12)+4*pi**2*a2*(pi**4-60*pi**2+480)+6*a3*(pi**6-140*pi**4+6720*pi**2-53760)+pi**6))

harmonicRelativeAmplitudes = []
for i in range(0, numHarmonics) :
    harmonicRelativeAmplitudes.append(harmonicRelativeAmplitude.subs(k, 3 + 2*i))

numCandidateEqs = 2**numHarmonics
numSignCombinations = 2**numEq
useHarmonics = range(numEq + 1)

bestSolution = []
bestRelativeAmplitude = 1
bestUnevaluatedRelativeAmplitude = 1
numSolutions = binomial(numHarmonics, numEq + 1)*2**numEq
solutionIndex = 0

for i in range(0, numCandidateEqs) :
    temp = i
    candidateNumHarmonics = 0
    j = 0
    while (temp) :
        if (temp & 1) :
            if candidateNumHarmonics < numEq + 1 :
                useHarmonics[candidateNumHarmonics] = j
            candidateNumHarmonics += 1
        temp >>= 1
        j += 1
    if (candidateNumHarmonics == numEq + 1) :
        for j in range(0,  numSignCombinations) :
            eqs = []
            temp = j
            for n in range(0, numEq) :
                if temp & 1 :
                    eqs.append(harmonicRelativeAmplitudes[useHarmonics[0]] - harmonicRelativeAmplitudes[useHarmonics[1+n]])
                else :
                    eqs.append(harmonicRelativeAmplitudes[useHarmonics[0]] + harmonicRelativeAmplitudes[useHarmonics[1+n]])
                temp >>= 1
            solution = solve(eqs, coefficients, manual=True)
            solutionIndex += 1
            print "Candidate solution %d of %d" % (solutionIndex, numSolutions)
            print solution
            solutionRelativeAmplitude = harmonicRelativeAmplitude
            for n in range(0, numEq) :                
                solutionRelativeAmplitude = solutionRelativeAmplitude.subs(coefficients[n], solution[0][n])
            solutionRelativeAmplitude = factor(solutionRelativeAmplitude)
            print solutionRelativeAmplitude
            solutionWorstRelativeAmplitude = 0
            for n in range(0, numHarmonics) :
                solutionEvaluatedRelativeAmplitude = abs(factor(solutionRelativeAmplitude.subs(k, 3 + 2*n)))
                if (solutionEvaluatedRelativeAmplitude > solutionWorstRelativeAmplitude) :
                    solutionWorstRelativeAmplitude = solutionEvaluatedRelativeAmplitude
            print solutionWorstRelativeAmplitude
            if (solutionWorstRelativeAmplitude < bestRelativeAmplitude) :
                bestRelativeAmplitude = solutionWorstRelativeAmplitude
                bestUnevaluatedRelativeAmplitude = solutionRelativeAmplitude                
                bestSolution = solution
                print "That is a new best solution!"
            print

print "Best Solution is:"
print bestSolution
print bestUnevaluatedRelativeAmplitude
print bestRelativeAmplitude

This is a variation on Robert's answer, and is the route I eventually took. I'm leaving it here in case it helps anyone else.
Guest

wow, solving it analytically. i woulda just used MATLAB and an FFT and sorta hunt around for the answer.
you did very well.
Роберт Брістоу-Джонсон

2
actually @OlliNiemitalo, i think -79 dB is good enough for the implementation of a digital synth sine wave oscillator. it can be driven by a triangle wave, which is generated easily from the abs value of a sawtooth, which is most easily generated with a fixed-point phase accumulator.
no one will hear a difference between that 5th-order polynomial sine wave and a pure sine.
robert bristow-johnson

1
Polynomials in general as f have the advantage that by increasing the order, the error can be made arbitrarily small. Rational functions have the same advantage, but a division is typically more costly to compute than multiplication. For example in Intel i7, a single thread can do 7-27 times as many multiplications and additions than divisions in the same time. Approximating some alternative f means decomposing it to elementary ops, typically multiplications and additions which always amount to polynomials. Those could be optimized to approximate sine directly versus via f.
Olli Niemitalo

1
@OlliNiemitalo, I see what you mean... if division is that much slower than multiplication (and I guess things like roots / fractional exponents will be even worse), then an approach like the above with a "good, fast f0" is going to wind up factoring out to a Taylor-series-like-polynomial anyway. I guess since it's an approximation anyway, some kind of cheap root approximation could potentially overtake the polynomial approach at some level of accuracy, but that's kinda off in the weeds for what was essentially supposed to be a math question.
Guest

5

Are you asking this for theoretical reasons or a practical application?

Usually, when you have an expensive to compute function over a finite range the best answer is a set of lookup tables.

One approach is to use best fit parabolas:

n = floor( x * N + .5 );

d = x * N - n;

i = n + N/2;

y = L_0 + L_1[i] * d + L_2[i] * d * d;

By finding the parabola at each point that meets the values for d being -1/2, 0, and 1/2, rather than using the derivatives at 0, you ensure a continuous approximation. You could also shift the x value, rather than the array index to deal with your negative x values.

Ced

=================================================

Followup:

The amount of effort, and the results, that have gone into finding good approximations is very impressive. I was curious as to how my boring and bland piecewise parabolic solution would compare. Not surprisingly, it does much better. Here are the results:

   Method    Minimum    Maximum     Mean       RMS
  --------   --------   --------   --------   --------
     Power   -8.48842    1.99861   -4.19436    5.27002
    OP S_3   -2.14675    0.00000   -1.20299    1.40854
     Bhask   -1.34370    1.63176   -0.14367    0.97353
     Ratio   -0.24337    0.22770   -0.00085    0.16244
     rbj 5   -0.06724    0.15519   -0.00672    0.04195
    Olli5C   -0.16367    0.20212    0.01003    0.12668
     Olli5   -0.26698    0.00000   -0.15177    0.16402
    Olli7C   -0.00213    0.00000   -0.00129    0.00143
     Olli7   -0.00005    0.00328    0.00149    0.00181
    Para16   -0.00921    0.00916   -0.00017    0.00467
    Para32   -0.00104    0.00104   -0.00001    0.00053
    Para64   -0.00012    0.00012   -0.00000    0.00006

The values represent 1000x the error between the approximation and the actual evaluated every .0001 from a scale of 0 to 1 (inclusive), so 10001 points in all. The scale is converted to evaluate the functions from 0 to π/2, except for Olli Niemitalo's equations which use the 0 to 1 scale. The columns values should be clear from the headers. The results don't change with a .001 spacing.

The "Power" line is the equation: xxe6.

The rbj 5 line is the same as Matt L's c5 solution.

The 16, 32, and 64 are the number of intervals that have parabolic fits. Of course there are insignificant discontinuities in the first derivative at each interval boundary. The values of the function are continuous though. Increasing the number of intervals only increases the memory requirements (and initialization time), it does not increase the amount of calculation needed for the approximation, which is less than any of the other equations. I chose powers of two because a fixed point implementation could save a division by using an AND in such cases. Also, I didn't want the count to be commensurate with the test sampling.

I did run Olli Niemitalo's python program and got this as part of the printout: "Candidate solution 176 of 120" I thought that was odd, so I am mentioning it.

If anybody wants me to include any of the other equations, please let me know in the comments.

Here is the code for the piecewise parabolic approximations. The entire test program is too long to post.

#=============================================================================
def FillParab( argArray, argPieceCount ):

#  y = a d^2 + b d + c

#  ym = a .25 - b .5 + c
#  y  =                c
#  yp = a .25 + b .5 + c

#  c = y
#  b = yp - ym
#  a = ( yp + ym - 2y ) * 2

#---- Calculate Lookup Arrays

        theStep = pi * .5 / float( argPieceCount - 1 )
        theHalf = theStep * .5

        theL0 = zeros( argPieceCount )
        theL1 = zeros( argPieceCount )
        theL2 = zeros( argPieceCount )

        for k in range( 0, argPieceCount ):
         x  = float( k ) * theStep

         ym = sin( x - theHalf )
         y  = sin( x )
         yp = sin( x + theHalf )

         theL0[k] = y
         theL1[k] = yp - ym
         theL2[k] = ( yp + ym - 2.0 * y ) * 2

#---- Do the Fill

        theN = len( argArray )

        theFactor = pi * .5 / float( theN - 1 )

        for i in range( 0, theN ):
         x  = float( i ) * theFactor

         kx = x / theStep
         k  = int( kx + .5 )
         d  = kx - k

         argArray[i] = theL0[k] + ( theL1[k] + theL2[k] * d ) * d

#=============================================================================

=======================================

Appendum

I have included Guest's S3 function from the original post as "OP S_3" and Guest's two parameter formula from the comments as "Ratio". Both are on the 0 to 1 scale. I don't think the Ratio one is suitable for either calculation at runtime or for building a lookup table. After all, it is significantly more computation for the CPU than just a plain sin() call. It is interesting mathematically though.


Good work! I fixed that bug ("176 of 120").
Olli Niemitalo

Nice update, this makes more sense to me now. The xxe6 probably doesn't need to be tested, I just threw it out there because I was trying to figure out the significance of e which seemed to keep popping up while I was playing with this. A better rational expression to test might be something like this: f0(x)=|x|asign(x) ; b=f0(1) ; f1(x)=f0(x)bx ; c=1f1(1) ; f2(x)=f1(x)c ... now a should be set to about 223...
Guest

...or f0(x) can be pretty much any other odd-symmetrical function; sigmoids seem to work well, like ax1ax+1 (but then the right value for a needs to be found, of course). Here's a plot... as Olli mentions, this probably isn't practical for on-the-fly computation, but I guess it could be useful for building a lookup table.
Guest

Or a more accurate 2-param version of that, a0xa1xa0x+a1x looks pretty good with a013 and a1109
Guest
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.