Androidplot:具有特定扫描速率的动态绘图

时间:2014-09-29 08:27:19

标签: java android androidplot

我正在使用androidplot来循环显示脉冲(基本上是一个相对较短的点序列)n次每分钟,其余时间是一个平坦的值。开始时有一个擦除栏可以删除最旧的50个点。但我无法弄清楚如何以特定间隔(run()的延迟)更新图表,以便系列扫描速度为25毫米/秒。

private class PulseXYSeries implements XYSeries {

    private ArrayList<Integer> values;
    private String title;
    public  PulseXYSeries(String title, int size) {
        values = new ArrayList<Integer>(size);
        for(int i = 0; i < size;i++) {
            values.add(null);
        }
        this.title = title;
    }
    @Override
    public String getTitle() {
        return title;
    }

    public void remove(int idx) {
        values.set(idx, null);
    }
    public void setY(int val, int idx) {
        values.set(idx, val);
    }
    @Override
    public Number getX(int idx) {
        return idx;
    }

    @Override
    public Number getY(int idx) {
        if(idx >= values.size())
            return null;
        return values.get(idx);
    }

    @Override
    public int size() {
        return values.size();
    }

}

private class MonitorDataSource implements Runnable {
    private final int SAMPLE_SIZE = 1000;
    private boolean keepRunning = false;
    private List<Integer> queue;
    private int flat;
    private Thread rd;

    MonitorDataSource(View rootView) {
        queue = getSelectedPointData(rootView);
        flat = queue.get(0);
        rd = new Thread(/** runnable that calls dynamicPlot.redraw() at 30Hz  **/);
        rd.start();
    }
    public void stopThread() {
        keepRunning = false;
        rd.interrupt();
    }

   public void run() {
        try {
            Log.i(TAG,"Running pulse thread");
            keepRunning = true;
            int i=0;
            boolean pulsing = true;
            long lastPulse = SystemClock.elapsedRealtime();
            long pulseDelay = 1000*60/mHeartRatePicker.getValue();
            int position = 0;
            // we need to scan at 25mm/sec
            long delay = 10;    
            DisplayMetrics dp = getResources().getDisplayMetrics();
            float plotWidth = dynamicPlot.getGraphWidget().getWidgetDimensions().canvasRect.width();
            float plotWidthMm = plotWidth / dp.xdpi * 25.4f;
            float widthPerTickInMm = plotWidthMm/(float)SAMPLE_SIZE;
            Log.i(TAG,"Width per tick: "+widthPerTickInMm+" plot width px="+plotWidth+" in mm="+plotWidthMm+" xdpi="+dp.xdpi+" xdpmm="+(dp.xdpi*(1.0f/25.4f)));
            long currTime,loopStart = SystemClock.elapsedRealtimeNanos();
            while (keepRunning) {
                // plot 4 points at a time
                for (int j = 0; j < 3; j++) {
                    if(pulsing) {
                        mMovingWaveSeries.setY(queue.get(i),position);
                        if(++i == queue.size()-1) {
                            pulsing = false;
                            i=0;
                        }
                    } else {
                        mMovingWaveSeries.setY(flat,position);
                        currTime = SystemClock.elapsedRealtime();
                        if(currTime - lastPulse >= pulseDelay) {
                            pulsing = true;
                            lastPulse = currTime;
                        }
                    }
                    mMovingWaveSeries.remove(((position + 50) % SAMPLE_SIZE));
                    position = (position+1) % SAMPLE_SIZE;
                    if(position +1 >= SAMPLE_SIZE) {
                        float diff = (SystemClock.elapsedRealtimeNanos() - loopStart )/ 1000000000f;
                        loopStart = SystemClock.elapsedRealtimeNanos();
                        Log.i(TAG,"Looped through "+plotWidthMm+"mm in "+diff+"s = "+ (plotWidthMm/diff)  +"mm/s");
                    }
                }
                Thread.sleep(delay); 
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您的代码中似乎缺少的是当前扫描速率的瞬时测量值,单位为mm。您可以使用此值来调整绘图域的比例以获得所需的效果。这是通过 XYPlot.setDomainBoundaries(...)完成的。可以调整域规模和采样频率(在代码中表示为“延迟”)以相互补偿,因此如果您需要维持特定的域规模,则相应地调整采样频率。如果正确完成,渲染频率根本不重要,可以允许浮动...实际上调制刷新率以补偿采样率通常会导致缓冲区溢出/欠载问题。

更新(对以下评论的回复)

看起来你实际上是在限制数据源(采样率),而不是绘图(刷新率),这很好。您需要做的第一件事是确定基于widthPerTickInMm达到25毫米/秒所需的循环频率以及每个循环中绘制的点数:

频率(Hz)= 25 /(widthPerTickInMm * pointsPerLoop)

使用此值调制数据源更新循环。下面是一个如何动态调制给定频率的任意循环的示例:

       float hz = 5; // modulate at 5hz
       long budget = (long) ((1/hz) * 1000f);
       long loopDurationMs = 0;
       long loopStartMs = 0;
       while(true) {
           // calculate how long this loop took:
           long now = System.currentTimeMillis();
           loopDurationMs = now - loopStartMs;
           long sleepTime = budget - loopDurationMs;
           loopStartMs = now;
           if(sleepTime > 0) {
               try {
                   Thread.sleep(sleepTime);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
       }

只是一个警告 - 我没有尝试编译或运行代码,但概念就在那里。 (这只有在您的潜在环路频率>所需频率时才有效...可能很明显,但以防万一)