我正在尝试将高振荡数据与来自python中的GSL Scientific Library和pygsl的函数 qawo 集成。因为我正在处理数据我虽然插值函数可以工作,但GSL给我一个不正确的结果 !! 。让我以函数 Sin(x)/(1 +x²)为例进行解释。
以下代码可以正常使用:
import pygsl
from pygsl import integrate
def f1(x,y):
return 1./(1 + x**2)
sys = integrate.gsl_function(f1, None)
w = integrate.workspace(100)
cyclew = integrate.workspace(1000000)
table = integrate.qawo_table(1, 10000, integrate.SINE, 100)
flag, result, error = integrate.qawo(sys, 0, 1e-8, 1e-8, 100, w, table)
应该给出 0.626761 。但是,如果我们使用上述函数模拟数据点......
xarr = np.linspace(0,1e15,1e30)
yarr = np.sin(xarr)/(1.+xarr**2)
interp = interpol.interp1d(xarr,yarr)
def fgsl(x,y):
return interp(x)
syst = integrate.gsl_function(fgsl, None)
w = integrate.workspace(1000)
cyclew = integrate.workspace(100000000)
table = integrate.qawo_table(1, 1e10, integrate.SINE, 100)
flag, result, error = integrate.qawo(syst, 0, 1e-15, 1e-15, 100, w, table)
给出了完全错误的结果: 4.2426e-21
此外,如果我们将 yarr 与 simps 功能集成在一起:
import scipy.integrate as ints
res = ints.simps(yarr,xarr)
给出了一个非常好的近似值: 0.64676099 。
假设我不能使用辛普森的规则。有谁知道如何使用gsl的插值函数?或者我如何更改代码以进行集成?
提前致谢。
答案 0 :(得分:3)
您的示例中的数字不太合理,它们将破坏任何自适应方案。让我解释一下原因。
您正在尝试将振荡函数与0到10 ^ 10的周期2 * Pi进行整合!没有自适应方案能够“看到”该区间的振荡行为,它们会收敛到错误的结果(错误的收敛)!请记住,自适应方案使用自上而下的方法。它们对整个区间应用一些规则,然后将该区间划分为两个,并在每个细分中应用相同的规则。在几个周期(通常是4或5)之后,该方案通过比较连续步骤中的部分结果来开始检查收敛。在您的示例中,该方案将需要大量细分以最终查看振荡行为,这是可能发生错误收敛的典型情况!
如何在开放区间(a,\infinity)
上集成振荡函数? qawf integral整合方案的解释非常完整。将函数集成在仅包含少量振荡的子区间上,并检查结果如何收敛 - 然后推断出来!
还有其他数字不太合理。为什么你需要在每dx = 1e-15时对sin(x)/(1 + x ^ 2)进行采样?任何合理的自适应方案都可以将sin(x)从0到2Pi w / ~10-20个采样点进行积分。
Simpson的规则没有失败,因为它不是一个自适应方案。 python代码将根据您提供的x-array确定'dx',它将使用该dx一直到1e10!但是我很确定您的代码中的舍入错误非常糟糕,因为您选择了dx~1e-15。
编辑1第一部分:实际上问题不仅仅是由被积函数的振荡行为引起的。假设包络1 / x ^ 2收敛得非常快 - 如果x>> 1,则函数几乎为零。因此,因为您正在将这个包络集成在巨大的区间[0,1e10]中,所以自适应积分认为结果非常小,因为它无法看到函数不可忽略的小(子)区间。 (你可能认为积分例程会在闭区间[0,1e10]中统一分布评估点 - 对高斯积分来说并不完全正确,但它很接近 - 所以其中一个点落入区间内的可能性很小〜[0,1e3]其中被积函数不可忽略的非常小。经过几次迭代后,积分程序将得到积分接近于零。
编辑1第二部分:我仍然认为(在阅读你的评论之后)问题是你插入的数字(或者python包装器有一个错误。)。请像我在下面的C ++代码中那样尝试使用合理数字的示例
int main()
{
const double omega = 1;
auto g = [](double x)->double {return 1.0/(1.+x*x);};
auto f = [&](double x)->double {return std::sin( omega * x) * g(x);};
const int points_per_cycle = 20;
const int n_cycles = 10;
const int size = n_cycles * points_per_cycle + 1;
const double xmin = 0.0;
const double xmax = n_cycles * (2 * M_PI);
const double L = xmax-xmin;
std::vector<double> x(size);
std::vector<double> y(size);
for (int i = 0; i <size; ++i) {
x[i] = i * L/(size-1);
y[i] = f(x[i]);
}
std::cout.precision(8);
// interpolation
InterpolationGSL<std::vector<double>> GSLinterpol(x, y, GSLIT::cspline, false);
// Integral of the interpolation
std::cout << GSLinterpol.If((1+1e-12)*xmin, (1-1e-12)*xmax) << std::endl;
// SECOND GSL INTEGRATION
gsl_integration_workspace* w = gsl_integration_workspace_alloc (1000);
gsl_integration_qawo_table* wf = gsl_integration_qawo_table_alloc
(omega, L, GSL_INTEG_SINE, 1000);
int status = gsl_integration_qawo_table_set (wf, omega, L, GSL_INTEG_SINE);
if(status) std::cerr<< "error: " << std::string(gsl_strerror (status)) << std::endl;
double result;
double abserr;
std::function<double(double)> gg( std::cref(g) );
GslFunction Fp(gg);
gsl_function *Fgsl = static_cast<gsl_function*>(&Fp);
status = gsl_integration_qawo (Fgsl, xmin, 0.0, 1e-5, 1000, w, wf, &result, &abserr);
if(status) std::cerr<< "error: " << std::string(gsl_strerror (status)) << std::endl;
std::cout << result << std::endl;
return 0;
}
此代码使用我的gsl_function和interpolation包装器 - 因此您可能会发现代码有点奇怪 - 但重要的是它评估您在合理的时间间隔内提到的相同积分和结果是
Interpolation integral: 0.64631754
GSL integral: 0.64650827