Valutazione numerica di integrale altamente oscillatorio


11

In questo corso avanzato sulle applicazioni della teoria delle funzioni complesse ad un certo punto di un esercizio l'integrale altamente oscillatorio

I(λ)=cos(λcosx)sinxxdX

deve essere approssimato per grandi valori di usando il metodo del punto a sella nel piano complesso.λ

A causa della sua natura altamente oscillatoria, questo integrale è molto difficile da valutare usando la maggior parte degli altri metodi. Questi sono due frammenti del grafico dell'integrando per a diverse scale:λ=10

cos (10 cos (x)) sin (x) / x

Un'approssimazione asintotica di ordine principale è

io1(λ)=cos(λ-14π)2πλ

e un ulteriore raffinamento (molto più piccolo) aggiunge il termine

io2(λ)=18peccato(λ-14π)2πλ3

Un grafico dei valori approssimati in funzione di il seguente aspetto:λ

I (lambda) ca.

Ora arriva la mia domanda: per vedere visivamente quanto è buona l'approssimazione, mi piacerebbe confrontarla con il "valore reale" dell'integrale, o più precisamente con una buona approssimazione allo stesso integrale usando un algoritmo indipendente. A causa della piccolezza della correzione subleading, mi aspetto che questo sia molto vicino.

Ho provato a valutare l'integrale per alcuni usando altri algoritmi, ma con scarso successo: Mathematica e Matlab usando l'integratore numerico predefinito non riescono a produrre un valore significativo (e lo riportano esplicitamente), mpmath usando entrambi il doppiamente esponenziale sostituzione e il metodo Gauss-Legendre producono risultati molto rumorosi, anche se ha una leggera tendenza a oscillare attorno ai valori forniti dal metodo del punto a sella, poiché questo grafico potrebbe mostrare:λtanh(sinh)

mpmath ca.

Alla fine ho tentato la fortuna con un integratore Monte-Carlo usando un esempio di importanza che ho implementato, ma non sono riuscito a ottenere risultati stabili.

Qualcuno ha un'idea di come questo integrale possa essere valutato indipendentemente per qualsiasi valore fisso di o giù di lì?λ>1


La funzione è pari?
Nicoguaro

Sì, è pari
doetoe

Hai provato a trasformare il tuo integrale in un ODE?
Nicoguaro

1
No, la differenziazione scrive e quindi risolve numericamente l'equazione differenziale. X
Nicoguaro

1
La tua prima trama sembra mostrare una funzione diversa rispetto al tuo integrando. Vale a dire, sembra che sostituito con λ x . Cioè la trama è della funzione x ( cos ( λ x cos x ) sinc x )λλXX(cos(λXcosX)sincX)
Ruslan

Risposte:


12

Usa il teorema di Plancherel per valutare questo integrale.

L'idea di base è quella per due funzioni f,g ,

io=-f(X)g*(X)dX=-F(K)sol*(K)dK

dove F,sol sono le trasformate di Fourier di f,g . Entrambe le funzioni hanno un supporto relativamente piccolo nel dominio spettrale. Qui peccatoX/Xrect(K) e cos(λcosX) dovrebbero avere una trasformata (o serie) analitica di Fourier, come l' espansione Jacobi-Anger . È possibile troncare le serie infinite a circa λ termini a causa del decadimento super-esponenziale della funzione di Bessel |Jn(X)|per n>|X|. Spero che questo ti aiuti.

Modifica : in realtà, dovresti usare le rappresentazioni della serie di Fourier qui invece delle trasformazioni. Il percorso di trasformazione porta a derivare la rappresentazione asintotica che hai già (risulta che questo è solo πJ0(λ) ). Il teorema di Plancherel sopra funziona anche per le serie di Fourier con un dominio di integrazione di [0,2π] sull'ultimo integrale.


Grazie, è un'ottima idea!
doetoe

7

La chiave per la valutazione degli integrali oscillatori è troncare l'integrale nel punto giusto. Per questo esempio devi scegliere il limite superiore della forma

πN+π2
Prima di spiegare perché dovrebbe funzionare, fammi prima dimostrare che in realtà produce buoni risultati.

asintotica

È facile indovinare che le serie asintotiche hanno la forma

I(λ)2πλ[cos(λπ4)+c1sin(λπ4)λ+c2cos(λπ4)λ2+c3sin(λπ4)λ3+]
c1=18

int := NIntegrate[Cos[l*Cos[x]]*Sinc[x], {x, 0, 20.5*Pi}]; 
Plot[{l*(Sqrt[2*l/Pi]*int - Cos[l-Pi/4]), Sin[l-Pi/4]/8}, {l, Pi/4, 20}]

Come risultato ottieni un bel seno che coincide con quello che hai derivato sopra.

18

Se vuoi trovare i seguenti coefficienti, un po 'più sofisticato pezzo di codice, se necessario. L'idea del codice seguente è quella di prendere diversi valori limite superiori e "mediare" i loro risultati.

J[l_?NumericQ] := Block[{n=500},
  f[k_] := NIntegrate[Cos[l*Cos[x]]*Sinc[x], {x,0,(n+k)*Pi+Pi/2},
  Method->{"DoubleExponential"}, AccuracyGoal->14, MaxRecursion->100];
  1/2*((f[0]+f[1])/2+(f[1]+f[2])/2)
]
t = Table[{l, l^2*(Sqrt[2*l/Pi]*J[l] - Cos[l-Pi/4] - 1/8*Sin[l-Pi/4]/l)}, 
    {l, 4*Pi+Pi/4, 12*Pi+Pi/4, Pi/36}];
Fit[t, Table[Cos[l-Pi/4+Pi/2*n]/l^n, {n, 0, 10}], l]

c2=-9128,c3=-751024,c4=367532768,...

Spiegazione

Semplice esempio

S(X)=0Xpeccato(y)ydy.
S()=π2

seno

S(X)

SN=Σn=1N(-1)nn.
SSN+12(-1)N+1N+1.
S(X)0πN+π2peccatoXXdX
max|S'(X)|si verifica.

Il tuo problema

ioX0(λ)=20X0cos(λcos(X))sinc(X)dX
X0=πN+π2λ=12π

tab = Table[{x0, 2*NIntegrate[Cos[12*Pi*Cos[x]]*Sinc[x], {x, 0, x0}, 
     Method->{"DoubleExponential"}, AccuracyGoal->12, MaxRecursion->100]},
    {x0, 10*Pi+Pi/2, 30*Pi+Pi/2, Pi}];
tab1 = Table[(tab[[i]] + tab[[i+1]])/2, {i,1,Length[tab]-1}];
ListPlot[{tab, tab1}]

acc

SN'=12(SN+SN+1)
SN'


Bello! Gli istruttori del corso sono i tuoi professori nella vita reale? Il loro corso è fantastico, anche se molto duro e frenetico
doetoe

@doetoe sì, sono uno studente di Konstantin. Ha condiviso con me un link alla tua domanda.
David Saykin,

6

Il metodo di Ooura per integrali sinusoidali di Fourier funziona qui, vedi:

Ooura, Takuya e Masatake Mori, una solida formula esponenziale doppia per integrali di tipo Fourier. Rivista di matematica computazionale e applicata 112.1-2 (1999): 229-241.

Ho scritto un'implementazione di questo algoritmo ma non ho mai lavorato per ottenerlo velocemente (ad esempio, memorizzando nodi / pesi nella cache), ma sto comunque ottenendo risultati coerenti in tutto ciò che va oltre la precisione del float:

float     = 0.0154244
double    = 0.943661538060268
long dbl  = 0.943661538066058702
quad      = 0.943661538066060288748574485677942
oct       = 0.943661538066060288748574485680878906503533004997613278231689169604876
asymptotic= 0.944029734

Ecco il codice:

#include <iostream>
#include <boost/math/quadrature/ooura_fourier_integrals.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/float128.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>

template<class Real>
Real asymptotic(Real lambda) {
    using std::sin;
    using std::cos;
    using boost::math::constants::pi;
    Real I1 = cos(lambda - pi<Real>()/4)*sqrt(2*pi<Real>()/lambda);
    Real I2 = sin(lambda - pi<Real>()/4)*sqrt(2*pi<Real>()/(lambda*lambda*lambda))/8;
    return I1 + I2;
}

template<class Real>
Real osc(Real lambda) {
    using std::cos;
    using boost::math::quadrature::ooura_fourier_sin;
    auto f = [&lambda](Real x)->Real { return cos(lambda*cos(x))/x; };
    Real omega = 1;
    Real Is = ooura_fourier_sin<decltype(f), Real>(f, omega);
    return 2*Is;
}

template<class Real>
void print(Real val) {
   std::cout << std::defaultfloat;
   std::cout << std::setprecision(std::numeric_limits<Real>::digits10);
   std::cout <<  val <<  " = " << std::hexfloat << val;
}

int main() {
    using boost::multiprecision::float128;
    float128  s = 7;
    std::cout << "Asymptotic = " << std::setprecision(std::numeric_limits<float128>::digits10) << asymptotic(s) << "\n";
    std::cout << "float precision = ";
    print(osc(7.0f));
    std::cout << "\n";
    std::cout << "double precision= ";
    print(osc(7.0));
    std::cout << "\n";
    std::cout << "long double     = ";
    print(osc(7.0L));
    std::cout << "\n";
    print(osc(s));

    print(osc(boost::multiprecision::cpp_bin_float_oct(7)));
    std::cout << "\n";
}

λ0inserisci qui la descrizione dell'immagine


Grazie, è davvero bello! Non l'ho ancora fatto funzionare, la mia installazione boost non è compatibile, ma sto scaricando l'ultima versione ora.
doetoe

Giusto per essere sicuri: in 23 hai cos (lambda * cos (x)) / x, senza il fattore sin (x) dall'integrando. È ooura_fourier_sin che assume questo fattore sin (x) per moltiplicare l'integrand passato ad esso?
doetoe

L'ho fatto funzionare. Lui e le sue dipendenze sembrano essere solo intestazione, quindi non ho nemmeno dovuto installare o compilare (tranne l'eseguibile). Spero che venga incluso nel boost!
doetoe

peccato(X)

@doetoe: è unito a Boost 1.71. L'API è leggermente diversa da quella fornita da questa risposta.
user14717
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.