选择最佳样本集以近似具有预定数量样本的曲线?

时间:2013-10-23 18:47:37

标签: javascript c++ optimization statistics curve-fitting

背景

我有一个宠物项目,我喜欢不时地过度思考。该项目与RC飞机控制输入设备有关。熟悉这种爱好的人可能也熟悉所谓的“棒展”,这是RC发射器的一个共同特征,其中控制棒在中性中心位置附近或多或少敏感,并且变得越来越不敏感。棒越接近其最小值或最大值。

我读过一些我不太了解的论文。我显然没有数学背景来解决这个问题,所以我希望也许你们中的一个可能。

问题

我决定通过采用预定数量的样本来近似曲线,并使用线性插值来确定采样点之间任何输入值的输出值。 我正试图找到一种方法来确定最佳的样本点集。

如果你看一下这个应用程序的典型增长曲线的例子,你会发现有些部分更线性(更直),有些部分更不线性(更弯曲)。

typical curve example

这些样本彼此之间的距离相同,但并非必须如此。在有更多变化的情况下增加样本密度是明智的,从而通过借用直线段中的冗余点来增加曲线段中的分辨率。

是否可以量化错误程度?如果是,那么是否也可以确定给定函数的最佳样本集和预定数量的样本?

参考代码

使用预先计算的点集来近似输出值的类的片段。

/* This makes the following assumptions:
 *   1. The _points[] data member contians at least 2 defined Points.
 *   2. All defined Points have x and y values between MIN_VALUE and MAX_VALUE.
 *   3. The Points in the array are ordered by ascending values of x.
 */
int InterpolatedCurve::value( int x ) {
  if( _points[0].x >= x ) { return _points[0].y; }
  for( unsigned int i = 1; i < _point_count; i++ ) {
    if( _points[i].x >= x ) {
      return map(x, _points[i-1].x, _points[i].x,
                    _points[i-1].y, _points[i].y);
    }
  }
  // This is an error condition that is not otherwise reported.
  // It won't happen as long as the points are set up correctly.
  return x;
}

// Example map function (borrowed from Arduino site)
long map( long x, long x1, long x2, long y1, long y2 ) {
  return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
}

虽然我的项目实际上是用C ++编写的,但我在考虑这个问题的同时使用谷歌电子表格来制作一些数字。

// x: Input value between -1 and 1
// s: Scaling factor for curve between 0 (linear) and 1 (maximum curve)
// c: Tunable constant
function expo_fn( x, s, c ) {
  s = typeof s !== 'undefined' ? s : 1.0;
  c = typeof c !== 'undefined' ? c : 4.0;
  var k = c * ((c - 1.0) * s*s*s + s)/c + 1.0;
  return ((k - 1.0) * x*x*x*x*x + x)/k;
};

以下内容在输入值-1和1之间创建一组等距分布(非最佳)点。对于上面的示例电子表格,这些输出值扩展为-16383和16383之间的整数。因子是介于0和1之间的值,它决定了“曲线” - 零是平坦的线性曲线,1是我关注的最小线性曲线。

function Point( x, y ) {
  this.x = x;
  this.y = y;
};

function compute_points_iso( count, factor ) {
  var points = [];
  for( var i = 0; i < count; ++i ) {
    var x = 2.0/(count - 1.0) * i - 1.0;
    var y = expo_fn(x, factor);
    points.push(new Point(x,y));
  }
  return points;
};

相关学术工作

我一直在研究this paper描述选择重要数据点的算法,但我的程序还没有完全正常工作。如果我发现这件事,我会报告回来。

1 个答案:

答案 0 :(得分:1)

这里的关键是要意识到你可以根据函数的二阶导数约束线性插值的误差。即如果我们估计f(x) \approx f(x_0) + f'(x_0)*(x-x_0),则此近似值中的误差小于abs[ 0.5*f''(x_0)(x-x_0)^2 ]

迭代方法的大纲可能如下所示:

  1. 构建一个例如均匀间隔的网格
  2. 计算此网格上函数的二阶导数。
  3. 使用二阶导数和样本间间距
  4. 计算误差的界限
  5. 将错误较大的样本移到一起;在错误很小的地方将它们进一步分开。
  6. 我希望这是一个循环步骤2,3,4的迭代解决方案。

    大部分细节都在第4步。 对于固定数量的采样点,可以使用要选择的误差范围的中值 需要更精细/更粗略的采样(即,误差大于中值误差的那些位置将使采样点拉得更近)。

    E_0为误差范围的中位数;然后,对于该点中的每个样本,我们可以计算新的所需样本间距(dx')^2=2*E_0/f''(x);然后你需要一些逻辑来改变网格间距,使它更接近这些理想的间距。

    我的回答受到对数据使用“自组织映射”算法的影响;此或相关算法可能与您的问题相关。但是,我永远不记得了 看到像你这样的问题,其目标是让你的误差估计在整个网格中统一。