正弦波の多項式近似を見つける


16

Iは、で与えられる正弦波近似する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

これはおそらく私の目的には十分ですが、正弦波により近く、計算的に安価な別の関数が存在するかどうか疑問に思っています。上記の3つの要件を満たす関数を見つける方法についてはかなりよく理解していますが、それらの要件を満たし、正弦波に最も近い関数を見つける方法はわかりません。

正弦波を模倣する多項式を見つけるための方法はありますか(三角波に適用される場合)?


明確にするために、奇数対称の多項式だけを探しているわけではありませんが、それらは最も簡単な選択です。

次の関数のようなものも私のニーズに合う可能性があります。

S4(x)=3x2+x24+x44

これは負の範囲の要件を満たし、区分的なソリューションを使用して正の範囲にも適用できます。例えば

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

ここで、P符号付きべき関数ですです。

また、小数指数をサポートするために符号付きべき関数を使用するソリューションにも興味があります。これにより、別の係数を追加せずに別の「ツイストノブ」が得られます。

a0x +a1P(x, p1)

適切な定数が与えられると、5次または7次の多項式の重みがなくても、非常に高い精度が得られる可能性があります。ここでの要件を満たす実施例は、いくつかの手摘み定数を使用してここに記載されます:0 = 1 ¯ 6661 = - 0 ¯ 666P 1 = 2.5a0=1.666¯,a1=0.666¯,p1=2.5

5x2P(x, 52)3

実際、これらの定数は非常にπに近い、及び1-ππ2、およびE。それらを接続すると、正弦波に非常に近いものが得られます1π2e

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

別の言い方をすれば、は、0,0とπ/ 2,1の間でsinxに非常に近く見えます。これの重要性についての考えはありますか?Octaveのようなツールは、このアプローチに最適な定数を見つけるのに役立つかもしれません。xxe6sin(x)


1
それでは、「より近い」というエラー用語の定義は何ですか?私が知る限り、あなたが引用したテイラー級数は、有限数の係数に対して近似された最小L²エラーです。(私は思う。)
マーカスミュラー

2
ところで、あなたの目標は何ですか?なぜ多項式波形整形器を探しているのか、どのような技術的根拠に基づいているのか、そして近似の主な目的は何かを教えてくれると本当に助かります。
マーカスミュラー

@MarcusMüller正弦波と人間の耳とを区別できない場合、テイラー級数の精度をかなり安価なものに犠牲にするつもりです。テイラー級数近似のピークも気になります。リストした他の2つの関数よりも「近い」何かを見つけることに興味があります。より安くはならないだろうと思う。S2
ゲスト

1
ここでは、「人間の耳に」が重要です。繰り返しますが、なぜ / どのような目的で、どの制限の下でこれを行っているのかを教えてください。十分な背景がないと、質問が広すぎて適切に答えられません。
マーカスミュラー

1
なぜ三角波から始めているのですか?サインジェネレータは、シンプルで共通している、方形波は自明など、基本波にフィルタ処理されている
カール・Witthoft

回答:


10

約10年前、私は、名前のない音楽シンセサイザー会社のためにこれをやりました。(彼らが誰なのか想像できません。)私は係数を持っていません。

しかし、これを試してください:

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

これにより、f x = f x )が保証されます。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π

それが2番目の制約です。0を削除し方程式を解きます。(1)及び(2)2換算で1(調整するために残されています)。a0a2a1

a0=52π12a1

a2=12π12a1

今、あなたは1つの係数だけ、持っている1を、最高のパフォーマンスをひねり、左:a1

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

これは私がひねりような方法で1正弦波発振器用のための最高のパフォーマンスを。上記使用して、x = 1についての正弦波の対称性を調整しますa1x=1と 2のべき乗のポイント(たとえば、128、私は気にしない)でバッファーに正確に1サイクル全体を配置し、その上でFFTを実行します完璧なサイクル。

FFT結果ビン1はサインの強度になり、約ます。今、あなたは調整することができます1を上下あなたの第三高調波歪みをもたらすことに。私が開始すると15N/2a1となるよう01。これはFFT結果のビン3にありますが、5次高調波歪み(ビン5の値)は結果的です(3次高調波が下がると増加します)。5次高調波レベルの強度が3次高調波レベルと等しくなるよう1を調整ます。これは、1次高調波から約-70 dBになります(思い出します)。これは、安価な3係数の5次の奇数対称多項式からの最も美しい正弦波になります。a15π2a01a1

他の誰かがMATLABコードを書くことができます。それはどのように聞こえますか?


3次高調波が5次高調波と等しくなり、基本波(1次高調波)より約70 dB低くなるように、MATLABを実行して最適なを探す時間は絶対にありません。他の誰かがそれをする必要があります。ごめんなさい。a1
ロバートブリストージョンソン

すばらしい答え、まだそれを消化します。実際に、3係数、5次、奇数対称多項式である必要があるかどうか疑問に思い始めています...あなたのf '(x)は、実際にはf(x)であり、0を単位とする区分的取引でしょうか?大まかなスケッチはこちら。たぶん、これはセッドが念頭に置いているものですか?まだ皆さんに追いついています。
ゲスト

これは美しいアプローチです。代わりにFFTを取り、繰り返し解くあなたからサード5次チェビシェフ多項式を形成することができるのだろうか 2を同一視して解くため、その後、1f(x)a1
スピーディ

その「スケッチ」を投稿したとき、私は半分眠っていたに違いありません、私はこのようなことをするつもりでしたが、±1を通り抜けて傾きがゼロになるように修正しました(単に誘導体を取り、それをいじって、再び統合することができます)。5次以上の利点があるかどうかは定かではありませんが、私はまだ考慮していませんでした。
ゲスト

1
これは本当に素晴らしい解決策であり、少し時間がかかっただけです。正しいとマークしても、他の人がコードを書いたり書いたりするのを止めないことを願っています。
ゲスト

9

どのような通常行われているとすると、エラーのいくつかの規範、多くの場合、最小化近似である(最大誤差が最小化されている)ノルム、またはL 2(平均二乗誤差が最小化されている)ノルムを。L -approximationを使用して行われるのRemez交換アルゴリズムを。そのアルゴリズムを実装するオープンソースコードを見つけることができると確信しています。ただし、この場合、非常に単純な(離散的な)l 2最適化で十分だと思います。Matlab / Octaveのコードと結果を見てみましょう:LL2Ll2

x = linspace(0、pi / 2,300); [0、pi / 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次近似

ショーのための近似誤差下図 -orderとのための5 のT H近似-ORDER。最大近似誤差があると、それぞれ。3rd5th8.8869e-031.5519e-04

enter image description here

最適な係数は

c3 =
   0.988720369237930
  -0.144993929056091

そして

c5 =
   0.99976918199047515
  -0.16582163562776930
   0.00757183954143367

したがって、3次近似は

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

そして、5次近似は

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

編集:

質問で示唆されているように、符号付きべき関数を使って近似値を調べましたが、最良の近似値は上記の3次近似値よりも優れています。近似関数は

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

ここで、およびf π / 2 なるように定数が選択されましたf(0)=1。パワー pは、範囲 [ 0 π / 2 ]で最小の最大誤差を達成するために最適化されました。pの最適値は p = 2.774であることがわかりました。次の図は、3次近似1 および新しい近似3f(π/2)=0p[0,π/2]pp=2.774(1)(3)

enter image description here

最大近似近似の誤差であるが、三次近似のみにそのエラー近い超えることに注意π / 2と大部分の近似誤差が署名された電力機能のものよりも実際に小さくなります。(3)4.5e-3π/2

編集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コマンドを使用してそれらをプロットします。
マットL.

1
@Guest:そして、あなたから得る最大値max(abs(b-f3))max(abs(b-f5))
マットL.

@Guest:符号付きべき乗関数をいじりましたが、結果は以前の3次近似よりも大幅に良くありません。編集した回答をご覧ください。複雑さに関して、それはそのような大きな違いを生むでしょうか?
マットL.

それを見てくれてありがとう。複雑さは大した問題ではなく、比較的低い複雑さで近似がどれほど正確かを知りたいだけです。どのように(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でなければなりませんf(1)=1xに1を代入すると、次のようになります。x

(1)a0+a1+a2=1

それが一つの制約です。ピークの勾配はゼロ、つまりf(1)=0なければなりません。f(x)の導関数は

a0+3a1x2+5a2x4

xに1を代入すると、2番目の制約が与えられます。x

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

今、私たちは私たちのために2つの制約を使用することができます解決のための12の条件で0a1a2a0

(3)a1=522a0a2=a032

あとはa0を微調整するだけです。なお、0(原点での傾き)がなってしまうπa0π2、関数のプロットからわかるように。

パラメータの最適化

以下は、基本周波数(1次高調波)と比較した高調波のこれらの相対的な振幅をもたらす係数の最適化の数です。

Comparison of approximations

複素フーリエ級数の場合

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

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.
robert bristow-johnson

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.