Menemukan perkiraan polinomial dari gelombang sinus


16

Saya ingin memperkirakan gelombang sinus yang diberikan oleh dengan menerapkan pemandu gelombang polinomial ke gelombang segitiga sederhana , yang dihasilkan oleh fungsisin(πx)

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

di mana adalah bagian fraksional dari :mod(x,1)x

mod(x,y)y(xyxy)

Sebuah seri Taylor dapat digunakan sebagai WaveShaper a.

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

Dengan adanya fungsi-fungsi di atas, S1(T(x)) akan memberi kita perkiraan yang layak dari gelombang sinus. Tapi kita harus naik ke kekuatan ke-7 dari seri untuk mendapatkan hasil yang masuk akal, dan puncaknya sedikit rendah dan tidak akan memiliki kemiringan yang persis nol.

Alih-alih seri Taylor, kita bisa menggunakan pembuat film polinom mengikuti beberapa aturan.

  • Harus melewati -1, -1 dan + 1, + 1.
  • Kemiringan pada -1, -1 dan + 1, + 1 harus nol.
  • Harus simetris.

Fungsi sederhana yang memenuhi persyaratan kami:

S2(x)=3x2x32

Grafik S2(T(x)) dan sin(πx) cukup dekat, tetapi tidak sedekat seri Taylor. Di antara puncak dan zero-crossing mereka tampak sedikit menyimpang. Fungsi yang lebih berat dan lebih akurat memenuhi persyaratan kami:

S3(x)=x(x25)216

Ini mungkin cukup dekat untuk tujuan saya, tetapi saya bertanya-tanya apakah ada fungsi lain yang mendekati gelombang sinus lebih dekat, dan secara komputasi lebih murah. Saya memiliki pemahaman yang cukup baik tentang bagaimana menemukan fungsi yang memenuhi tiga persyaratan di atas, tetapi saya tidak yakin bagaimana mencari fungsi yang memenuhi persyaratan tersebut dan juga yang paling cocok dengan gelombang sinus.

Metode apa yang ada untuk menemukan polinomial yang meniru gelombang sinus (bila diterapkan pada gelombang segitiga)?


Untuk memperjelas, saya tidak hanya mencari polinomial aneh-simetris, meskipun itu adalah pilihan yang paling mudah.

Sesuatu seperti fungsi berikut ini juga dapat memenuhi kebutuhan saya:

S4(x)=3x2+x24+x44

Ini memenuhi persyaratan dalam kisaran negatif, dan solusi sepotong-sepotong dapat digunakan untuk menerapkannya pada rentang positif juga; sebagai contoh

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

di mana adalah fungsi daya yang ditandatangani .P

Saya juga akan tertarik pada solusi menggunakan fungsi daya yang ditandatangani untuk mendukung eksponen fraksional, karena ini memberi kita "kenop untuk memutar" tanpa menambahkan koefisien lain.

a0x +a1P(x, p1)

Dengan konstanta yang tepat, ini berpotensi mendapatkan akurasi yang sangat baik tanpa beban polinomial orde lima atau ketujuh. Berikut ini contoh memenuhi persyaratan yang dijelaskan di sini menggunakan beberapa konstanta yang dipilih sendiri: .a0=1.666¯,a1=0.666¯,p1=2.5

5x-2P(x, 52)3

Faktanya, konstanta-konstanta itu sangat dekat dengan , dan , dan . Memasukkannya memberi sesuatu yang terlihat sangat dekat dengan gelombang sinus. 1-ππ21-π2e

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

Dengan kata lain, terlihat sangat dekat dengan antara 0,0 dan π / 2,1. Adakah pemikiran tentang pentingnya hal ini? Mungkin alat seperti Oktaf dapat membantu menemukan konstanta "terbaik" untuk pendekatan ini.x-xe6dosa(x)


1
jadi, apa definisi istilah kesalahan Anda untuk "lebih dekat"? Sejauh yang saya tahu, seri Taylor yang Anda kutip adalah perkiraan kesalahan L² minimum untuk jumlah koefisien terbatas. (Saya pikir.)
Marcus Müller

2
Ngomong-ngomong, apa tujuan Anda? Mungkin sangat membantu untuk memberi tahu kami mengapa Anda mencari pembentuk gelombang polinomial, atas dasar teknologi apa, dan apa tujuan utama Anda untuk perkiraan tersebut.
Marcus Müller

@ MarcusMüller Saya bersedia mengorbankan akurasi seri Taylor untuk sesuatu yang jauh lebih murah, jika itu tidak dapat dibedakan dari gelombang sinus hingga ke telinga manusia. Puncak perkiraan seri Taylor juga mengganggu saya. Saya tertarik menemukan sesuatu yang "lebih dekat" daripada dua fungsi lainnya yang saya daftarkan. Saya menduga itu tidak akan lebih murah dari . S2
Tamu

1
"Untuk telinga manusia" sangat penting di sini :) Mengapa puncak "mengganggu" Anda? Sekali lagi: beri kami ide mengapa / untuk tujuan apa dan di bawah batasan apa Anda melakukan ini. Tanpa latar belakang yang cukup, pertanyaan Anda terlalu luas untuk dijawab dengan benar!
Marcus Müller

1
Mengapa Anda memulai dengan gelombang segitiga? Generator sinus sederhana dan umum, gelombang persegi disaring secara sepele ke harmonik dasar, dll.
Carl Witthoft

Jawaban:


10

sekitar satu dekade yang lalu saya melakukan ini untuk perusahaan synthesizer musik tanpa nama yang memiliki R&D tidak terlalu jauh dari kondominium saya di Waltham MA. (tidak bisa membayangkan siapa mereka.) Saya tidak memiliki koefisien.

tapi coba ini:

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

ini menjamin bahwa .f(x)=f(x)

Untuk menjamin bahwa laluf(x)|x=±1=0

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

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

Itu kendala pertama. Untuk menjamin itu , lalu|f(±1)|=1

(2)a0+a1+a2=2π

Itu kendala kedua. Menghilangkan dan memecahkan pers. (1) dan (2) untuk sebuah 2 dalam hal suatu 1 (yang tersisa untuk menyesuaikan):a0a2a1

a0=52π12a1

a2=12π12a1

Sekarang Anda hanya memiliki satu koefisien, , kiri untuk bermalas untuk kinerja terbaik:a1

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

Ini adalah cara saya akan main 1 untuk kinerja terbaik untuk osilator gelombang sinus. Saya akan menyesuaikan menggunakan di atas dan simetri gelombang sinus sekitar x = 1 dan menempatkan tepat satu siklus penuh dalam buffer dengan kekuatan dua jumlah poin (katakan 128, saya tidak peduli) dan jalankan FFT pada itu siklus sempurna.a1x=1

Bin hasil FFT 1 akan menjadi kekuatan sinus dan harus sekitar . Sekarang Anda dapat menyesuaikan sebuah 1 untuk membawa distorsi harmonik ke-3 atas dan ke bawah. Saya akan mulai dengan sebuah 15N/2a1sehinggasebuah01. Itu di bin 3 dari hasil FFT Tapi distorsi harmonik ke-5 (nilai dalam bin 5) akan menjadi konsekuensial (itu akan naik ketika harmonik ke-3 turun). Saya akan menyesuaikansebuah1sehingga kekuatan dari tingkat harmonik ke-5 sama dengan tingkat harmonik ke-3. Ini akan menjadi sekitar -70 dB dari harmonik 1 (seingat saya). Itu akan menjadi gelombang sinus terdengar terbaik dari polinomial aneh, simetris, 3-koefisien, orde-5.a15π2a01a1

Orang lain dapat menulis kode MATLAB. Bagaimana kedengarannya menurut anda?


saya pasti tidak akan punya waktu untuk melakukan MATLABing untuk berburu untuk optimal sehingga 3rd harmonik sama dengan harmonik ke-5, sekitar 70 dB di bawah (harmonik 1) fundamental. orang lain perlu melakukan itu. Maaf. a1
robert bristow-johnson

Jawaban yang bagus, masih mencernanya. Sebenarnya mulai bertanya-tanya apakah itu perlu polinomial 3-koefisien, orde 5, aneh-simetris ... Bisakah f '(x) Anda benar-benar menjadi f (x) dan menjadi kesepakatan piecewise sekitar 0? Sketsa kasar di sini . Mungkin ini yang ada di benak Ced? Masih mengejar kalian.
Tamu

Ini adalah pendekatan yang indah. Saya ingin tahu apakah alih-alih mengambil FFT dan menyelesaikannya secara berulang, Anda dapat membentuk polinomial Chebyshev urutan ketiga dan kelima dari , lalu menyamakan keduanya dan menyelesaikannya dengan nilai 1 ? f(x)a1
Cepat

Pasti setengah tertidur ketika saya memposting "sketsa," saya bermaksud melakukan sesuatu seperti ini , tetapi dikoreksi untuk menjalankan ± 1 dan memiliki kemiringan nol (hanya dapat mengambil turunan, bermain-main dengannya, mengintegrasikannya lagi). Tidak yakin apakah ada keunggulan dibandingkan urutan kelima, hanya sesuatu yang belum saya pertimbangkan.
Tamu

1
Ini benar-benar solusi yang brilian, hanya perlu beberapa saat untuk meresap. Saya harap menandainya dengan benar tidak akan menghentikan orang lain untuk datang dan menulis kode.
Tamu

9

Apa yang biasanya dilakukan adalah perkiraan meminimalkan beberapa norma kesalahan, seringkali -norm (di mana kesalahan maksimum diminimalkan), atau L 2 -norm (di mana kesalahan kuadrat rata-rata diminimalkan). L ∞ - aproksimasi dilakukan dengan menggunakan algoritma pertukaran Remez . Saya yakin Anda dapat menemukan beberapa kode sumber terbuka yang mengimplementasikan algoritma itu. Namun, dalam kasus ini saya pikir sangat sederhana (diskrit) l 2 -optimization cukup. Mari kita lihat beberapa kode Matlab / Oktaf dan hasilnya:LL2Ll2

x = linspace (0, pi / 2.300); % kisi pada [0, pi / 2]
x = x (:);
% sistem persamaan linear yang ditentukan secara berlebihan
% (hanya menggunakan kekuatan ganjil)
A3 = [x, x. ^ 3];
A5 = [x, x. ^ 3, x. ^ 5];
b = sin (x);
% pecahkan dalam arti l2
c3 = A3 \ b;
c5 = A5 \ b;
f3 = A3 * c3; % Perkiraan pesanan 3
f5 = A5 * c5; % Perkiraan pesanan ke-5

Gambar di bawah ini menunjukkan kesalahan perkiraan untuk orde dan untuk orde 5 t h- orde. Kesalahan perkiraan maksimum masing-masing adalah dan .3rd5th8.8869e-031.5519e-04

masukkan deskripsi gambar di sini

Koefisien optimal adalah

c3 =
   0,988720369237930
  -0.144993929056091

dan

c5 =
   0.99976918199047515
  -0.16582163562776930
   0,00757183954143367

Jadi perkiraan tingkat ketiga adalah

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

dan pendekatan urutan kelima adalah

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

EDIT:

Saya telah melihat perkiraan dengan fungsi daya yang ditandatangani, seperti yang disarankan dalam pertanyaan, tetapi perkiraan terbaik hampir tidak lebih baik daripada perkiraan urutan ketiga yang ditunjukkan di atas. Fungsi aproksimasi adalah

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

di mana konstanta dipilih sedemikian rupa sehingga dan f ( π / 2 ) = 0 . Power p dioptimalkan untuk mencapai kesalahan maksimum terkecil di kisaran [ 0 , π / 2 ] . Nilai optimal untuk p ditemukan p = 2.774 . Gambar di bawah ini menunjukkan kesalahan aproksimasi untuk aproksimasi orde ketiga ( 1 ) dan untuk aproksimasi baru ( 3)f(0)=1f(π/2)=0p[0,π/2]pp=2.774(1) :(3)

enter image description here

Kesalahan aproksimasi maksimum aproksimasi adalah , tetapi perhatikan bahwa aproksimasi orde ketiga hanya melebihi kesalahan yang mendekati π / 2 dan bahwa sebagian besar kesalahan aproksimasi sebenarnya lebih kecil dari salah satu fungsi daya yang ditandatangani.(3)4.5e-3π/2

EDIT 2:

Jika Anda tidak keberatan pembagian, Anda juga bisa menggunakan rumus perkiraan sinus Bhaskara I , yang memiliki kesalahan perkiraan maksimum 1.6e-3:

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

Itu sangat membantu, terima kasih. Ini adalah pertama kalinya saya menggunakan Oktaf. Saya mengikuti sebagian besar, tetapi bagaimana Anda mendapatkan plot kesalahan perkiraan dan nilai maksimum?
Tamu

1
@Guest: Kesalahan hanya b-f3dan b-f5masing-masing. Gunakan plotperintah untuk merencanakannya.
Matt L.

1
@ Guest: Dan maksimal yang Anda dapatkan dari max(abs(b-f3))dan max(abs(b-f5)).
Matt L.

@ Guest: Saya bermain-main dengan fungsi daya yang ditandatangani, tetapi hasilnya tidak jauh lebih baik daripada perkiraan tingkat ketiga yang saya miliki sebelumnya. Lihat jawaban saya yang diedit. Sedangkan untuk kompleksitas, apakah akan membuat perbedaan besar?
Matt L.

Terima kasih telah memeriksanya. Kompleksitas bukan masalah besar, hanya ingin tahu seberapa akurat perkiraan dapat dengan kompleksitas yang relatif rendah. Saya tidak yakin bagaimana Anda datang dengan (3), tetapi itu bekerja dengan baik. Saya harus menggunakan 2.752 sebagai gantinya p, karena apa pun di atas yang akan mengirim puncak lebih dari 1 (kliping).
Tamu

7

Mulai dengan polinomial parameter-urutan ke-5 yang umum dan tidak simetri :

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

Sekarang kami menempatkan beberapa kendala pada fungsi ini. Amplitudo harus 1 pada puncak, dengan kata lain f(1)=1 . Mengganti 1 untuk x memberi:

(1)a0+a1+a2=1

That's one constraint. The slope at the peaks should be zero, in other words f(1)=0. The derivative of f(x) is

a0+3a1x2+5a2x4

and substituting 1 for x gives our second constraint:

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

Now we can use our two constraints to solve for a1 and a2 in terms of a0.

(3)a1=522a0a2=a032

All that's left is to tweak a0 to get a nice fit. Incidentally, a0 (and the slope at the origin) ends up being π2, as we can see from a plot of the function.

Parameter optimization

Below are a number of optimizations of the coefficients, which result in these relative amplitudes of the harmonics compared to the fundamental frequency (1st harmonic):

Comparison of approximations

In the complex Fourier series:

k=ckei2πPkx,

of a real P-periodic waveform with P=4 and time symmetry about x=1 and with half a period defined by odd function f(x) over 1x1, the coefficient of the kth complex exponential harmonic is:

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

Because of the relationship 2cos(x)=eix+eix (see: Euler's formula), the amplitude of a real sinusoidal harmonic with k>0 is 2|ck|, which is twice that of the magnitude of the complex exponential of the same frequency. This can be massaged to a form which makes it easier for some symbolic mathematics software to simplify the integral:

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

Ini adalah variasi dari jawaban Robert, dan rute yang akhirnya saya ambil. Saya meninggalkannya di sini kalau-kalau itu membantu orang lain.
Tamu

wow, solving it analytically. i woulda just used MATLAB and an FFT and sorta hunt around for the answer.
you did very well.
robert bristow-johnson

2
sebenarnya @OlliNiemitalo, saya pikir -79 dB cukup baik untuk penerapan osilator gelombang sine digital synth. itu dapat digerakkan oleh gelombang segitiga, yang dihasilkan dengan mudah dari nilai abs dari gigi gergaji, yang paling mudah dihasilkan dengan akumulator fase titik tetap.
tidak ada yang akan mendengar perbedaan antara gelombang sinus polinomial orde 5 dan sinus murni.
robert bristow-johnson

1
Polinomial pada umumnya seperti fmemiliki keuntungan bahwa dengan meningkatkan pesanan, kesalahan dapat dibuat kecil secara sewenang-wenang. Fungsi rasional memiliki keuntungan yang sama, tetapi pembagian biasanya lebih mahal untuk dihitung daripada perkalian. Misalnya di Intel i7, utas tunggal dapat melakukan 7-27 kali lebih banyak perkalian dan penambahan daripada pembagian dalam waktu yang bersamaan. Mendekati beberapa alternatiffberarti menguraikannya ke operasi elementer, biasanya perkalian dan penambahan yang selalu berjumlah polinomial. Itu bisa dioptimalkan untuk mendekati sinus langsung versus viaf.
Olli Niemitalo

1
@ OlliNiemitalo, saya mengerti maksud Anda ... jika pembagian jauh lebih lambat daripada perkalian (dan saya kira hal-hal seperti eksponen root / fraksional akan lebih buruk), maka pendekatan seperti di atas dengan "baik, cepat f0"Akan berakhir memfaktorkan keluar ke polinomial Taylor-series-like-anyway. Saya kira karena itu pula pendekatan, semacam pendekatan akar murah berpotensi menyalip pendekatan polinomial pada tingkat akurasi tertentu, tapi itu agak tidak masuk akal. gulma untuk apa yang pada dasarnya seharusnya menjadi pertanyaan matematika.
Tamu

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

Atau versi 2-param yang lebih akurat dari itu, Sebuah0x-Sebuah1xSebuah0x+Sebuah1x terlihat cukup bagus denganSebuah013 dan Sebuah1109
Tamu
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.