mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-28 07:28:20 -04:00
also measurement components are using new ValueTable
This commit is contained in:
parent
7129b9b5b6
commit
9bab1e42f0
@ -17,17 +17,6 @@ public class DataPlotter implements Drawable {
|
|||||||
private final int maxTextLength;
|
private final int maxTextLength;
|
||||||
private double size = SIZE;
|
private double size = SIZE;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a simple dummy DataSet used for creating the DataShape
|
|
||||||
*/
|
|
||||||
public DataPlotter() {
|
|
||||||
this(new ValueTable("A", "B", "C")
|
|
||||||
.add(new Value[]{new Value(0), new Value(0), new Value(0)})
|
|
||||||
.add(new Value[]{new Value(0), new Value(1), new Value(0)})
|
|
||||||
.add(new Value[]{new Value(0), new Value(1), new Value(0)})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
@ -62,15 +51,18 @@ public class DataPlotter implements Drawable {
|
|||||||
* Apply a scaling factor
|
* Apply a scaling factor
|
||||||
*
|
*
|
||||||
* @param f the factor
|
* @param f the factor
|
||||||
|
* @return the scaling factor really applied
|
||||||
*/
|
*/
|
||||||
public void scale(double f) {
|
public double scale(double f) {
|
||||||
|
double oldSize = size;
|
||||||
size *= f;
|
size *= f;
|
||||||
if (size < Style.NORMAL.getThickness()) size = Style.NORMAL.getThickness();
|
if (size < Style.NORMAL.getThickness()) size = Style.NORMAL.getThickness();
|
||||||
if (size > SIZE * 4) size = SIZE * 4;
|
if (size > SIZE) size = SIZE;
|
||||||
|
return size / oldSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
synchronized public void drawTo(Graphic g, Style highLight) {
|
public void drawTo(Graphic g, Style highLight) {
|
||||||
int x = getTextBorder();
|
int x = getTextBorder();
|
||||||
|
|
||||||
int yOffs = SIZE / 2;
|
int yOffs = SIZE / 2;
|
||||||
@ -114,13 +106,6 @@ public class DataPlotter implements Drawable {
|
|||||||
return maxTextLength * Style.NORMAL.getFontSize() / 2 + BORDER + SEP;
|
return maxTextLength * Style.NORMAL.getFontSize() / 2 + BORDER + SEP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the preferred width of the graphical representation
|
|
||||||
*/
|
|
||||||
public int getGraphicWidth() {
|
|
||||||
return getTextBorder() + data.getRows() * SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the preferred height of the graphical representation
|
* @return the preferred height of the graphical representation
|
||||||
*/
|
*/
|
||||||
|
@ -2,6 +2,7 @@ package de.neemann.digital.data;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,6 +14,7 @@ public class ValueTable implements Iterable<Value[]> {
|
|||||||
private final String[] names;
|
private final String[] names;
|
||||||
private final ArrayList<Value[]> values;
|
private final ArrayList<Value[]> values;
|
||||||
private final long[] max;
|
private final long[] max;
|
||||||
|
private int maxSize = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new table.
|
* Creates a new table.
|
||||||
@ -48,10 +50,21 @@ public class ValueTable implements Iterable<Value[]> {
|
|||||||
* @return this for chained calls
|
* @return this for chained calls
|
||||||
*/
|
*/
|
||||||
public ValueTable add(Value[] row) {
|
public ValueTable add(Value[] row) {
|
||||||
|
if (maxSize > 0 && values.size() >= maxSize) {
|
||||||
|
while (values.size() >= maxSize)
|
||||||
|
values.remove(0);
|
||||||
|
Arrays.fill(max, 0);
|
||||||
|
for (Value[] v : values)
|
||||||
|
checkMax(v);
|
||||||
|
}
|
||||||
values.add(row);
|
values.add(row);
|
||||||
|
checkMax(row);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkMax(Value[] row) {
|
||||||
for (int i = 0; i < row.length; i++)
|
for (int i = 0; i < row.length; i++)
|
||||||
if (max[i] < row[i].getValue()) max[i] = row[i].getValue();
|
if (max[i] < row[i].getValue()) max[i] = row[i].getValue();
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,4 +145,22 @@ public class ValueTable implements Iterable<Value[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear all values
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
values.clear();
|
||||||
|
Arrays.fill(max, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the maximum size for this table
|
||||||
|
*
|
||||||
|
* @param maxSize the max size
|
||||||
|
* @return this for chained calls
|
||||||
|
*/
|
||||||
|
public ValueTable setMaxSize(int maxSize) {
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import javax.swing.event.TableModelListener;
|
|||||||
import javax.swing.table.TableModel;
|
import javax.swing.table.TableModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The table model to present a test result.
|
* The table model to represent a value table.
|
||||||
* <p>
|
* <p>
|
||||||
* Created by hneemann on 24.08.16.
|
* Created by hneemann on 24.08.16.
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,9 @@ import de.neemann.digital.core.element.Element;
|
|||||||
import de.neemann.digital.core.element.ElementAttributes;
|
import de.neemann.digital.core.element.ElementAttributes;
|
||||||
import de.neemann.digital.core.element.Keys;
|
import de.neemann.digital.core.element.Keys;
|
||||||
import de.neemann.digital.core.element.PinDescriptions;
|
import de.neemann.digital.core.element.PinDescriptions;
|
||||||
|
import de.neemann.digital.data.DataPlotter;
|
||||||
|
import de.neemann.digital.data.Value;
|
||||||
|
import de.neemann.digital.data.ValueTable;
|
||||||
import de.neemann.digital.draw.elements.IOState;
|
import de.neemann.digital.draw.elements.IOState;
|
||||||
import de.neemann.digital.draw.elements.Pins;
|
import de.neemann.digital.draw.elements.Pins;
|
||||||
import de.neemann.digital.draw.graphics.Graphic;
|
import de.neemann.digital.draw.graphics.Graphic;
|
||||||
@ -15,7 +18,6 @@ import de.neemann.digital.draw.model.ModelCreator;
|
|||||||
import de.neemann.digital.draw.model.ModelEntry;
|
import de.neemann.digital.draw.model.ModelEntry;
|
||||||
import de.neemann.digital.gui.components.CircuitComponent;
|
import de.neemann.digital.gui.components.CircuitComponent;
|
||||||
import de.neemann.digital.gui.components.OrderMerger;
|
import de.neemann.digital.gui.components.OrderMerger;
|
||||||
import de.neemann.digital.gui.components.data.DataSet;
|
|
||||||
import de.neemann.digital.gui.components.data.DataSetObserver;
|
import de.neemann.digital.gui.components.data.DataSetObserver;
|
||||||
import de.neemann.digital.gui.sync.Sync;
|
import de.neemann.digital.gui.sync.Sync;
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ public class DataShape implements Shape {
|
|||||||
|
|
||||||
private final boolean microStep;
|
private final boolean microStep;
|
||||||
private final int maxSize;
|
private final int maxSize;
|
||||||
private DataSet dataSet;
|
private ValueTable logData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
@ -55,7 +57,7 @@ public class DataShape implements Shape {
|
|||||||
return new Interactor() {
|
return new Interactor() {
|
||||||
@Override
|
@Override
|
||||||
public boolean clicked(CircuitComponent cc, Point pos, IOState ioState, Element element, Sync modelSync) {
|
public boolean clicked(CircuitComponent cc, Point pos, IOState ioState, Element element, Sync modelSync) {
|
||||||
dataSet.clear();
|
logData.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -63,10 +65,12 @@ public class DataShape implements Shape {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawTo(Graphic graphic, Style heighLight) {
|
public void drawTo(Graphic graphic, Style heighLight) {
|
||||||
if (dataSet == null) {
|
if (logData == null) {
|
||||||
dataSet = new DataSet();
|
logData = new ValueTable("A", "B", "C")
|
||||||
|
.add(new Value[]{new Value(0), new Value(0), new Value(0)})
|
||||||
|
.add(new Value[]{new Value(0), new Value(1), new Value(0)});
|
||||||
}
|
}
|
||||||
dataSet.drawTo(graphic, null);
|
new DataPlotter(logData).drawTo(graphic, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,9 +83,8 @@ public class DataShape implements Shape {
|
|||||||
}
|
}
|
||||||
}.order(signals);
|
}.order(signals);
|
||||||
|
|
||||||
dataSet = new DataSet(signals, maxSize);
|
DataSetObserver dataSetObserver = new DataSetObserver(microStep, signals, maxSize);
|
||||||
|
logData = dataSetObserver.getLogData();
|
||||||
DataSetObserver dataSetObserver = new DataSetObserver(microStep, dataSet);
|
|
||||||
model.addObserver(dataSetObserver);
|
model.addObserver(dataSetObserver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
package de.neemann.digital.gui.components.data;
|
|
||||||
|
|
||||||
import de.neemann.digital.core.Signal;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A DataSample contains all the values of the signals to collect data for.
|
|
||||||
* Only the data of a single timestamp is stored in one sample.
|
|
||||||
*
|
|
||||||
* @author hneemann
|
|
||||||
*/
|
|
||||||
public class DataSample {
|
|
||||||
|
|
||||||
private final int timeStamp;
|
|
||||||
private final long[] values;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new sample
|
|
||||||
*
|
|
||||||
* @param timeStamp the time stamp
|
|
||||||
* @param valueCount the number of values, all values are set to zero
|
|
||||||
*/
|
|
||||||
public DataSample(int timeStamp, int valueCount) {
|
|
||||||
this.timeStamp = timeStamp;
|
|
||||||
values = new long[valueCount];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param sample a deep copy of the given sample
|
|
||||||
*/
|
|
||||||
public DataSample(DataSample sample) {
|
|
||||||
this(sample.timeStamp, sample.values.length);
|
|
||||||
System.arraycopy(sample.values, 0, values, 0, values.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return returns the timestamp
|
|
||||||
*/
|
|
||||||
public int getTimeStamp() {
|
|
||||||
return timeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a value
|
|
||||||
*
|
|
||||||
* @param i indes of the value
|
|
||||||
* @return the value
|
|
||||||
*/
|
|
||||||
public long getValue(int i) {
|
|
||||||
return values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sets a value in the sample
|
|
||||||
*
|
|
||||||
* @param i the index of the value
|
|
||||||
* @param value the value
|
|
||||||
* @return this for chained calls
|
|
||||||
*/
|
|
||||||
public DataSample setValue(int i, long value) {
|
|
||||||
values[i] = value;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills this sample with the actual signals values
|
|
||||||
*
|
|
||||||
* @param signals the signals to create a sample from
|
|
||||||
* @return the sample to allow chained calls
|
|
||||||
*/
|
|
||||||
public DataSample fillWith(ArrayList<Signal> signals) {
|
|
||||||
for (int i = 0; i < signals.size(); i++)
|
|
||||||
values[i] = signals.get(i).getValue().getValueIgnoreHighZ();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write this sample as a single CSV line
|
|
||||||
*
|
|
||||||
* @param w the writer
|
|
||||||
* @throws IOException IOException
|
|
||||||
*/
|
|
||||||
public void writeTo(BufferedWriter w) throws IOException {
|
|
||||||
w.write("\"" + timeStamp + "\"");
|
|
||||||
for (int i = 0; i < values.length; i++)
|
|
||||||
w.write(",\"" + values[i] + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,264 +0,0 @@
|
|||||||
package de.neemann.digital.gui.components.data;
|
|
||||||
|
|
||||||
import de.neemann.digital.core.Signal;
|
|
||||||
import de.neemann.digital.draw.graphics.Graphic;
|
|
||||||
import de.neemann.digital.draw.graphics.Orientation;
|
|
||||||
import de.neemann.digital.draw.graphics.Style;
|
|
||||||
import de.neemann.digital.draw.graphics.Vector;
|
|
||||||
import de.neemann.digital.draw.shapes.Drawable;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The dataSet stores the collected DataSamples.
|
|
||||||
* Every DataSample contains the values of al signals at a given time.
|
|
||||||
*
|
|
||||||
* @author hneemann
|
|
||||||
*/
|
|
||||||
public class DataSet implements Iterable<DataSample>, Drawable {
|
|
||||||
private final ArrayList<Signal> signals;
|
|
||||||
private final int maxSize;
|
|
||||||
private final ArrayList<DataSample> samples;
|
|
||||||
private final int maxTextLength;
|
|
||||||
private DataSample min;
|
|
||||||
private DataSample max;
|
|
||||||
private double size = SIZE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a simple dummy DataSet used for creating the DataShape
|
|
||||||
*/
|
|
||||||
public DataSet() {
|
|
||||||
this(createDummy(), 20);
|
|
||||||
add(new DataSample(0, signalSize()));
|
|
||||||
add(new DataSample(1, signalSize()).setValue(1, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ArrayList<Signal> createDummy() {
|
|
||||||
ArrayList<Signal> list = new ArrayList<>();
|
|
||||||
list.add(new Signal("A", null));
|
|
||||||
list.add(new Signal("B", null));
|
|
||||||
list.add(new Signal("C", null));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance
|
|
||||||
*
|
|
||||||
* @param signals the signals used to collect DataSamples
|
|
||||||
* @param maxSize max size of data elements
|
|
||||||
*/
|
|
||||||
public DataSet(ArrayList<Signal> signals, int maxSize) {
|
|
||||||
this.signals = signals;
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
samples = new ArrayList<>();
|
|
||||||
int tl = 0;
|
|
||||||
for (int i = 0; i < signalSize(); i++) {
|
|
||||||
String text = getSignal(i).getName();
|
|
||||||
int w = text.length();
|
|
||||||
if (w > tl) tl = w;
|
|
||||||
}
|
|
||||||
maxTextLength = tl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes all data
|
|
||||||
*/
|
|
||||||
synchronized public void clear() {
|
|
||||||
samples.clear();
|
|
||||||
min = null;
|
|
||||||
max = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new Datasample
|
|
||||||
*
|
|
||||||
* @param sample the DataSample
|
|
||||||
*/
|
|
||||||
synchronized void add(DataSample sample) {
|
|
||||||
while (samples.size() >= maxSize)
|
|
||||||
samples.remove(0);
|
|
||||||
|
|
||||||
samples.add(sample);
|
|
||||||
if (min == null) {
|
|
||||||
min = new DataSample(sample);
|
|
||||||
max = new DataSample(sample);
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < signals.size(); i++) {
|
|
||||||
if (sample.getValue(i) < min.getValue(i))
|
|
||||||
min.setValue(i, sample.getValue(i));
|
|
||||||
if (sample.getValue(i) > max.getValue(i))
|
|
||||||
max.setValue(i, sample.getValue(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the mumber of samples
|
|
||||||
*/
|
|
||||||
public int size() {
|
|
||||||
return samples.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the number of signals
|
|
||||||
*/
|
|
||||||
public int signalSize() {
|
|
||||||
return signals.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<DataSample> iterator() {
|
|
||||||
return samples.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the width of the signal with the given index
|
|
||||||
*
|
|
||||||
* @param i the index of the signal
|
|
||||||
* @return max-min
|
|
||||||
*/
|
|
||||||
private long getWidth(int i) {
|
|
||||||
return max.getValue(i) - min.getValue(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the signal with the given index
|
|
||||||
*
|
|
||||||
* @param i the index
|
|
||||||
* @return the signal
|
|
||||||
*/
|
|
||||||
public Signal getSignal(int i) {
|
|
||||||
return signals.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final int BORDER = 10;
|
|
||||||
private static final int SIZE = 25;
|
|
||||||
private static final int SEP2 = 5;
|
|
||||||
private static final int SEP = SEP2 * 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fits the data in the visible area
|
|
||||||
*
|
|
||||||
* @param width width of the frame
|
|
||||||
*/
|
|
||||||
public void fitInside(int width) {
|
|
||||||
size = ((double) (width - getTextBorder())) / size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a scaling factor
|
|
||||||
*
|
|
||||||
* @param f the factor
|
|
||||||
*/
|
|
||||||
public void scale(double f) {
|
|
||||||
size *= f;
|
|
||||||
if (size < Style.NORMAL.getThickness()) size = Style.NORMAL.getThickness();
|
|
||||||
if (size > SIZE * 4) size = SIZE * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
synchronized public void drawTo(Graphic g, Style highLight) {
|
|
||||||
int x = getTextBorder();
|
|
||||||
|
|
||||||
int yOffs = SIZE / 2;
|
|
||||||
int y = BORDER;
|
|
||||||
for (int i = 0; i < signalSize(); i++) {
|
|
||||||
String text = getSignal(i).getName();
|
|
||||||
g.drawText(new Vector(x - 2, y + yOffs), new Vector(x + 1, y + yOffs), text, Orientation.RIGHTCENTER, Style.NORMAL);
|
|
||||||
g.drawLine(new Vector(x, y - SEP2), new Vector(x + (int) (size * size()), y - SEP2), Style.DASH);
|
|
||||||
y += SIZE + SEP;
|
|
||||||
}
|
|
||||||
g.drawLine(new Vector(x, y - SEP2), new Vector(x + (int) (size * size()), y - SEP2), Style.DASH);
|
|
||||||
|
|
||||||
|
|
||||||
int[] lastRy = new int[signalSize()];
|
|
||||||
boolean first = true;
|
|
||||||
double pos = 0;
|
|
||||||
for (DataSample s : this) {
|
|
||||||
int xx = (int) (pos + x);
|
|
||||||
g.drawLine(new Vector(xx, BORDER - SEP2), new Vector(xx, (SIZE + SEP) * signalSize() + BORDER - SEP2), Style.DASH);
|
|
||||||
y = BORDER;
|
|
||||||
for (int i = 0; i < signalSize(); i++) {
|
|
||||||
|
|
||||||
long width = getWidth(i);
|
|
||||||
if (width == 0) width = 1;
|
|
||||||
int ry = (int) (SIZE - (SIZE * s.getValue(i)) / width);
|
|
||||||
g.drawLine(new Vector(xx, y + ry), new Vector((int) (xx + size), y + ry), Style.NORMAL);
|
|
||||||
if (!first && ry != lastRy[i])
|
|
||||||
g.drawLine(new Vector(xx, y + lastRy[i]), new Vector(xx, y + ry), Style.NORMAL);
|
|
||||||
|
|
||||||
lastRy[i] = ry;
|
|
||||||
y += SIZE + SEP;
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
pos += size;
|
|
||||||
}
|
|
||||||
g.drawLine(new Vector(x, BORDER - SEP2), new Vector(x, (SIZE + SEP) * signalSize() + BORDER - SEP2), Style.DASH);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getTextBorder() {
|
|
||||||
return maxTextLength * Style.NORMAL.getFontSize() / 2 + BORDER + SEP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the preferred width of the graphical representation
|
|
||||||
*/
|
|
||||||
public int getGraphicWidth() {
|
|
||||||
return getTextBorder() + size() * SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the preferred height of the graphical representation
|
|
||||||
*/
|
|
||||||
public int getGraphicHeight() {
|
|
||||||
return signalSize() * (SIZE + SEP) + 2 * BORDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the current width of the graphical representation
|
|
||||||
*/
|
|
||||||
public int getCurrentGraphicWidth() {
|
|
||||||
return getTextBorder() + (int) (size() * size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the signals stored
|
|
||||||
*/
|
|
||||||
public ArrayList<Signal> getSignals() {
|
|
||||||
return signals;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the data in csv file
|
|
||||||
*
|
|
||||||
* @param file the file
|
|
||||||
* @throws IOException IOException
|
|
||||||
*/
|
|
||||||
public void saveCSV(File file) throws IOException {
|
|
||||||
saveCSV(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the data in csv file
|
|
||||||
*
|
|
||||||
* @param w the writer
|
|
||||||
* @throws IOException IOException
|
|
||||||
*/
|
|
||||||
public void saveCSV(BufferedWriter w) throws IOException {
|
|
||||||
try {
|
|
||||||
w.write("\"step\"");
|
|
||||||
for (Signal s : signals)
|
|
||||||
w.write(",\"" + s.getName() + '"');
|
|
||||||
w.write("\n");
|
|
||||||
for (DataSample s : samples) {
|
|
||||||
s.writeTo(w);
|
|
||||||
w.write("\n");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
w.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,7 @@
|
|||||||
package de.neemann.digital.gui.components.data;
|
package de.neemann.digital.gui.components.data;
|
||||||
|
|
||||||
|
import de.neemann.digital.data.DataPlotter;
|
||||||
|
import de.neemann.digital.data.ValueTable;
|
||||||
import de.neemann.digital.draw.graphics.GraphicSwing;
|
import de.neemann.digital.draw.graphics.GraphicSwing;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@ -12,7 +14,7 @@ import java.awt.*;
|
|||||||
* @author hneemann
|
* @author hneemann
|
||||||
*/
|
*/
|
||||||
public class DataSetComponent extends JComponent {
|
public class DataSetComponent extends JComponent {
|
||||||
private final DataSet dataSet;
|
private final DataPlotter plotter;
|
||||||
private JScrollPane scrollPane;
|
private JScrollPane scrollPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,8 +22,8 @@ public class DataSetComponent extends JComponent {
|
|||||||
*
|
*
|
||||||
* @param dataSet the dataSet to paint
|
* @param dataSet the dataSet to paint
|
||||||
*/
|
*/
|
||||||
public DataSetComponent(DataSet dataSet) {
|
public DataSetComponent(ValueTable dataSet) {
|
||||||
this.dataSet = dataSet;
|
plotter = new DataPlotter(dataSet);
|
||||||
addMouseWheelListener(e -> {
|
addMouseWheelListener(e -> {
|
||||||
double f = Math.pow(0.9, e.getWheelRotation());
|
double f = Math.pow(0.9, e.getWheelRotation());
|
||||||
scale(f, e.getX());
|
scale(f, e.getX());
|
||||||
@ -34,14 +36,14 @@ public class DataSetComponent extends JComponent {
|
|||||||
g.setColor(Color.WHITE);
|
g.setColor(Color.WHITE);
|
||||||
g.fillRect(0, 0, getWidth(), getHeight());
|
g.fillRect(0, 0, getWidth(), getHeight());
|
||||||
|
|
||||||
dataSet.drawTo(new GraphicSwing(g2), null);
|
plotter.drawTo(new GraphicSwing(g2), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
int w = dataSet.getCurrentGraphicWidth();
|
int w = plotter.getCurrentGraphicWidth();
|
||||||
if (w < 600) w = 600;
|
if (w < 600) w = 600;
|
||||||
return new Dimension(w, dataSet.getGraphicHeight());
|
return new Dimension(w, plotter.getGraphicHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +55,7 @@ public class DataSetComponent extends JComponent {
|
|||||||
public void scale(double f, int xPos) {
|
public void scale(double f, int xPos) {
|
||||||
revalidate();
|
revalidate();
|
||||||
repaint();
|
repaint();
|
||||||
dataSet.scale(f);
|
f=plotter.scale(f);
|
||||||
|
|
||||||
int x = (int) (xPos * f) - (xPos - (int) scrollPane.getViewport().getViewRect().getX());
|
int x = (int) (xPos * f) - (xPos - (int) scrollPane.getViewport().getViewRect().getX());
|
||||||
if (x < 0) x = 0;
|
if (x < 0) x = 0;
|
||||||
@ -66,7 +68,7 @@ public class DataSetComponent extends JComponent {
|
|||||||
* @param width the clients width
|
* @param width the clients width
|
||||||
*/
|
*/
|
||||||
public void fitData(int width) {
|
public void fitData(int width) {
|
||||||
dataSet.fitInside(width);
|
plotter.fitInside(width);
|
||||||
revalidate();
|
revalidate();
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import de.neemann.digital.core.Model;
|
|||||||
import de.neemann.digital.core.ModelEvent;
|
import de.neemann.digital.core.ModelEvent;
|
||||||
import de.neemann.digital.core.ModelStateObserver;
|
import de.neemann.digital.core.ModelStateObserver;
|
||||||
import de.neemann.digital.core.Signal;
|
import de.neemann.digital.core.Signal;
|
||||||
|
import de.neemann.digital.data.ValueTable;
|
||||||
import de.neemann.digital.gui.SaveAsHelper;
|
import de.neemann.digital.gui.SaveAsHelper;
|
||||||
import de.neemann.digital.gui.components.OrderMerger;
|
import de.neemann.digital.gui.components.OrderMerger;
|
||||||
import de.neemann.digital.gui.sync.Sync;
|
import de.neemann.digital.gui.sync.Sync;
|
||||||
@ -31,7 +32,7 @@ public class DataSetDialog extends JDialog implements ModelStateObserver {
|
|||||||
private final DataSetComponent dsc;
|
private final DataSetComponent dsc;
|
||||||
private final JScrollPane scrollPane;
|
private final JScrollPane scrollPane;
|
||||||
private final Sync modelSync;
|
private final Sync modelSync;
|
||||||
private DataSet dataSet;
|
private ValueTable logData;
|
||||||
private DataSetObserver dataSetObserver;
|
private DataSetObserver dataSetObserver;
|
||||||
|
|
||||||
private static final Icon ICON_EXPAND = IconCreator.create("View-zoom-fit.png");
|
private static final Icon ICON_EXPAND = IconCreator.create("View-zoom-fit.png");
|
||||||
@ -61,11 +62,11 @@ public class DataSetDialog extends JDialog implements ModelStateObserver {
|
|||||||
}
|
}
|
||||||
}.order(signals);
|
}.order(signals);
|
||||||
|
|
||||||
dataSet = new DataSet(signals, MAX_SAMPLE_SIZE);
|
|
||||||
|
|
||||||
dataSetObserver = new DataSetObserver(microStep, dataSet);
|
dataSetObserver = new DataSetObserver(microStep, signals, MAX_SAMPLE_SIZE);
|
||||||
|
logData = dataSetObserver.getLogData();
|
||||||
|
|
||||||
dsc = new DataSetComponent(dataSet);
|
dsc = new DataSetComponent(logData);
|
||||||
scrollPane = new JScrollPane(dsc);
|
scrollPane = new JScrollPane(dsc);
|
||||||
getContentPane().add(scrollPane);
|
getContentPane().add(scrollPane);
|
||||||
dsc.setScrollPane(scrollPane);
|
dsc.setScrollPane(scrollPane);
|
||||||
@ -122,7 +123,7 @@ public class DataSetDialog extends JDialog implements ModelStateObserver {
|
|||||||
JFileChooser fileChooser = new MyFileChooser();
|
JFileChooser fileChooser = new MyFileChooser();
|
||||||
fileChooser.setFileFilter(new FileNameExtensionFilter("Comma Separated Values", "csv"));
|
fileChooser.setFileFilter(new FileNameExtensionFilter("Comma Separated Values", "csv"));
|
||||||
new SaveAsHelper(DataSetDialog.this, fileChooser, "csv")
|
new SaveAsHelper(DataSetDialog.this, fileChooser, "csv")
|
||||||
.checkOverwrite(file -> dataSet.saveCSV(file));
|
.checkOverwrite(file -> logData.saveCSV(file));
|
||||||
}
|
}
|
||||||
}.setToolTip(Lang.get("menu_saveData_tt")).createJMenuItem());
|
}.setToolTip(Lang.get("menu_saveData_tt")).createJMenuItem());
|
||||||
|
|
||||||
|
@ -2,6 +2,11 @@ package de.neemann.digital.gui.components.data;
|
|||||||
|
|
||||||
import de.neemann.digital.core.ModelEvent;
|
import de.neemann.digital.core.ModelEvent;
|
||||||
import de.neemann.digital.core.ModelStateObserver;
|
import de.neemann.digital.core.ModelStateObserver;
|
||||||
|
import de.neemann.digital.core.Signal;
|
||||||
|
import de.neemann.digital.data.Value;
|
||||||
|
import de.neemann.digital.data.ValueTable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observer to create measurement data
|
* Observer to create measurement data
|
||||||
@ -10,54 +15,64 @@ import de.neemann.digital.core.ModelStateObserver;
|
|||||||
*/
|
*/
|
||||||
public class DataSetObserver implements ModelStateObserver {
|
public class DataSetObserver implements ModelStateObserver {
|
||||||
|
|
||||||
private final DataSet dataSet;
|
private final ValueTable logData;
|
||||||
private final ModelEvent type;
|
private final ModelEvent type;
|
||||||
|
private final ArrayList<Signal> signals;
|
||||||
|
|
||||||
private DataSample manualSample;
|
private Value[] manualSample;
|
||||||
private int maintime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
* @param microStep true if gate base logging required
|
* @param microStep true if gate base logging required
|
||||||
* @param dataSet the dataset to fill
|
* @param signals the signals to log
|
||||||
|
* @param maxSize the maximum number of data points to store
|
||||||
*/
|
*/
|
||||||
public DataSetObserver(boolean microStep, DataSet dataSet) {
|
public DataSetObserver(boolean microStep, ArrayList<Signal> signals, int maxSize) {
|
||||||
|
this.signals = signals;
|
||||||
if (microStep)
|
if (microStep)
|
||||||
this.type = ModelEvent.MICROSTEP;
|
this.type = ModelEvent.MICROSTEP;
|
||||||
else
|
else
|
||||||
this.type = ModelEvent.STEP;
|
this.type = ModelEvent.STEP;
|
||||||
|
|
||||||
this.dataSet = dataSet;
|
this.logData = new ValueTable(createNames(signals)).setMaxSize(maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] createNames(ArrayList<Signal> signals) {
|
||||||
|
String[] names = new String[signals.size()];
|
||||||
|
for (int i = 0; i < signals.size(); i++)
|
||||||
|
names[i] = signals.get(i).getName();
|
||||||
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(ModelEvent event) {
|
public void handleEvent(ModelEvent event) {
|
||||||
if (event == ModelEvent.STARTED) {
|
if (event == ModelEvent.STARTED) {
|
||||||
dataSet.clear();
|
logData.clear();
|
||||||
maintime = 0;
|
|
||||||
}
|
}
|
||||||
if (event == ModelEvent.MANUALCHANGE && type == ModelEvent.MICROSTEP) {
|
if (event == ModelEvent.MANUALCHANGE && type == ModelEvent.MICROSTEP) {
|
||||||
if (manualSample == null)
|
if (manualSample == null)
|
||||||
manualSample = new DataSample(maintime, dataSet.signalSize());
|
manualSample = new Value[logData.getColumns()];
|
||||||
manualSample.fillWith(dataSet.getSignals());
|
for (int i = 0; i < logData.getColumns(); i++)
|
||||||
|
manualSample[i] = new Value(signals.get(i).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event == type) {
|
if (event == type) {
|
||||||
if (manualSample != null) {
|
if (manualSample != null) {
|
||||||
dataSet.add(manualSample);
|
logData.add(manualSample);
|
||||||
manualSample = null;
|
manualSample = null;
|
||||||
maintime++;
|
|
||||||
}
|
}
|
||||||
dataSet.add(new DataSample(maintime, dataSet.signalSize()).fillWith(dataSet.getSignals()));
|
Value[] row = new Value[logData.getColumns()];
|
||||||
maintime++;
|
for (int i = 0; i < logData.getColumns(); i++)
|
||||||
|
row[i] = new Value(signals.get(i).getValue());
|
||||||
|
logData.add(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the dataSet
|
* @return the value table
|
||||||
*/
|
*/
|
||||||
public DataSet getDataSet() {
|
public ValueTable getLogData() {
|
||||||
return dataSet;
|
return logData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package de.neemann.digital.integration;
|
package de.neemann.digital.integration;
|
||||||
|
|
||||||
|
import de.neemann.digital.data.Value;
|
||||||
|
import de.neemann.digital.data.ValueTable;
|
||||||
import de.neemann.digital.draw.graphics.Export;
|
import de.neemann.digital.draw.graphics.Export;
|
||||||
import de.neemann.digital.draw.graphics.GraphicTransform;
|
|
||||||
import de.neemann.digital.draw.graphics.GraphicsImage;
|
import de.neemann.digital.draw.graphics.GraphicsImage;
|
||||||
import de.neemann.digital.gui.components.data.DataSample;
|
|
||||||
import de.neemann.digital.gui.components.data.DataSet;
|
|
||||||
import de.neemann.digital.gui.components.data.DataSetObserver;
|
import de.neemann.digital.gui.components.data.DataSetObserver;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
@ -27,19 +26,19 @@ public class TestData extends TestCase {
|
|||||||
ToBreakRunner toBreakRunner = new ToBreakRunner("dig/data.dig").runToBreak(31);
|
ToBreakRunner toBreakRunner = new ToBreakRunner("dig/data.dig").runToBreak(31);
|
||||||
|
|
||||||
// check recorded data
|
// check recorded data
|
||||||
DataSet dataSet = toBreakRunner.getModel()
|
ValueTable dataSet = toBreakRunner.getModel()
|
||||||
.getObserver(DataSetObserver.class)
|
.getObserver(DataSetObserver.class)
|
||||||
.getDataSet();
|
.getLogData();
|
||||||
|
|
||||||
assertEquals(31, dataSet.size());
|
assertEquals(31, dataSet.getRows());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (DataSample ds : dataSet) {
|
for (Value[] ds : dataSet) {
|
||||||
assertEquals((~i) & 1, ds.getValue(0)); // clock
|
assertEquals((~i) & 1, ds[0].getValue()); // clock
|
||||||
int s = i / 2 + 1;
|
int s = i / 2 + 1;
|
||||||
assertEquals(s & 1, ds.getValue(1));//q_0
|
assertEquals(s & 1, ds[1].getValue());//q_0
|
||||||
assertEquals((s >> 1) & 1, ds.getValue(2));//q_1
|
assertEquals((s >> 1) & 1, ds[2].getValue());//q_1
|
||||||
assertEquals((s >> 2) & 1, ds.getValue(3));//q_2
|
assertEquals((s >> 2) & 1, ds[3].getValue());//q_2
|
||||||
assertEquals((s >> 3) & 1, ds.getValue(4));//q_3
|
assertEquals((s >> 3) & 1, ds[4].getValue());//q_3
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user