3

我正在尝试用非均匀屏幕点的特定分布填充向量。这些点代表屏幕上的某个 x 和 y 位置。在某个时候,我将在屏幕上绘制所有这些点,它们应该不均匀地分布在中心。基本上,当您靠近中心时,点的频率应该增加,屏幕的一侧是另一侧的反射(可以“在屏幕中心进行镜像”)

我正在考虑使用某种公式(例如 -pi/2 和 pi/2 之间的y=cos(x)),其中得到的 y 将等于屏幕该区域中点的频率(其中 -pi/2将是屏幕的最左侧,反之亦然),但我被困在如何在创建点放在矢量上时应用这样的东西。注意:必须生成特定数量的点

如果上面的假设不能工作,也许实现这一点的一种欺骗方法是不断减少每个点之间的一些步长,但我不知道我如何能够确保具体的点数达到中央。

前任。

// this is a member function inside a class PointList
// where we fill a member variable list(vector) with nonuniform data
void PointList::FillListNonUniform(const int numPoints, const int numPerPoint)
{
    double step = 2;
    double decelerator = 0.01;

    // Do half the screen then duplicate and reverse the sign
    // so both sides of the screen mirror eachother
    for (int i = 0; i < numPoints / 2; i++)
    {
        Eigen::Vector2d newData(step, 0);
        for (int j = 0; j < numPerPoint; j++)
        {
            list.push_back(newData);
        }
        decelerator += 0.01f;
        step -= 0.05f + decelerator;
    }

    // Do whatever I need to, to mirror the points ...
}

从字面上看,任何帮助将不胜感激。我曾简要研究过 std::normal_distribution,但在我看来它依赖于随机性,所以我不确定这是否是我想做的一个好的选择。

4

2 回答 2

3

您可以使用一种称为拒绝抽样的方法。这个想法是你有一些参数的函数(在你的例子中是 2 个参数x, y),它代表概率密度函数。在您的 2D 案例中,您可以生成一个x,y对以及一个表示概率 的变量p。如果坐标(即 )处的概率密度函数较大,f(x, y) > p则添加样本,否则生成新的对。您可以像这样实现:

#include <functional>
#include <vector>
#include <utility>
#include <random>

std::vector<std::pair<double,double>> getDist(int num){

    std::random_device rd{};
    std::mt19937 gen{rd()};

    auto pdf = [] (double x, double y) {
        return /* Some probability density function */;
    };

    std::vector<std::pair<double,double>> ret;
    
    double x,y,p;

    while(ret.size() <= num){
        x = (double)gen()/SOME_CONST_FOR_X;
        y = (double)gen()/SOME_CONST_FOR_Y;
        p = (double)gen()/SOME_CONST_FOR_P;

        if(pdf(x,y) > p) ret.push_back({x,y});
    }
    return ret;
}

这是一个非常粗略的草案,但应该给出关于它如何工作的想法。

另一个选项(如果您想要正态分布)是std::normal_distribution. 参考页面中的示例可以修改为:

#include <random>
#include <vector>
#include <utility>

std::vector<std::pair<double,double>> getDist(int num){

    std::random_device rd{};
    std::mt19937 gen{rd()};

    std::normal_distribution<> d_x{x_center,x_std};
    std::normal_distribution<> d_y{y_center,y_std};
 
    while(ret.size() <= num){
        ret.push_back({d_x(gen),d_y(gen)});
    }

}
于 2021-07-31T19:16:03.723 回答
2

有多种方法可以解决此问题,具体取决于您想要的确切分布。一般来说,如果你有一个分布函数 f(x),它给出了一个点到中心特定距离处的概率,那么你可以将它积分得到累积分布函数F(x)。如果可以反转 CDF,则可以使用逆 CDF将均匀随机变量映射到距中心的距离,从而获得所需的分布。但并非所有功能都可以轻松反转。

另一种选择是稍微伪造它:例如,制作一个从 0 到距中心最大距离的循环,然后对于每个距离,您使用概率函数来获得该距离处的预期点数。然后只需以随机选择的角度添加那么多点。这是相当快的,结果可能已经足够好了。

Lala5th 提到的拒绝采样是另一种选择,它可以为您提供所需的分布,但如果屏幕的大部分区域概率非常低,则可能需要很长时间。确保它在有限时间内完成的一种方法是在添加点之前不循环num,而是循环遍历每个像素,并添加该像素的坐标 if pdf(x,y) > p。这样做的缺点是你不会得到确切的num分数。

于 2021-07-31T19:25:18.883 回答