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

标签 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();
        }
    }
}

最佳答案

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

更新(回复以下评论)

看来您实际上是在限制数据源(采样率),而不是绘图(刷新率),这很好。您需要做的第一件事是根据 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);
               }
           }
       }

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

关于java - Androidplot:具有特定扫描速率的动态绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26095538/

相关文章:

Java:最终字符串比较不起作用

java - DocuSign 自动回复收件人事件

android - 在 Android Plot 中更改正弦波宽度

android - 在安卓上写python代码

java - AndroidPlot 和 RectRegion 行为

java - Androidplot错误: Cannot resolve getGraphWidget and other method

java - Java 同步方法通常优先考虑最近调用的线程吗?

java - 如何提高 Android 低功耗蓝牙 GATT 吞吐量?

Android:在 Twitter 上使用我的应用程序时没有获得访问 token ?

android - Assets 文件夹中的更新图像在启动应用程序时未显示