Trouver des approximations polynomiales d'une onde sinusoïdale


16

Je veux approximer l'onde sinusoïdale donnée par en appliquant un forme d' onde polynomiale à une simple onde triangulaire , générée par la fonctionsin(πx)

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

où est la partie fractionnaire de :mod(x,1)x

mod(x,y)y(xyxy)

Une série Taylor pourrait être utilisée comme forme d'onde.

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

Étant donné les fonctions ci-dessus, S1(T(x)) nous donnera une approximation décente d'une onde sinusoïdale. Mais nous devons aller jusqu'à la 7e puissance de la série pour obtenir un résultat raisonnable, et les pics sont un peu bas et n'auront pas une pente exactement nulle.

Au lieu de la série Taylor, nous pourrions utiliser un onduleur polynomial suivant quelques règles.

  • Doit passer par -1, -1 et + 1, + 1.
  • La pente à -1, -1 et + 1, + 1 doit être nulle.
  • Doit être symétrique.

Une fonction simple répondant à nos exigences:

S2(x)=3x2x32

Les graphiques de S2(T(x)) et sin(πx) sont assez proches, mais pas aussi proches que la série Taylor. Entre les pics et les passages à zéro, ils s'écartent visiblement un peu. Une fonction plus lourde et plus précise répondant à nos exigences:

S3(x)=x(x25)216

C'est probablement assez proche pour mes besoins, mais je me demande si une autre fonction existe qui se rapproche de l'onde sinusoïdale de plus près et est moins coûteuse en termes de calcul. J'ai une assez bonne compréhension de la façon de trouver des fonctions répondant aux trois exigences ci-dessus, mais je ne suis pas sûr de savoir comment trouver des fonctions qui répondent à ces exigences et correspondent le mieux à une onde sinusoïdale.

Quelles méthodes existent pour trouver des polynômes qui imitent une onde sinusoïdale (lorsqu'ils sont appliqués à une onde triangulaire)?


Pour clarifier, je ne recherche pas nécessairement uniquement des polynômes symétriques impairs, bien que ce soit le choix le plus simple.

Quelque chose comme la fonction suivante pourrait également répondre à mes besoins:

S4(x)=3x2+x24+x44

Cela répond aux exigences dans la plage négative, et une solution par morceaux pourrait être utilisée pour l'appliquer également à la plage positive; par exemple

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

où est la fonction de puissance signée .P

Je serais également intéressé par des solutions utilisant la fonction de puissance signée pour prendre en charge les exposants fractionnaires, car cela nous donne un autre "bouton à tordre" sans ajouter un autre coefficient.

a0x +a1P(x, p1)

Étant donné les bonnes constantes, cela pourrait potentiellement obtenir une très bonne précision sans la lourdeur des polynômes du cinquième ou du septième ordre. Voici un exemple répondant aux exigences décrites ici à l'aide de constantes : .a0=1.666¯,a1=0.666¯,p1=2.5

5x2P(x, 52)3

En fait, ces constantes sont très proches de et et . Le fait de les brancher donne quelque chose qui ressemble extrêmement à une onde sinusoïdale. 1π21π2e

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

En d'autres , semble très proche de entre 0,0 et π / 2,1. Des réflexions sur la signification de cela? Peut-être qu'un outil comme Octave peut aider à découvrir les «meilleures» constantes pour cette approche.xxe6sin(x)


1
Alors, quelle est votre définition du terme d'erreur pour "plus proche"? Pour autant que je sache, la série de Taylor que vous avez citée est l'erreur minimale L² approximative pour un nombre fini de coefficients. (Je pense.)
Marcus Müller

2
Au fait, quel est votre objectif? Cela pourrait vraiment aider à nous dire pourquoi vous recherchez un modeleur d'ondes polynomiales, sur quelle base technologique et quels sont vos principaux objectifs pour l'approximation.
Marcus Müller

@ MarcusMüller Je suis prêt à sacrifier la précision de la série Taylor pour quelque chose de nettement moins cher, si elle ne se distingue pas d'une onde sinusoïdale à l'oreille humaine. Les pics d'approximation de la série Taylor me dérangent également. Je suis intéressé à trouver quelque chose de "plus proche" que les deux autres fonctions que j'ai énumérées. Je soupçonne que ce ne sera pas moins cher que . S2
Invité du

1
"Pour l'oreille humaine" est critique ici :) Pourquoi les pics vous "dérangent"? Encore une fois: donnez-nous une idée de pourquoi / dans quel but et sous quelles restrictions vous faites cela. Sans suffisamment de fond, votre question est tout simplement trop large pour être répondue correctement!
Marcus Müller

1
Pourquoi commencez-vous par une onde triangulaire? Les générateurs de
sinus

Réponses:


10

Il y a environ une décennie, j'ai fait cela pour une société de synthétiseur de musique anonyme qui avait de la R&D pas trop loin de mon condo à Waltham MA. (je ne peux pas imaginer qui ils sont.) Je n'ai pas les coefficients.

mais essayez ceci:

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

cela garantit que .f(x)=f(x)

Pour garantir que alorsf(x)|x=±1=0

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

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

Voilà la première contrainte. Pour garantir que , puis|f(±1)|=1

(2)a0+a1+a2=2π

Voilà la deuxième contrainte. Éliminer et résoudre les égaliseurs. (1) et (2) pour en termes de (qui reste à ajuster):a 2 a 1a0a2a1

a0=52π12a1

a2=12π12a1

Il ne vous reste plus qu'un coefficient, , à tordre pour de meilleures performances:a1

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

C'est ainsi que je ferais tourner pour de meilleures performances pour un oscillateur à onde sinusoïdale. Je réglerais en utilisant ce qui précède et la symétrie de l'onde sinusoïdale autour de et placerais exactement un cycle entier dans un tampon avec une puissance de deux nombres de points (disons 128, je m'en fiche) et exécuter la FFT sur ce cycle parfait. x = 1a1x=1

Le bac de résultat FFT 1 sera la force du sinus et devrait être d'environ . Maintenant, vous pouvez régler pour augmenter et diminuer la distorsion de votre 3e harmonique. Je commencerais par pour que . C'est dans la case 3 des résultats FFT Mais la 5ème distorsion harmonique (valeur dans la case 5) sera conséquente (elle montera lorsque la 3ème harmonique descendra). J'ajusterais pour que la force du 5ème niveau harmonique soit égale au 3ème niveau harmonique. Il sera d'environ -70 dB à partir de la 1ère harmonique (si je me souviens bien). Ce sera l'onde sinusoïdale la plus agréable à entendre à partir d'un polynôme symétrique symétrique à 5 coefficients bon marché.a 1 a 15N/2a1a01a1a15π2a01a1

Quelqu'un d'autre peut écrire le code MATLAB. Comment cela vous semble-t-il?


je n'aurai certainement pas le temps de faire le MATLABing pour rechercher l' optimal afin que la 3ème harmonique soit égale à la 5ème harmonique, environ 70 dB en dessous de la fondamentale (1ère harmonique). quelqu'un d'autre doit le faire. Pardon. a1
robert bristow-johnson

Excellente réponse, toujours digérée. En fait, je commence à me demander s'il doit s'agir d'un polynôme à 3 coefficients, 5e ordre, symétrique impair ... Votre f '(x) pourrait-il être réellement f (x) et être une opération par morceaux autour de 0? Croquis approximatif ici . C'est peut-être ce que Ced a en tête? Je vous rattrape toujours.
Invité du

C'est une belle approche. Je me demande si au lieu de prendre la FFT et de la résoudre de manière itérative, vous pourriez former les polynômes de Chebyshev de troisième et cinquième ordre à partir de votre , puis égaliser les deux et résoudre pour ? a 1f(x)a1
Speedy

Doit être à moitié endormi quand j'ai posté cette "esquisse", je voulais faire quelque chose comme ça , mais corrigé pour parcourir ± 1 et avoir une pente nulle (peut simplement prendre le dérivé, jouer avec, réintégrer). Je ne sais pas s'il y a un avantage par rapport au cinquième ordre, juste quelque chose que je n'avais pas encore considéré.
Invité le

1
C'est vraiment une solution brillante, il a juste fallu un certain temps pour pénétrer. J'espère que le marquer correctement n'empêchera pas quelqu'un d'autre de venir et d'écrire le code.
Invité du

9

Ce qui est généralement fait est une approximation minimisant une certaine norme de l'erreur, souvent la norme (où l'erreur maximale est minimisée), ou la norme L 2 (où l'erreur quadratique moyenne est minimisée). L' approximation L se fait en utilisant l' algorithme d'échange Remez . Je suis sûr que vous pouvez trouver du code open source implémentant cet algorithme. Cependant, dans ce cas, je pense qu'une optimisation l 2 (discrète) très simple est suffisante. Regardons un peu de code Matlab / Octave et les résultats:LL2Ll2

x = espace lins (0, pi / 2 300); % grille sur [0, pi / 2]
x = x (:);
% système d'équations linéaires surdéterminé
% (en utilisant uniquement des pouvoirs impairs)
A3 = [x, x. ^ 3];
A5 = [x, x. ^ 3, x. ^ 5];
b = sin (x);
% résoudre au sens l2
c3 = A3 \ b;
c5 = A5 \ b;
f3 = A3 * c3; % 3e approximation d'ordre
f5 = A5 * c5; % Approximation du 5ème ordre

La figure ci - dessous montre les erreurs d'approximation pour les -order et pour le 5 t h -order approximations. Les erreurs d'approximation maximales sont et , respectivement.3rd5th8.8869e-031.5519e-04

entrez la description de l'image ici

Les coefficients optimaux sont

c3 =
   0,988720369237930
  -0.144993929056091

et

c5 =
   0,99976918199047515
  -0.16582163562776930
   0,00757183954143367

Donc, l'approximation du troisième ordre est

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

et l'approximation du cinquième ordre est

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

ÉDITER:

J'ai examiné les approximations avec la fonction de puissance signée, comme suggéré dans la question, mais la meilleure approximation n'est guère meilleure que l'approximation du troisième ordre ci-dessus. La fonction d'approximation est

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

où les constantes ont été choisies de telle sorte que et f ( π / 2 ) = 0 . La puissance p a été optimisée pour obtenir la plus petite erreur maximale dans la plage [ 0 , π / 2 ] . La valeur optimale pour p s'est avérée être p = 2,774 . La figure ci-dessous montre les erreurs d'approximation pour l'approximation du troisième ordre ( 1 ) et pour la nouvelle approximation ( 3f(0)=1f(π/2)=0p[0,π/2]pp=2.774(1) :(3)

entrez la description de l'image ici

L'erreur d'approximation maximale de l'approximation est , mais notez que l'approximation du troisième ordre ne dépasse que cette erreur proche de π / 2 et que, pour la plupart, son erreur d'approximation est en fait plus petite que celle de la fonction de puissance signée.(3)4.5e-3π/2

EDIT 2:

Si cela ne vous dérange pas, vous pouvez également utiliser la formule d'approximation sinus de Bhaskara I , qui a une erreur d'approximation maximale de 1.6e-3:

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

C'est très utile, merci. C'est la première fois que j'utilise Octave. J'ai suivi l'essentiel, mais comment avez-vous obtenu les tracés d'erreur d'approximation et les valeurs maximales?
Invité du

1
@Guest: Les erreurs sont justes b-f3et b-f5, respectivement. Utilisez la plotcommande pour les tracer.
Matt L.

1
@Guest: Et les maxima que vous obtenez max(abs(b-f3))et max(abs(b-f5)).
Matt L.

@Guest: J'ai joué avec la fonction d'alimentation signée, mais le résultat n'est pas significativement meilleur que l'approximation du troisième ordre que j'avais auparavant. Découvrez ma réponse modifiée. Quant à la complexité, cela ferait-il une telle différence?
Matt L.

Merci de l'avoir regardé. La complexité n'est pas énorme, juste curieux de savoir à quel point l'approximation peut être précise avec une complexité relativement faible. Je ne sais pas trop comment vous en êtes arrivé à (3), mais cela fonctionne bien. J'aurais besoin d'utiliser 2,752 à la place pour p, car tout ce qui est au-dessus enverra les pics sur 1 (écrêtage).
Invité le

7

Commencez avec un polynôme paramétré de 5ème ordre de symétrie étrange sinon général :

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

Nous plaçons maintenant quelques contraintes sur cette fonction. L'amplitude doit être de 1 aux pics, c'est-à-dire f(1)=1 . Substituer 1 à x donne:

(1)a0+a1+a2=1

Voilà une contrainte. La pente aux pics doit être nulle, c'est-à-dire f(1)=0 . La dérivée de f(x) est

a0+3a1x2+5a2x4

et substituer 1 à x donne notre deuxième contrainte:

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

Maintenant , nous pouvons utiliser nos deux contraintes à résoudre pour a1 et a2 en termes d' a0 .

(3)a1=522a0a2=a032

Il ne reste plus qu'à modifier a0 pour obtenir un bon ajustement. Soit dit en passant, a0 (et la pente à l'origine) finit par être π2 , comme nous pouvons le voir sur untracéde la fonction.

Optimisation des paramètres

Voici quelques optimisations des coefficients, qui se traduisent par ces amplitudes relatives des harmoniques par rapport à la fréquence fondamentale (1ère harmonique):

Comparison of approximations

Dans la série complexe de Fourier :

k=ckei2πPkx,

d'un véritable P- forme d' onde périodique avec P=4 et la symétrie de temps environ x=1 et d'une demi - période définie par fonction impaire f(x) au-dessus de 1x1, le coefficient de la kth exponentielle complexe harmonique est la suivante :

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

En raison de la relation 2cos(x)=eix+eix (voir: formule d'Euler ), l'amplitude d'une harmonique sinusoïdale réelle avec k>0 est 2|ck|, qui est le double de la grandeur de l'exponentielle complexe de la même fréquence. Cela peut être massé sous une forme qui permet à certains logiciels de mathématiques symboliques de simplifier l'intégrale plus facilement:

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

Ceci est une variation de la réponse de Robert, et c'est la voie que j'ai finalement empruntée. Je le laisse ici au cas où cela aiderait quelqu'un d'autre.
Invité du

wow, le résoudre analytiquement. j'aurais juste utilisé MATLAB et une FFT et sorta pour trouver la réponse.
tu as très bien fait.
robert bristow-johnson

2
en fait @OlliNiemitalo, je pense que -79 dB est assez bon pour la mise en œuvre d'un oscillateur à onde sinusoïdale de synthé numérique. il peut être entraîné par une onde triangulaire, qui est générée facilement à partir de la valeur abs d'une dent de scie, qui est plus facilement générée avec un accumulateur de phase à virgule fixe.
personne n'entendra de différence entre cette onde sinusoïdale polynomiale du 5e ordre et un sinus pur.
robert bristow-johnson

1
Polynômes en général comme Font l'avantage qu'en augmentant la commande, l'erreur peut être rendue arbitrairement petite. Les fonctions rationnelles ont le même avantage, mais une division est généralement plus coûteuse à calculer que la multiplication. Par exemple, dans Intel i7, un seul thread peut effectuer 7 à 27 fois plus de multiplications et d'ajouts que de divisions en même temps. Approximation d'une alternativeFsignifie la décomposer en opérations élémentaires, généralement des multiplications et des ajouts qui équivalent toujours à des polynômes. Ceux-ci pourraient être optimisés pour approximer le sinus directement par rapport à viaF.
Olli Niemitalo

1
@OlliNiemitalo, je vois ce que tu veux dire ... si la division est beaucoup plus lente que la multiplication (et je suppose que des choses comme les racines / exposants fractionnaires seront encore pires), alors une approche comme la précédente avec un "bon, rapide" F0"va finir par prendre en compte un polynôme de type Taylor de toute façon. Je suppose que puisque c'est une approximation de toute façon, une sorte d'approximation de racine bon marché pourrait potentiellement dépasser l'approche polynomiale à un certain niveau de précision, mais c'est un peu différent dans les mauvaises herbes pour ce qui était essentiellement censé être une question de mathématiques.
Invité du

5

Vous le demandez pour des raisons théoriques ou pour une application pratique?

Habituellement, lorsque vous avez une fonction coûteuse à calculer sur une plage finie, la meilleure réponse est un ensemble de tables de recherche.

Une approche consiste à utiliser les paraboles les mieux adaptées:

n = étage (x * N + .5);

d = x * N - n;

i = n + N / 2;

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

En trouvant la parabole à chaque point qui correspond aux valeurs de d étant -1/2, 0 et 1/2, plutôt que d'utiliser les dérivées à 0, vous garantissez une approximation continue. Vous pouvez également décaler la valeur x, plutôt que l'index du tableau pour gérer vos valeurs x négatives.

Ced

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

Suivre:

La quantité d'efforts et les résultats qui ont permis de trouver de bonnes approximations sont très impressionnants. J'étais curieux de savoir comment ma solution parabolique ennuyeuse et fade se comparerait. Sans surprise, il fait beaucoup mieux. Voici les résultats:

   Méthode Minimum Maximum Mean RMS
  -------- -------- -------- -------- --------
     Puissance -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

Les valeurs représentent 1000x l'erreur entre l'approximation et la valeur réelle évaluée tous les .0001 sur une échelle de 0 à 1 (inclus), donc 10001 points en tout. L'échelle est convertie pour évaluer les fonctions de 0 àπ/2, à l'exception des équations d'Olli Niemitalo qui utilisent l'échelle 0 à 1. Les valeurs des colonnes doivent être claires dans les en-têtes. Les résultats ne changent pas avec un espacement de 0,001.

La ligne "Power" est l'équation: X-Xe6.

La ligne rbj 5 est la même que la solution c5 de Matt L.

Les 16, 32 et 64 sont le nombre d'intervalles qui ont des ajustements paraboliques. Bien sûr, il y a des discontinuités insignifiantes dans la dérivée première à chaque frontière d'intervalle. Les valeurs de la fonction sont cependant continues. L'augmentation du nombre d'intervalles ne fait qu'augmenter les besoins en mémoire (et le temps d'initialisation), elle n'augmente pas la quantité de calcul nécessaire pour l'approximation, qui est inférieure à toutes les autres équations. J'ai choisi deux puissances car une implémentation en virgule fixe pourrait sauver une division en utilisant un ET dans de tels cas. De plus, je ne voulais pas que le dénombrement soit proportionnel à l'échantillonnage d'essai.

J'ai exécuté le programme python d'Olli Niemitalo et j'ai obtenu ceci dans le cadre de l'impression: "Solution candidate 176 sur 120" Je pensais que c'était étrange, donc je le mentionne.

Si quelqu'un veut que j'inclue l'une des autres équations, veuillez me le faire savoir dans les commentaires.

Voici le code pour les approximations paraboliques par morceaux. L'ensemble du programme de test est trop long pour être publié.

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

# y = ad ^ 2 + bd + 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

# ---- Calculer les tableaux de recherche

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

        theL0 = zéros (argPieceCount)
        theL1 = zéros (argPieceCount)
        theL2 = zéros (argPieceCount)

        pour k dans la plage (0, argPieceCount):
         x = float (k) * theStep

         ym = sin (x - la moitié)
         y = sin (x)
         yp = sin (x + la moitié)

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

# ---- Faites le plein

        theN = len (argArray)

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

        pour i dans la plage (0, theN):
         x = float (i) * theFactor

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

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

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

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

Appendice

J'ai inclus Guest's S3fonction du message d'origine comme "OP S_3" et formule de deux paramètres de l'invité des commentaires comme "Ratio". Les deux sont sur une échelle de 0 à 1. Je ne pense pas que le ratio soit adapté au calcul lors de l'exécution ou à la création d'une table de recherche. Après tout, c'est beaucoup plus de calcul pour le CPU qu'un simple appel sin (). C'est intéressant mathématiquement cependant.


Bon travail! J'ai corrigé ce bogue ("176 sur 120").
Olli Niemitalo

Belle mise à jour, cela a plus de sens pour moi maintenant. leX-Xe6 n'a probablement pas besoin d'être testé, je l'ai juste jeté là-bas parce que j'essayais de comprendre la signification de equi semblait continuer d'apparaître pendant que je jouais avec ça. Une meilleure expression rationnelle à tester pourrait ressembler à ceci:F0(X)=|X|unesigne(X) ; b=F0(1) ; F1(X)=F0(X)-bX ; c=1F1(1) ; F2(X)=F1(X)c ... maintenant une devrait être réglé sur environ 223...
Invité

...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.
Invité

Ou une version à 2 paramètres plus précise de cela, une0X-une1Xune0X+une1X semble assez bon avecune013 et une1dix9
Invité
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.