精华内容
下载资源
问答
  • 摘要:为DSP控制的功率因数校正(PFC)变换器提出了一种新颖的采样算法,它能够很好地消除PFC电路中高频开关动作产生的振荡对数字采样的影响。尤其是当开关频率高于30kHz时,所提出的新颖采样算法能够更好地提高开关...
  • 泊松分布采样算法(Fast Poisson Disc Sampling) 前(fei)言(hua) 最近在看一些随机地图生成算法,涉及到生成Voronoi图,这需要提前在一个平面内随机生成一堆的点,这些点还要满足随机而且尽量平均分布在平面上。...

    快速泊松碟采样算法实现(Fast Poisson Disc Sampling)

    前(fei)言(hua)

    最近在看一些随机地图生成算法,涉及到生成Voronoi图,这需要提前在一个平面内随机生成一堆的点,这些点还要满足随机而且尽量均匀分布在平面上。一般文章都提到采用Lloyd Relaxation算法,不过这个算法比较复杂,消耗也比较大,后来看到这个快速泊松碟采样算法,也是用于生成一堆均匀分布的点的,而且算法复杂度在 O ( N ) O(N) O(N)
    算法的说明论文可以参考这里。个人觉得描述得很不(fan)清(ren)晰(lei),后来我看了别人的视频说明才真正了解这个算法,其实算法本身很简单,也很直观,下面会讲解下。完整代码我放在个人Github上。

    算法说明

    下面以2维平面为例:
    假设我们需要在一个宽高为 ( w i d t h , h e i g h t ) (width,height) (width,height)的平面内平均生成一堆的点,且这些点之间的距离不能小于 r r r
    我们可以先从平面内随机选一个点,然后在这个点附近随机找一些点,并判断这些点是否合法,合法的话则在这些点附近继续随机寻找,直到找不到合法点为止。

    算法简单说起来就是这样,下面详细说下细节。

    1. 为了保证能尽量填满整个平面, 随机找点时,采用与中心点距离为 [ r , 2 r ) [r,2r) [r,2r)的圆环内找,这个距离能保证找的点距离自身大于 r r r,且不会离得太远,能填满整个平面。
    2. 怎么判断一个点的附近已经找不到合法点了?算法定义了一个常量 k k k,对于每个点,我们尝试在它附近随机找 k k k次,如果都找不到,那么就认为这个点附近已经没有合法点。
    3. 怎么快速判定随机找出的点是否合法?这个是算法的关键,可以采用一些空间划分方法来做(游戏场景也会经常用到),首先将平面划分成 m m m n n n列的格子,每个格子都保存了格子内部的点。这样当我需要判断一个点是否合法时,我只要和附近的格子内的点做判断即可。
    4. 那怎么确定每个格子的大小?我们尽量让每个格子内部最多只能有1个点,这样数据结构就会简单很多。怎么做到呢?我们假设每个格子都是正方形,那正方形内部距离最远的点就是对角线的2个点,所以我们只要保证正方形的对角线长度大于等于 r r r,则正方形内部任意2个点之间的距离肯定小于 r r r,从而保证每个正方形内部肯定最多只能有1个点。假设正方形边长为 a a a,对角线长度为 r r r,那么有: a 2 + a 2 = r 2 a^2+a^2=r^2 a2+a2=r2,那么 a = r 2 a=\frac{r}{\sqrt{2}} a=2 r

    代码

    public static class Algorithm
    {
        public static List<Vector2> Sample2D(float width, float height, float r, int k = 30)
        {
            return Sample2D((int)DateTime.Now.Ticks, width, height, r, k);
        }
    
        public static List<Vector2> Sample2D(int seed, float width, float height, float r, int k = 30)
        {
            // STEP 0
    
            // 维度,平面就是2维
            var n = 2;
    
            // 计算出合理的cell大小
            // cell是一个正方形,为了保证每个cell内部不可能出现多个点,那么cell内的任意点最远距离不能大于r
            // 因为cell内最长的距离是对角线,假设对角线长度是r,那边长就是下面的cell_size
            var cell_size = r / Math.Sqrt(n);
    
            // 计算出有多少行列的cell
            var cols = (int)Math.Ceiling(width / cell_size);
            var rows = (int)Math.Ceiling(height / cell_size);
    
            // cells记录了所有合法的点
            var cells = new List<Vector2>();
    
            // grids记录了每个cell内的点在cells里的索引,-1表示没有点
            var grids = new int[rows, cols];
            for (var i = 0; i < rows; ++i) {
                for (var j = 0; j < cols; ++j) {
                    grids[i, j] = -1;
                }
            }
    
            // STEP 1
            var random = new Random(seed);
    
            // 随机选一个起始点
            var x0 = new Vector2(random.Range(width), random.Range(height));
            var col = (int)Math.Floor(x0.x / cell_size);
            var row = (int)Math.Floor(x0.y / cell_size);
    
            var x0_idx = cells.Count;
            cells.Add(x0);
            grids[row, col] = x0_idx;
    
            var active_list = new List<int>();
            active_list.Add(x0_idx);
    
            // STEP 2
            while (active_list.Count > 0) {
                // 随机选一个待处理的点xi
                var xi_idx = active_list[random.Range(active_list.Count)]; // 区间是[0,1),不用担心溢出。
                var xi = cells[xi_idx];
                var found = false;
    
                // 以xi为中点,随机找与xi距离在[r,2r)的点xk,并判断该点的合法性
                // 重复k次,如果都找不到,则把xi从active_list中去掉,认为xi附近已经没有合法点了
                for (var i = 0; i < k; ++i) {
                    var dir = random.insideUnitCircle();
                    var xk = xi + (dir.normalized * r + dir * r); // [r,2r)
                    if (xk.x < 0 || xk.x >= width || xk.y < 0 || xk.y >= height) {
                        continue;
                    }
    
                    col = (int)Math.Floor(xk.x / cell_size);
                    row = (int)Math.Floor(xk.y / cell_size);
    
                    if (grids[row, col] != -1) {
                        continue;
                    }
    
                    // 要判断xk的合法性,就是要判断附近有没有点与xk的距离小于r
                    // 由于cell的边长小于r,所以只测试xk所在的cell的九宫格是不够的(考虑xk正好处于cell的边缘的情况)
                    // 正确做法是以xk为中心,做一个边长为2r的正方形,测试这个正方形覆盖到的所有cell
                    var ok = true;
                    var min_r = (int)Math.Floor((xk.y - r) / cell_size);
                    var max_r = (int)Math.Floor((xk.y + r) / cell_size);
                    var min_c = (int)Math.Floor((xk.x - r) / cell_size);
                    var max_c = (int)Math.Floor((xk.x + r) / cell_size);
                    for (var or = min_r; or <= max_r; ++or) {
                        if (or < 0 || or >= rows) {
                            continue;
                        }
    
                        for (var oc = min_c; oc <= max_c; ++oc) {
                            if (oc < 0 || oc >= cols) {
                                continue;
                            }
    
                            var xj_idx = grids[or, oc];
                            if (xj_idx != -1) {
                                var xj = cells[xj_idx];
                                var dist = (xj - xk).magnitude;
                                if (dist < r) {
                                    ok = false;
                                    goto end_of_distance_check;
                                }
                            }
                        }
                    }
    
                    end_of_distance_check:
                    if (ok) {
                        var xk_idx = cells.Count;
                        cells.Add(xk);
    
                        grids[row, col] = xk_idx;
                        active_list.Add(xk_idx);
    
                        found = true;
                        break;
                    }
                }
    
                if (!found) {
                    active_list.Remove(xi_idx);
                }
            }
    
            return cells;
        }
    }
    
    // 测试代码
    class Program
    {
        static void Main(string[] args)
        {
            var width = 1024;
            var height = 1024;
            var r = 50f;
            var points = Algorithm.Sample2D(width, height, r);
    
            var image = new Bitmap(width, height);
            using (var graphics = Graphics.FromImage(image)) {
                graphics.FillRectangle(Brushes.Black, 0f, 0f, width, height);
    
                var dot_r = 3f;
                var pen = new Pen(Color.DarkRed, 2f);
                foreach (var p in points) {
                    graphics.FillEllipse(Brushes.Yellow, p.x - dot_r, p.y - dot_r, 2f * dot_r, 2f * dot_r);
                    graphics.DrawEllipse(pen, p.x - r / 2f, p.y - r / 2f, r, r);
                }
            }
    
            image.Save("out.png");
        }
    }
    

    输出的图片:可以看到黄点分布随机且比较平均,且任意2个黄点之间的距离都小于 r r r(红色圆的半径是 r / 2 r/2 r/2
    在这里插入图片描述

    展开全文
  •     Android的触控重采样算法非常出色。Android使用触摸外推和触摸内插的组合。触摸插值意味着我们接受两个触摸事件,并在两个触摸事件中间的某个位置创建一个触摸事件。触摸外推意味着我们进行两次触摸事件,并...

    1.概述

        Android的触控重采样算法非常出色。Android使用触摸外推和触摸内插的组合。触摸插值意味着我们接受两个触摸事件,并在两个触摸事件中间的某个位置创建一个触摸事件。触摸外推意味着我们进行两次触摸事件,并在上一次触摸事件之前的某个位置创建一个触摸事件,或者预测触摸事件的位置。让我们从60hz的LCD刷新显示速率和100hz的触摸屏刷新扫描速率来看一下我们的标准输入。
    在这里插入图片描述
        我们每10毫秒移动一次触摸输入事件,每10毫秒移动一次像素,每16.6毫秒刷新一次刷新显示vsync事件。Android的算法会创建一个称为“采样时间”的新计时事件,该事件始终比vsync事件晚5毫秒。因此,第一个采样时间为时间st = 11 ms(16个vsync时间-5个采样时间),然后下一个采样时间事件为时间st = 27 ms(32 ms vsync-5),下一个采样时间为43 ms( 48-5)。让我们看一下与采样时间相同的图:
    在这里插入图片描述
        采样时间用于平衡和确定触摸事件是外推还是内插。我们只看最后两个真实的触摸事件,而不看采样事件。如果最后一次触摸事件发生在采样时间之后,但在垂直同步时间之前,我们进行插值。例如,这发生在时间vsync t = 32 ms。采样时间为时间st = 27 ms,但是我们有两个触摸事件。在时间t1 = 20 ms和时间t2 = 30 ms发生一次触摸事件。由于上一次触摸事件t2在30毫秒后27毫秒之后,我们对这两个触摸事件进行插值。如果最后一次触摸事件发生在采样时间之前,则我们推断触摸事件。例如,在vsync事件t = 48毫秒时,我们的采样时间为st = 43毫秒。上一次触摸事件发生在时间t = 40 ms,即采样时间之前。我们将使用时间t1 = 30ms和t2 = 40ms的最后两个触摸事件来推断vsync事件t = 48的触摸事件。如果在采样时间之后(而不是垂直同步时间之后)存在触摸事件,我们将插入最后两次触摸。如果两个触摸事件都在采样时间之前发生,则我们推断出最后两个触摸事件。

    2.插补

        让我们看一下插值的情况。这不是简单的中点插值,因为它会考虑相对于采样时间发生触摸事件的时间。首先,我们计算两次最后一次触摸事件之间经过的时间,我们称其为触摸时间差。每个设备应该相对稳定。在我们的情况下,这应该始终为10毫秒。接下来,我们计算采样时间与触摸事件之间的时间差,即采样时间之前的时间(触摸采样差异)。对于我们在vsync t = 32的示例,采样时间为27ms。采样时间之前的第一次触摸事件为t = 20ms。因此,27 ms的采样时间-20 ms的触摸时间= 7ms。接下来,我们创建一个名为alpha的变量,它是触摸样本差异/触摸时间差异。在这种情况下,7 ms / 10 ms = 0.7。最后,我们使用此alpha值作为采样时间之后的触摸事件与采样时间之前的触摸事件之间的中点修饰符进行线性插值。我们的两个触摸事件分别在时间t = 20,位移d = 20和t = 30且位移d = 30。我们首先使用样本之前的第一个触摸事件,然后向其添加插值位移。因此,我们有一个内插位移d = 20 +(30-20)* alpha,它是20 +(10 * 0.7)=27。因此,在vsync时间t = 32时,我们发送一个位移为d =的触摸事件27。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们的两个触摸事件分别在时间t = 20,位移d = 20和t = 30且位移d = 30。我们首先使用样本之前的第一个触摸事件,然后向其添加插值位移。因此,我们有一个内插位移d = 20 +(30-20)* alpha,它是20 +(10 * 0.7)=27。因此,在vsync时间t = 32时,我们发送一个位移为d =的触摸事件27。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们的两个触摸事件分别在时间t = 20,位移d = 20和t = 30且位移d = 30。我们首先使用样本之前的第一个触摸事件,然后向其添加插值位移。因此,我们有一个内插位移d = 20 +(30-20)* alpha,它是20 +(10 * 0.7)=27。因此,在vsync时间t = 32时,我们发送一个位移为d =的触摸事件27。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们发送位移为d = 27的触摸事件。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们发送位移为d = 27的触摸事件。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:
    在这里插入图片描述
    这是一般的方程式。LastTouch指的是SampleTime之前的触摸。FirstTouch指的是SampleTime之前的触摸。
    在这里插入图片描述
        让我们看另一个示例,在vsync时间t = 80处。我们有两个触摸事件,一个在时间t = 70,另一个在时间t = 80。我们的采样时间是80毫秒-5 = 75毫秒。由于在采样时间之后发生一次触摸事件t = 80,因此我们进行插值。这是工作:
    在这里插入图片描述
        我们看到了位移d = 75的最终结果。插值就是这样。

    3.外推法

        当最后一次触摸事件在采样时间之前发生时,发生触摸外推。这发生在垂直同步时间t = 48。我们的采样时间是48-5 = 43毫秒。我们有两个触摸事件,一个在时间t = 30,另一个在时间t = 40 ms。由于两者均在43毫秒之前,因此我们推断触摸事件。逻辑工作原理与触摸插值类似,但有一些区别。两个触摸事件之间的触摸时间差仍然相同,始终为10 ms。接下来,我们计算触摸采样差,现在是最后一次触摸事件减去采样时间,因此我们期望一个负数。因此,我们将最后一次触摸事件设为t = 40-采样时间st = 43 = -3。接下来,我们以相同的方式计算Alpha,即触摸样本差异/触摸时间差异。这种情况是(-3 / 10)= -0.3。最后,我们再次使用相同的线性插值方程,但是由于alpha为负,因此我们可以推断。此外,我们交换操作数,并从最后一次触摸中减去第一次触摸,并将起始位移设置为最后一次触摸。因此,与插值算法不同,我们从最后一次触摸事件开始,并为其添加位移。我们的最终结果是位移d = 40 +(30-40)* -0.3 =43。因此,在这种情况下,我们推断了3个像素。这是所有的数学运算:
    在这里插入图片描述
    这是一般的外推方程。最后触摸是指最近的触摸。首次触摸是指较早的触摸事件。我们仍然使用最后两个触摸事件进行推断。

    在这里插入图片描述
    让我们在vsync时间t = 128 ms处再做一次推断。这是最终位移d = 123ms的工作。
    在这里插入图片描述

    如果我们对原始输入进行内插和外推,这是最终的位移图:
    在这里插入图片描述
        哇。哇 在第一帧之外,因为我们没有额外的触摸事件,所以它达到了理想的情况,即每16毫秒移动16个像素的位移以实现完美的平滑滚动。它的帧均匀性标准偏差为0。更令人惊奇的是,这些公式可在不同的触摸屏刷新率下计算触摸插值和外推。例如,Mozilla的Flame参考设备的触摸刷新率为每13毫秒一次,而不是像Nexus 4那样每10毫秒一次,它仍然可以创建完美的平滑滚动。更令人惊奇的是,此算法解决了触摸驱动器的噪声问题,因为实际设备不会以完全正确的10 ms间隔发送触摸事件,它们会抖动,因此您会以9.9ms或10.5ms的间隔获得触摸事件。

    4.总结

        猛击的感觉更快,使整个系统不一定更流畅,但响应速度更快。在跟踪手指或进行慢速滚动时,我们还获得了滚动感觉也更加流畅的额外好处。在所有方面,与其他触摸算法相比,这是优越的。在快速滚动时,它比以前的采样算法更好地保持手指顺畅。在慢速滚动时,它可以平滑触摸事件,从而提供流畅的体验。

    展开全文
  • 在上一篇文章单片机ADC采样算法---平均值采样法中分析了平均值采样法的使用,上篇文章中的平均值采样法是连续采样100个数据,然后求平均值,这种方法存在一个问题,就是采集100个值之后,下一次又重新采集100个新的...

           在上一篇文章单片机ADC采样算法---平均值采样法中分析了平均值采样法的使用,上篇文章中的平均值采样法是连续采样100个数据,然后求平均值,这种方法存在一个问题,就是采集100个值之后,下一次又重新采集100个新的值,这两次采集的值是不连续的,相当于每次都是独立的采集来100个值,然后求平均值。这样计算出来的值有可能看不出来数据的变化趋势。希望在求平均值的时候每次读取到一个新的值,就将最早读取的旧值丢弃一个,相当于水管中的流水一样,有新的水流进来,就让最早进来的水流出去。这样采集到的数据就是连续变化的。这样通过采样值就能看出来采样数据是否发生了波动。

        算法如下:

    #define N 100
    unsigned int filter4( void )                   
    {
        static unsigned int value_buf[N];
        static unsigned int i = 0;
        unsigned int count;
        int  sum = 0;
        value_buf[i++] = ReadVol_CH3();
        if( i == N )
        {
            i = 0;
        }
        for( count = 0; count < N; count++ )
        {
            sum += value_buf[count];
        }
        return ( unsigned int )( sum / N );
    }

               通过数组将采样的数据存储起来,若数组存满之后,数组下标直接跳转到数组头,覆盖最早采样的数据。然后再计算平均值 。但是用数组存储的话会浪费单片机大量的存储空间,如果采样的数据比较多,单片机的空间有可能不够用。所以为了节省单片机的空间,这里不用数组存储,而是用另一种方法来实现  。

            改进后的算法如下:

    #define CNT  100
    u16 get_ave( void )
    {
        static  u8 count = 0;
        static  u32 S = 0;      //累加和
        static  u16 C = 0;      //本次采样值
        static  u16 A = 0;      //平均值
        C = ReadVol_CH3();
        if( count == 0 )
        {
            A = C;
            S = A * CNT;
            count = 1;
        }
        S = S - A + C;              //加上本次采样值,减去上次平均值
        A = S / N;                  //计算本次平均值
        return A;
    }

          不用数组存储的话就不知道最早采样的值是多少,这里用上次采样的平均值代替最早的采样值。A代表上次采样的平均值,C代表本次采样的值,S代表100次数据的累加和,每次采样到新数据时,就用累加和减去上一次的平均值,然后再加上本次采样的值,计算出本次采样新的平均值。

       这样S就相当于连续100个数据的累加和,每次有新的数据进来之后,先减去旧的数据,再加上新的数据。这样计算出来的平均值就是连续的。下来测试一下优化算法。

     

    这是函数发生器产的一个100HZ的正弦波,最小值是0V,最大值是4V,平均值是2.02V。单片机通过串口将采样回来的平均值发送出来,用串口波形显示软件,将采样值的波形显示出来。

    通过串口波形软件可以看出,采样回来的值是波动的,说明优化后的采样算法更能实时的反应出来采样波形的波动情况。

    在波形显示软件右下角可以看到,采样回来的值最小是419,最大是427,单片机ADC是10位分辨率 2^10=1024,所以采样的平均电压为 419/1024*5=2.0458984375V         427/1024*5=2.0849609375V  采样的平均值在2.04和2.08V之间波动。和示波器测出来的平均值2.02V有一点误差,误差最大值为0.06V左右,上一篇平均值采样法的最大误差为0.02V。

        改进后的平均值采样算法和上一篇单片机ADC采样算法---平均值采样法采样的值相比,误差增大了,但是相对于平均值采样法来看,采样的值能更快速的反应出采样数据的变化情况。

    展开全文
  • 因为需要用到Alias Sampling Method的方法,但是查了... 关于Alias Method的介绍的比较好的是一个外国Blog:Darts, Dice, and Coins: Sampling from a Discrete Distribution,以下的介绍也主要参考这篇Blog里的算法

    因为需要用到Alias Sampling Method的方法,但是查了一下,发现没有找到靠谱的关于Alias Method的中文介绍,所以干脆自己写一个好了。
    关于Alias Method的介绍的比较好的是一个外国Blog:Darts, Dice, and Coins: Sampling from a Discrete Distribution,以下的介绍也主要参考这篇Blog里的算法。

    问题:比如一个随机事件包含四种情况,每种情况发生的概率分别为: 12,13,112,112 ,问怎么用产生符合这个概率的采样方法。

    最容易想到的方法

    我之前有在【数学】均匀分布生成其他分布的方法中写过均匀分布生成其他分布的方法,这种方法就是产生0~1之间的一个随机数,然后看起对应到这个分布的CDF中的哪一个,就是产生的一个采样。比如落在0~ 12 之间就是事件A,落在 12 ~ 56 之间就是事件B,落在 56 ~ 1112 之间就是事件C,落在 1112 ~1之间就是事件D。
    但是这样的复杂度,如果用BST树来构造上面这个的话,时间复杂度为 O(logN) ,有没有时间复杂度更低的方法。

    一个Naive的办法

    一个Naive的想法如下:
    这里写图片描述
    1. 可以像上图这样采样,将四个事件排成4列:1~4,扔两次骰子,第一次扔1~4之间的整数,决定落在哪一列。
    这里写图片描述
    2. 如上如所示,将其按照最大的那个概率进行归一化。在1步中决定好哪一列了之后,扔第二次骰子,0~1之间的任意数,如果落在了第一列上,不论第二次扔几,都采样时间A,如果落在第二列上,第二次扔超过 23 则采样失败,重新采样,如果小于 23 则采样时间B成功,以此类推。
    3. 这样算法复杂度最好为 O(1) 最坏有可能无穷次,平均意义上需要采样 O(N)

    那怎么去改进呢?

    Alias Method

    这样Alias Method采样方法就横空出世了
    这里写图片描述
    还是如上面的那样的思路,但是如果我们不按照其中最大的值去归一化,而是按照其均值归一化。即按照 1N (这里是$\frac{1}{4})归一化,即为所有概率乘以N,得到如下图:
    这里写图片描述
    其总面积为N,然后可以将其分成一个1*N的长方形,如下图:
    这里写图片描述
    将前两个多出来的部分补到后面两个缺失的部分中。
    先将1中的部分补充到4中:
    这里写图片描述
    这时如果,将1,2中多出来的部分,补充到3中,就麻烦了,因为又陷入到如果从中采样超过2个以上的事件这个问题中,所以Alias Method一定要保证:每列中最多只放两个事件
    所以此时需要讲1中的补满3中去:
    这里写图片描述
    再将2中的补到1中:
    这里写图片描述
    至此整个方法大功告成
    Alias Method具体算法如下:
    1. 按照上面说的方法,将整个概率分布拉平成为一个1*N的长方形即为Alias Table,构建上面那张图之后,储存两个数组,一个里面存着第 i 列对应的事件i矩形站的面积百分比【也即其概率】,上图的话数组就为Prab[ 23 , 1 , 13, 13 ],另一个数组里面储存着第 i 列不是事件i的另外一个事件的标号,像上图就是Alias[2 NULL 1 1]
    2.产生两个随机数,第一个产生1~N 之间的整数i,决定落在哪一列。扔第二次骰子,0~1之间的任意数,判断其与Prab[i]大小,如果小于Prab[i],则采样i,如果大于Prab[i],则采样Alias[i]

    这个算法是不是非常的精妙而且简洁,做到了 O(1) 事件复杂度的采样。但是还有一个问题是,如何去构建上面的第1步?即如何去拉平整个概率分布?这样预处理的时间复杂度又是多少呢?

    Alias Method程序化构建

    Naive方法

    构建方法:
    1.找出其中面积小于等于1的列,如i列,这些列说明其一定要被别的事件矩形填上,所以在Prab[i]中填上其面积
    2.然后从面积大于1的列中,选出一个,比如j列,用它将第i列填满,然后Alias[i] = j,第j列面积减去填充用掉的面积。

    以上两个步骤一直循环,直到所有列的面积都为1了为止。

    存在性证明

    那么Alias Table一定存在吗,如何去证明呢?
    要证明Alias Table一定存在,就说明上述的算法是能够一直运行下去,直到所有列的面积都为1了为止,而不是会中间卡住。
    一个直觉就是,这一定是可以一直运行下去的。上述方法每运行一轮,就会使得剩下的没有匹配的总面积减去1,在第n轮,剩下的面积为N-n,如果存在有小于1的面积,则一定存在大于1的面积,则一定可以用大于1的面积那部分把小于1部分给填充到1,这样就进入到了第n+1轮,最后一直到所有列面积都为1。
    更为严谨的证明见上面给出的那个Blog。

    更快的构建方法

    如果按照上面的方法去构建Alias Table,算法复杂度是 O(n2) 的,因为最多需要跑N轮,而每跑一轮的最大都需要遍历N次。一个更好的办法是用两个队列A,B去储存面积大于1的节点标号,和小于1的节点标号,每次从两个队列中各取一个,将大的补充到小的之中,小的出队列,再看大的减去补给之后,如果大于1,继续放入A中,如果等于1,则也出去,如果小于1则放入B中。
    这样算法复杂度为 O(n)

    至此Alias Method就讲完了,感觉还是一个非常精妙的方法,而且方法实现起来也非常的简单。值得学习。

    展开全文
  • 【FPS】远点采样Python实现

    千次阅读 2020-03-01 14:41:04
    远点采样 2.Python实现 import random import math import matplotlib.pyplot as plt M = 50 # 所有的点数量 N = 10 # fps采样点数量 x = [] y = [] xy = [] # 生成数据 random.seed(0) for _ in range(M): px ...
  • 关于上采样方法总结(插值和深度学习)

    万次阅读 多人点赞 2019-10-23 11:12:41
    采样的技术是图像进行超分辨率的必要步骤,最近看到了CVPR2019有一些关于上采样的文章,所以想着把上采样的方法做一个简单的总结。 看了一些文章后,发现上采样大致被总结成了三个类别: 1、基于线性插值的上...
  • 提出一种多重网格剖分快速搜索算法,该算法首先将采样数据进行多重网格剖分,建立网格索引;然后通过索引搜索多重网格,合并采样数据;最后利用快速搜索算法得到的采样数据计算出待插值点。实际数据的网格化测试结果...
  • 为了解决这些问题,本文将介绍基于随机采样的路径规划算法。这类算法适用于高维度空间,它们以概率完备性(当时间接近无限时一定有解)来代替完备性,从而提高搜索效率。 概率路图算法(Probabilistic Road Map, PRM) ...
  • RRT路径规划算法

    万次阅读 多人点赞 2019-08-29 21:43:42
    RRT(Rapidly-Exploring Random Tree)算法是一种基于采样的路径规划算法,常用于移动机器人路径规划,适合解决高维空间和复杂约束下的路径规划问题。基本思想是以产生随机点的方式通过一个步长向目标点搜索前进,...
  • 快速的寻路算法 Jump Point Search

    千次阅读 2020-11-13 18:00:00
    作者:runzhiwang,腾讯 TEG 后台开发工程师本文介绍一种跳点搜索算法 JPS 以及其四个优化算法,其寻路速度最快可是 A*算法的 273 倍。文中的 JPS-Bit 和 JP...
  • 文章目录影响力最大化RIS算法简介随机反向可达集最大贪婪覆盖算法算法近似比时间复杂度源代码 ...这篇文章主要是介绍一种解决静态网络的影响力最大化问题,RIS方法是Reverse Influence Sampling,反向影响力采样,这
  • 图像上采样和图像下采样

    千次阅读 2018-05-07 16:36:44
    参考: ... ... 一种基于图像边缘的插值算法.韩萍 1. 图像下采样和上采样的概念 无论是图像的上采样还是下采样都可以使用matlab中的imresize函数来实现,而这些操作在使用到图像...
  • 现将这两种电流采样算法进行分析比较。 硬件连接示意图 交流220V通过全桥整流滤波后变为直流310V,直流310V给后端负载供电,采样电阻Rs串联在直流回路的地线中。 当设备工作时,电流从整流桥正极流出经过负载,...
  • 采样算法】拉丁超立方采样

    千次阅读 2020-04-13 16:35:51
    采样算法】拉丁超立方采样简介过程一维拉丁超立方采样多维拉丁超立方采样python编程结论参考 简介 LHS(Latin Hypercube Sampling)是一种分层采样方法,相较于蒙特卡洛采样,减少了迭代次数。其背后的概念并不...
  • · 说明 以下均为 Being_young 前辈所写,现转载过来,再加上自己的理解,重新写了一遍,方便自己日后使用 ...随机采样一致性算法 (RANSAC) 最小中值法 (LMeds) PCL中 Sample_consensus 模块及类的介绍
  • 对基于快速傅里叶变换的4种典型相位解包裹算法的速度、准确性及适用范围等相关问题进行了深入的研究,并且通过计算机模拟分析了该类算法中的4种经典算法的抗噪能力和处理含有欠采样情况的能力。结果表明,对于含有强...
  • 相对固定频率采样的传感器,变频采样的传感器在监测性能上更有优势。针对传感器的应用场景提出了一种策略模型,在此基础上设计了一种应用于节点异常监测状态的频率控制(DisTros)算法,并用MATLAB/Simulink工具进行...
  • 基于采样的路径规划算法——RRT

    千次阅读 2020-02-24 16:11:15
    基于采样的路径规划算法——RRT* ​ 在上一篇博客中简介了基于搜索的路径规划算法A*的原理,这篇博客则会从另外一个角度去解决路径规划的问题。首先我们要从RRT算法说起,然后再探讨其优势和缺点然后给出一些改进的...
  • 前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题。 坦白讲,我精力有限,但...
  • 图像识别算法

    万次阅读 多人点赞 2019-08-15 17:36:40
    图像特征提取是图像分析与图像识别的前提,它是将高维的图像数据进行简化表达有效的方式,从一幅图像的的数据矩阵中,我们看不出任何信息,所以我们必须根据这些数据提取出图像中的关键信息,一些基本元件以及它们...
  • 提出了非负张量分解的一种快速算法。首先,将大的张量数据视做多元连续函数的离散化,对其进行采样得到一个小张量;其次,对小张量执行非负分解,可得到它的重构张量;然后,对于采样后的重构张量,使用二维线性插值...
  • 运动目标跟踪算法

    万次阅读 多人点赞 2019-02-17 12:53:17
    本文介绍了一般的目标跟踪算法,对几个常用的算法进行对比,并详细介绍了粒子滤波算法和基于轮廓的目标跟踪算法。最后简单介绍了目标遮挡的处理、多摄像头目标跟踪和摄像头运动下的目标跟踪。 一、一般的目标跟踪...
  • EAST算法详解

    万次阅读 多人点赞 2018-06-18 14:54:54
     通过ICDAR 2015,COCO-Text和MSRA-TD500的标准数据集实验表明,所提出的算法在准确性和效率方面都明显优于当前先进的方法。在ICDAR 2015数据集中,所提出的算法在720p分辨率下以13.2fps获得 0.7820 的F-score 。...
  • 本文提供粒子群算法简介和一个算法举例,提供粒子群算法仿真PID的M文件代码及simulink仿真。另外,本文还提供了一种动态simulink仿真方法,可以让M文件和simulink文件之间互相交换数据,实现仿真与程序的反馈,增加...
  • 汤普森采样--Thompson Sampling 应用代码,汤普森采样解决最优路径问题。
  •  上一篇介绍了快速搜索随机树(RRT)算法的原理,这是一种基于采样的路径规划算法,在地图尺寸较大时,其效率将显著的优于基于图搜索的路径规划算法(如A*)。  然而,RRT也有其局限性,如: 狭窄通道情况下的...
  • 重新取样将在您缩放图片时更改图像数据的数量。当缩减像素取样(减少像素的数量)时,将从图像中删除一些信息。...Neighbour Interpolation)一种速度但精度低的图像像素模拟方法。该法针对于二维图像 ...
  • 快速傅里叶算法实现 学习笔记

    千次阅读 2018-08-02 12:19:41
    一、左的x(n)是采样的时域信号,右的X(k)是算出的频域信号。可以看到左边的x(n)中,n 的序列并非正常的递增,这是为了使得输出的X(k)中的k频率呈递增序列。 二、[n]的序列是通过将十进制n转化成的二进制数字...
  • 快速傅里叶变换(FFT)

    千次阅读 2016-10-31 16:40:56
    离散傅里叶变换(discrete Fourier transform) 傅里叶分析方法是信号分析的基本方法,傅里叶变换是傅里叶分析的核心,通过它把信号从时间域变换到频率域,进而研究信号的频谱结构和变化规律。 4.1定义 离散...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,308
精华内容 24,123
关键字:

最快的采样算法