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