Maverik
Maverik

Reputation: 2398

JFreeChart: DynamicTimeSeries with period of n milliseconds

I'm trying do define an interface in which I want to plot some values received by an external device. These values are received with a frequency that can be set through the interface. Of course the period of the plot should change according to the period defined by the user. So I started to define the followint Chart:

int periodMs = 200;
MilliDTSC dataset = new MilliDTSC(1,100, new MultipleOfMillisecond(periodMs));
dataset.setTimeBase(new MultipleOfMillisecond(periodMs))
dataset.addSeries(zeroSeries()),0,"Zero data") // zeroSeries returs a series with values set to 0
JFreeChart chart = createChart(dataset) // create the chart and set ranges and legends
ChartPanel panel = new ChartPanel(panel);

MilliDTSC is the following class, as suggested here:

public class MilliDTSC extends DynamicTimeSeriesCollection{
  public MilliDTSC(int nSeries, int nMoments, RegularTimePeriod timeSample){
    super(nSeries, nMoments, timeSample);
    if(timeSample instanceof Millisecond)
      this.pointsInTime = new Millisecond[nMoments]
    else if (timeSample instanceof MultipleOfMillisecond)
      this.pointsInTime = new MultipleOfMillisecond[nMoments]
  }
}

MultipleOfMillisecond is the following class:

public class MultipleOfMilliseconds extends Millisecond{
  MulitpleOfMilliseconds(int periodMs){
    this.periodMs = periodMs
  }

  public RegularTimePeriod previous(){
    RegularTimePeriod result = null;
    if(getMillisecond() - periodMs >= FIRST_MILLISECOND_IN_SECOND)
      result = new Millisecond((int)getMillisecond - periodMs, getSecond());
    else{
      Second previous = (Second)getSecond().previous();
      if(previous!=null)
        result = new Millisecond((int)(getMillisecond() - periodMS + LAST_MILLISECOND_IN_SECOND + 1), previous);
    }
    return result;
  }
  // similar for next()
}

I add sample to the series in the following way:

dataset.advanceTime();
dataset.appendData(newData);

What I expected is that once I fixed the period to 200 ms the chart reports on the X label more or less 5 time values:

00:00:00.000 00:00:05.000 00:00:10.000 00:00:15.000 00:00:20.000

And I expected 25 samples in each "space".

What happen instead is that I have 25 samples for each "space" but the chart reports the following values on the X label:

00:00:00.000 00:00:00.025 00:00:00.050 00:00:00.075 00:00:00.100

It seems that the period is 1ms but I'm adding samples very 200 ms.

How can I solve the problem? If I was not clear pleas tell me. Thanks!!

Upvotes: 2

Views: 4020

Answers (3)

Maverik
Maverik

Reputation: 2398

This is the solution I implemented. I reported only the methods that I changed. It was a stupid error :D

public MilliDTSC(int nSeries, int nMoments, RegularTimePeriod timeSample) {
  super(nSeries, nMoments, timeSample);
  if(timeSample instanceof MultipleOfMillisecond){
    this.pointsInTime = new MultipleOfMillisecond[nMoments];
  }else if (timeSample instanceof Millisecond) {
    this.pointsInTime = new Millisecond[nMoments];
  } 
}

public class MultipleOfMillisecond extends Millisecond {

  private static final long serialVersionUID = 1L;
  private int periodMs = 100;

  public MultipleOfMillisecond(int periodMs){
    super();
    this.periodMs = periodMs;
  }

  public MultipleOfMillisecond(int periodMs, int millisecond, Second second){
    super(millisecond, second);
    this.periodMs = periodMs;
  }

  @Override
  public RegularTimePeriod next() {
    
    RegularTimePeriod result = null;
    if(getMillisecond() + periodMs <= LAST_MILLISECOND_IN_SECOND){
        result = new MultipleOfMillisecond( periodMs, (int)(getMillisecond() + periodMs), getSecond());
    }else{
        Second next = (Second)getSecond().next();
        if(next != null){
            result = new MultipleOfMillisecond(periodMs, (int)(getMillisecond() + periodMs - LAST_MILLISECOND_IN_SECOND - 1), next);
        }
    }
    return result;
    
  }

  @Override
  public RegularTimePeriod previous() {
    
    RegularTimePeriod result = null;
    if(getMillisecond() - periodMs >= FIRST_MILLISECOND_IN_SECOND){
        result = new MultipleOfMillisecond(periodMs, (int)getMillisecond() - periodMs, getSecond());
    }else{
        Second previous = (Second)getSecond().previous();
        if(previous != null){
            result = new MultipleOfMillisecond(periodMs, (int)(getMillisecond() - periodMs + LAST_MILLISECOND_IN_SECOND + 1), previous);
        }
    }
    return result;
    
  } 
}

Now I have 10 samples in 5 seconds, i set the period to 500 ms

Now I have 10 samples in 5 seconds, i set the period to 500 ms

Upvotes: 2

trashgod
trashgod

Reputation: 205785

Instead, use the original MilliDTSC & Millisecond, and invoke advanceTime() and append the old data as required before appending the new data. Using 200 ms as an example, do something like this:

float[] newData = new float[1];
float[] oldData = new float[1];

@Override
public void actionPerformed(ActionEvent e) {
    newData[0] = randomValue();
    oldData[0] = newData[0];
    for (int i = 0; i < 200; i++) {
        dataset.advanceTime();
        dataset.appendData(oldData);
    }
    dataset.appendData(newData);
}

Note that there are now 5 samples/second, spaced 200 ms apart.

enter image description here

Upvotes: 1

clstrfsck
clstrfsck

Reputation: 14829

I think because you have this:

public class MultipleOfMilliseconds extends Millisecond
//                                          ^^^^^^^^^^^

this is true:

if(timeSample instanceof Millisecond)

If you change the ordering of the tests you might have better luck:

if(timeSample instanceof MultipleOfMillisecond)
  this.pointsInTime = new MultipleOfMillisecond[nMoments];
else if (timeSample instanceof Millisecond)
  this.pointsInTime = new Millisecond[nMoments];

Upvotes: 4

Related Questions