Método para integração numérica da integral oscilatória difícil

25

Preciso avaliar numericamente a integral abaixo:

0sinc(xr)rE(r)dr

onde , e . Aqui é a função de Bessel modificada do segundo tipo. No meu caso particular, tenho , e .xR+λ,κ,ν>0Kλ=0,00313κ=0,00825ν=0,33E(r)=r4(λκ2+r2)ν5/2Kν5/2(λκ2+r2)xR+λ,κ,ν>0Kλ=0.00313κ=0.00825ν=0.33

Estou usando o MATLAB e tentei as funções internas integrale quadgk, o que me deu muitos erros (veja abaixo). Naturalmente, tentei várias outras coisas, como integrar por partes e somar integrais de a .( k + 1 ) x πkxπ(k+1)xπ

Então, você tem alguma sugestão sobre qual método devo tentar a seguir?

ATUALIZAÇÃO (perguntas adicionadas)
Li o artigo @Pedro vinculado e não acho que seja muito difícil de entender. No entanto, tenho algumas perguntas:

  • Seria bom usar como os elementos base , no método univariado de Levin descrito?ψ kxkψk
  • Em vez disso, eu poderia apenas usar um método Filon, já que a frequência das oscilações é fixa?

Código de exemplo
>> integral(@(r) sin(x*r).*sqrt(E(r)),0,Inf)
Warning: Reached the limit on the maximum number of intervals in use. Approximate
bound on error is 1.6e+07. The integral may not exist, or it may be difficult to
approximate numerically to the requested accuracy.
> In funfun\private\integralCalc>iterateScalarValued at 372
In funfun\private\integralCalc>vadapt at 133
In funfun\private\integralCalc at 84
In integral at 89

ans =

3.3197e+06

torbonde
fonte
O que é na sua integral? x
Pedro
Qualquer número positivo e real. Acabei de atualizar minha postagem.
torbonde
Se você puder mostrar algum código e erros, provavelmente não será muito difícil resolver a maioria deles. Obviamente, tente ler o erro cuidadosamente primeiro e veja se você pode desaparecer por conta própria.
Dennis Jaheruddin
Farei um comentário ainda hoje com alguns códigos e erros. Ou amanhã.
precisa saber é o seguinte
Ok, então eu esqueci. Mas agora atualizei minha postagem com um exemplo (dividi a integral em duas calculando explicitamente). sinc
torbonde

Respostas:

12

Eu escrevi meu próprio integrador, quadccque lida substancialmente melhor do que os integradores Matlab com singularidades e fornece uma estimativa de erro mais confiável.

Para usá-lo para o seu problema, fiz o seguinte:

>> lambda = 0.00313; kappa = 0.00825; nu = 0.33;
>> x = 10;
>> E = @(r) r.^4.*(lambda*sqrt(kappa^2 + r.^2)).^(-nu-5/2) .* besselk(-nu-5/2,lambda*sqrt(kappa^2 + r.^2));
>> sincp = @(x) cos(x)./x - sin(x)./x.^2;
>> f = @(r) sincp(x*r) .* r .* sqrt( E(r) );

A função fagora é seu integrando. Observe que eu acabei de atribuir qualquer valor antigo a x.

Para integrar em um domínio infinito, aplico uma substituição de variáveis:

>> g = @(x) f ( tan ( pi / 2 * x ) ) .* ( 1 + tan ( pi * x / 2 ).^2 ) * pi / 2;

isto é, integrar gde 0 a 1 deve ser o mesmo que integrar fde 0 a . Transformações diferentes podem produzir resultados de qualidade diferentes: matematicamente todas as transformações devem fornecer o mesmo resultado, mas transformações diferentes podem produzir s mais suaves ou mais facilmente integráveis .g

Então chamo meu próprio integrador, quadccque pode lidar com os NaNdois lados:

>> [ int , err , npoints ] = quadcc( g , 0 , 1 , 1e-6 )
int =
  -1.9552e+06
err =
   1.6933e+07
npoints =
       20761

Observe que a estimativa de erro é enorme, ou seja quadcc, não tem muita confiança nos resultados. Olhando para a função, porém, isso não é surpreendente, pois oscila em valores três ordens de grandeza acima da integral real. Novamente, o uso de uma transformação de intervalo diferente pode produzir melhores resultados.

Você também pode querer procurar métodos mais específicos como esse . É um pouco mais envolvido, mas definitivamente o método certo para esse tipo de problema.

Pedro
fonte
Muito obrigado. Vou dar uma olhada nos diferentes métodos. Para meus propósitos, o erro não precisa ser tão pequeno quanto o padrão na eq integral(1e-10 eu acho), mas 1,7e + 07 ainda é muito, muito grande. Talvez outra transformação faça o bem, como você mencionou.
torbonde
@ cimrg.joe: Observe que a estimativa de erro é uma estimativa do erro absoluto com base, entre outros, nos valores absolutos máximos do integrando. Em alguns casos extremos, o valor retornado pode realmente estar bem. Se você está procurando dez dígitos de precisão, é altamente recomendável usar os métodos do tipo Levin que mencionei no final da minha postagem.
Pedro
Talvez eu não precise de dez dígitos de precisão, mas acho que preciso de pelo menos cinco. Seu método pode produzir isso?
torbonde
O método não pode garantir esse tipo de precisão para sua integral, uma vez que os valores na extremidade direita do intervalo são várias ordens de magnitude maiores que a própria integral.
Pedro
11

Como aponta Pedro, os métodos do tipo Levin são os melhores métodos estabelecidos para esse tipo de problema.

Você tem acesso ao Mathematica? Para esse problema, o Mathematica irá detectá-los e usá-los por padrão:

In[1]:= e[r_] := 
 r^4 (l Sqrt[k^2 + r^2])^(-v - 5/2) BesselK[-v - 5/2, l Sqrt[k^2 + r^2]]

In[2]:= {l, k, v} = {0.00313, 0.00825, 0.33};

In[3]:= Block[{x = 10}, 
 NIntegrate[Sinc'[x r] r Sqrt[e[r]], {r, 0, \[Infinity]}, 
  PrecisionGoal -> 3]]

Out[3]= -112494.

Aqui está um gráfico sobre uma faixa de valores de x:

In[4]:= ListLinePlot[
 Table[NIntegrate[Sinc'[x r] r Sqrt[e[r]], {r, 0, \[Infinity]}, 
   PrecisionGoal -> 3], {x, .5, 10, 0.1}]]

Traçar de x = 0,5 ex = 10

Você também pode especificar manualmente o método do tipo Levin específico a ser aplicado, que nesse caso pode resultar em uma ligeira melhoria no desempenho:

In[5]:= method = {"LevinRule", "Kernel" -> {Cos[r x], Sin[r x]}, 
   "DifferentialMatrix" -> {{0, -x}, {x, 0}}, 
   "Amplitude" -> {(
     3497.878840962873` Sqrt[(
      r^4 BesselK[-2.17`, 
        0.00313` Sqrt[
         0.00006806250000000001` + r^2]])/(0.00006806250000000001` + 
        r^2)^1.415`])/
     x, -((3497.878840962873` Sqrt[(
       r^4 BesselK[-2.17`, 
         0.00313` Sqrt[
          0.00006806250000000001` + r^2]])/(0.00006806250000000001` + 
         r^2)^1.415`])/(r x^2))}, "AdditiveTerm" -> 0};

In[6]:= Block[{x = 10}, 
 NIntegrate[Sinc'[x r] r Sqrt[e[r]], {r, 0, \[Infinity]}, 
  PrecisionGoal -> 3, Method -> method]]

Out[6]= -112495.

Consulte a documentação para obter detalhes dos métodos do tipo Levin no Mathematica .

Andrew Moylan
fonte
Infelizmente não tenho acesso ao Mathematica - apenas ao MATLAB. Vou atualizar minha pergunta com algumas perguntas adicionais, relacionadas ao artigo @Pedro vinculado.
torbonde
OK, como você diz, terá que se contentar com o Matlab. Vou acrescentar outra resposta sobre isso.
Andrew Moylan
5

Se você não tem acesso ao Mathematica, você pode escrever um método do tipo Levin (ou outro oscilador especializado) no Matlab, como Pedro sugere.

Você usa a biblioteca chebfun para o Matlab? Acabei de aprender que ele contém uma implementação de um método básico do tipo Levin aqui . A implementação foi escrita por Olver (um dos especialistas no campo da quadratura oscilatória). Não lida com singularidades, subdivisões adaptativas, etc., mas pode ser exatamente o que você precisa para começar.

Andrew Moylan
fonte
Pensei em implementar um método Levin, mas ainda não tenho certeza se estou pronto para o desafio. Eu acho que preciso entender o método um pouco melhor. Talvez eu possa falar com meu consultor sobre isso. Enfim, o motivo que perguntei sobre os métodos Filon é que eles parecem mais fáceis de implementar. E desde que eu não preciso de precisão extremamente elevada, mas isso é parte da minha tese de mestrado, dificuldade pesa.
torbonde
Eu dei uma olhada na biblioteca chebfun (que é impressionante) e no exemplo de integração Levin. Mas não consigo fazê-lo funcionar. Na verdade, eu postei uma pergunta sobre isso aqui .
torbonde
0

A transformação recomendada por Pedro é uma ótima idéia. Você tentou brincar com os parâmetros da função "quadgk" do Matlab? Por exemplo, usando a transformação de Pedro, você pode fazer o seguinte:
quadgk(f, 0.0+eps, 1.0-eps, 'AbsTol', eps, 'MaxIntervalCount', 100000)
Usar isso fornece uma solução de:
-2184689.50220729
e leva apenas 0,8 segundos (usando os valores mencionados acima: x = 10)
Walter Gander e Walter Gautschi têm um artigo sobre quadratura adaptativa com o Matlab código que você pode usar também (link aqui )

Joel Vroom
fonte