Skip to content

Commit ca56a8b

Browse files
committed
ordering of graphs fixed, improved rolling extremes calculation, fixed axis scaling in x-y
1 parent 1b218ed commit ca56a8b

File tree

5 files changed

+142
-62
lines changed

5 files changed

+142
-62
lines changed

Plotter/Plotter.cpp

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,37 @@
33
Plotter::Plotter() {
44
Serial.begin(115200);
55
head = NULL;
6+
tail = NULL;
67
total_size = 0;
78
num_graphs = 0;
89
max_points_displayed = 0;
910
last_updated = millis();
1011
}
1112

12-
Plotter::~Plotter() { }
13+
Plotter::~Plotter() {
14+
GraphNode* temp = head;
15+
GraphNode* temp_next;
16+
while (temp->next) {
17+
temp_next = temp->next;
18+
delete temp;
19+
temp = temp_next;
20+
}
21+
delete temp;
22+
}
1323

1424

1525
void Plotter::addTimeGraph(String title, int points_displayed, String labelA, double* refA) {
16-
GraphNode* temp = head;
1726
String labels[] = {labelA};
1827
double* refs[] = {refA};
19-
head = new GraphNode(title, labels, refs, 1, false, points_displayed);
20-
head->next = temp;
28+
GraphNode* temp = new GraphNode(title, labels, refs, 1, false, points_displayed);
29+
if (head) {
30+
tail->next = temp;
31+
tail = temp;
32+
} else {
33+
head = temp;
34+
tail = temp;
35+
}
36+
2137
total_size++;
2238
num_graphs++;
2339
if (points_displayed > max_points_displayed) {
@@ -28,11 +44,17 @@ void Plotter::addTimeGraph(String title, int points_displayed, String labelA, do
2844

2945
void Plotter::addTimeGraph(String title, int points_displayed, String labelA, double* refA,
3046
String labelB, double* refB) {
31-
GraphNode* temp = head;
3247
String labels[] = {labelA, labelB};
3348
double* refs[] = {refA, refB};
34-
head = new GraphNode(title, labels, refs, 2, false, points_displayed);
35-
head->next = temp;
49+
GraphNode* temp = new GraphNode(title, labels, refs, 2, false, points_displayed);
50+
if (head) {
51+
tail->next = temp;
52+
tail = temp;
53+
} else {
54+
head = temp;
55+
tail = temp;
56+
}
57+
3658
total_size+=2;
3759
num_graphs++;
3860
if (points_displayed > max_points_displayed) {
@@ -43,11 +65,17 @@ void Plotter::addTimeGraph(String title, int points_displayed, String labelA, do
4365

4466
void Plotter::addTimeGraph(String title, int points_displayed, String labelA, double* refA,
4567
String labelB, double* refB, String labelC, double* refC) {
46-
GraphNode* temp = head;
4768
String labels[] = {labelA, labelB, labelC};
4869
double* refs[] = {refA, refB, refC};
49-
head = new GraphNode(title, labels, refs, 3, false, points_displayed);
50-
head->next = temp;
70+
GraphNode* temp = new GraphNode(title, labels, refs, 3, false, points_displayed);
71+
if (head) {
72+
tail->next = temp;
73+
tail = temp;
74+
} else {
75+
head = temp;
76+
tail = temp;
77+
}
78+
5179
total_size+=3;
5280
num_graphs++;
5381
if (points_displayed > max_points_displayed) {
@@ -58,12 +86,17 @@ void Plotter::addTimeGraph(String title, int points_displayed, String labelA, do
5886

5987

6088
void Plotter::addXYGraph(String title, int points_displayed, String labelX, double* refX, String labelY, double* refY) {
61-
// Code for creating XYgraph...
62-
GraphNode* temp = head;
6389
String labels[] = {labelX, labelY};
6490
double* refs[] = {refX, refY};
65-
head = new GraphNode(title, labels, refs, 2, true, points_displayed);
66-
head->next = temp;
91+
GraphNode* temp = new GraphNode(title, labels, refs, 2, true, points_displayed);
92+
if (head) {
93+
tail->next = temp;
94+
tail = temp;
95+
} else {
96+
head = temp;
97+
tail = temp;
98+
}
99+
67100
total_size+=2;
68101
num_graphs++;
69102
if (points_displayed > max_points_displayed) {
@@ -78,12 +111,7 @@ void Plotter::plot() {
78111
code += (num_graphs + INNER_KEY + total_size + INNER_KEY
79112
+ max_points_displayed + INNER_KEY + last_updated + INNER_KEY);
80113
Serial.print(code);
81-
/*
82-
Serial.print(OUTER_KEY);
83-
Serial.print(num_graphs); Serial.print('@'); Serial.print(num_time); Serial.print(INNER_KEY);
84-
Serial.print(total_size); Serial.print('@');
85-
Serial.print(last_updated); Serial.print('@'); Serial.println();
86-
*/
114+
// Print each graph code
87115
GraphNode* temp = head;
88116
while (temp != NULL) {
89117
Serial.println();

Plotter/Plotter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class Plotter {
6161
int max_points_displayed;
6262
unsigned long last_updated;
6363
GraphNode* head;
64+
GraphNode* tail;
6465

6566
};
6667

Plotter/examples/test/test.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ void setup() {
2222
void loop() {
2323

2424
if (millis() > 10100 && anotherOne) {
25-
test.addTimeGraph("Anothah one", 3000, "x", &x, "y", &y, "z", &z);
25+
test.addTimeGraph("Anothah one", 2000, "x", &x, "y", &y);
2626
anotherOne = false;
2727
}
2828

Plotter/library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Plotter
2-
version=0.0
2+
version=0.0.0
33
author=Devin Conley <devinconley@jhu.edu>
44
maintainer=Devin Conley <devinconley@jhu.edu>
55
sentence=an Arduino library for easy plotting using Processing via serial communication.

listeners/ArduinoPlotter_processingListener/ArduinoPlotter_processingListener.pde

Lines changed: 91 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Serial port;
55
final int[] COLORS = {#00FF00,#FF0000,#0000FF}; //int color codes
66
final char OUTER_KEY = '#';
77
final String INNER_KEY = "@";
8-
final double Y_SCALE_COVERAGE = 0.75;
8+
final double AXIS_COVERAGE = 0.75;
99

1010
// Setup and config Globals
1111
int h;
@@ -24,9 +24,10 @@ float[][] pos_graphs; // stored as {x, y}
2424
String[] titles;
2525
boolean[] xvy;
2626
int[] first_index_graphs;
27-
int[] sz_graphs;
27+
int[] sz_graphs; // num of values tracked in each graph
2828
int[] num_points;
2929
double[][] extremes_graphs; // {min_x, max_x, min_y, max_y}
30+
int[][] extremes_graphs_counter; // tracker for values since last set
3031
int[] pos_x;
3132

3233
// Variable-specific Globals
@@ -41,7 +42,7 @@ void setup() {
4142
String portID = Serial.list()[0];
4243
port = new Serial(this, portID, 115200);
4344
port.bufferUntil('#');
44-
frameRate(20);
45+
frameRate(100);
4546
textSize(16);
4647
background(75);
4748
}
@@ -67,16 +68,10 @@ void plot_xy(int graph_index) {
6768
int k = first_index_graphs[g];
6869

6970
// Calculations for offset and scaling of graph
70-
double x_scale = sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]);
71-
double x_offset = x_scale*extremes_graphs[g][0];
72-
double y_scale = Y_SCALE_COVERAGE*sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]);
73-
double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - Y_SCALE_COVERAGE)*sub_height;
74-
75-
// Reset the extremes to the first value in data and get min and max again
76-
extremes_graphs[g][0] = data[0][k][1];
77-
extremes_graphs[g][1] = data[0][k][1];
78-
extremes_graphs[g][2] = data[0][k+1][1];
79-
extremes_graphs[g][3] = data[0][k+1][1];
71+
double x_scale = AXIS_COVERAGE * sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]);
72+
double x_offset = x_scale*extremes_graphs[g][0] - 0.5*(1.0 - AXIS_COVERAGE)*sub_width;
73+
double y_scale = AXIS_COVERAGE * sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]);
74+
double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height;
8075

8176
// Drawing setup
8277
fill(115);
@@ -88,17 +83,6 @@ void plot_xy(int graph_index) {
8883
for (int j = 0; j < num_points[g]; j++) {
8984
point( (float)(pos_graphs[g][0] + (data[j][k][1]*x_scale - x_offset)),
9085
(float)(pos_graphs[g][1] + y_offset - data[j][k+1][1]*y_scale) );
91-
// Check for min or max
92-
if (data[j][k][1] < extremes_graphs[g][0]) {
93-
extremes_graphs[g][0] = data[j][k][1];
94-
} else if (data[j][k][1] > extremes_graphs[g][1]) {
95-
extremes_graphs[g][1] = data[j][k][1];
96-
}
97-
if (data[j][k+1][1] < extremes_graphs[g][2]) {
98-
extremes_graphs[g][2] = data[j][k+1][1];
99-
} else if (data[j][k+1][1] > extremes_graphs[g][3]) {
100-
extremes_graphs[g][3] = data[j][k+1][1];
101-
}
10286
}
10387

10488
}
@@ -110,12 +94,8 @@ void plot_time(int graph_index) {
11094
// Calculations for offset and scaling of graph
11195
double x_scale = sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]);
11296
double x_offset = x_scale*extremes_graphs[g][0];
113-
double y_scale = Y_SCALE_COVERAGE*sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]);
114-
double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - Y_SCALE_COVERAGE)*sub_height;
115-
116-
// Reset the y-extremes to the first value in data and get min and max again
117-
extremes_graphs[g][2] = data[0][k][1];
118-
extremes_graphs[g][3] = data[0][k][1];
97+
double y_scale = AXIS_COVERAGE*sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]);
98+
double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height;
11999

120100
// Drawing setup
121101
fill(115);
@@ -132,12 +112,6 @@ void plot_time(int graph_index) {
132112
for (int j = 0; j < num_points[g]; j++) {
133113
point( (float)(pos_graphs[g][0] + (data[j][k+i][0]*x_scale - x_offset)),
134114
(float)(pos_graphs[g][1] + y_offset - data[j][k+i][1]*y_scale) );
135-
// Check for min or max
136-
if (data[j][k+i][1] < extremes_graphs[g][2]) {
137-
extremes_graphs[g][2] = data[j][k+i][1];
138-
} else if (data[j][k+i][1] > extremes_graphs[g][3]) {
139-
extremes_graphs[g][3] = data[j][k+i][1];
140-
}
141115

142116
}
143117

@@ -198,6 +172,7 @@ void serialEvent(Serial ser) {
198172
xvy = new boolean[num_graphs];
199173
sz_graphs = new int[num_graphs];
200174
extremes_graphs = new double[num_graphs][4];
175+
extremes_graphs_counter = new int[num_graphs][4];
201176
first_index_graphs = new int[num_graphs];
202177
data = new double[max_points][total_vars][2];
203178

@@ -245,9 +220,50 @@ void serialEvent(Serial ser) {
245220
// j is only a counter for var in graph context
246221
for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) {
247222
data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]);
223+
224+
// Check for new extremes ("p-5, "p-4" is just to get index at x:0,1 then y:2,3)
225+
if (data[pos_x[i]][j][1] < extremes_graphs[i][p-5]) {
226+
extremes_graphs[i][p-5] = data[pos_x[i]][j][1];
227+
extremes_graphs_counter[i][p-5] = 0;
228+
} else if (data[pos_x[i]][j][1] > extremes_graphs[i][p-4]) {
229+
extremes_graphs[i][p-4] = data[pos_x[i]][j][1];
230+
extremes_graphs_counter[i][p-4] = 0;
231+
}
232+
248233
p += 2;
249234
}
250-
235+
236+
// Check for extremes going out of scope, to need a full new max/min calc
237+
boolean[] needs_calc = {false, false, false, false};
238+
for (int j = 0; j < 4; j++) {
239+
if (extremes_graphs_counter[i][j] > num_points[i]) {
240+
needs_calc[j] = true;
241+
} else {
242+
extremes_graphs_counter[i][j]++;
243+
}
244+
}
245+
if (needs_calc[0] || needs_calc[1] || needs_calc[2] || needs_calc[3]) {
246+
int j = first_index_graphs[i];
247+
for (int k = 0; k < num_points[i]; k++) {
248+
// x-direction
249+
if (needs_calc[0] && data[k][j][1] < extremes_graphs[i][0]) {
250+
extremes_graphs[i][0] = data[k][j][1];
251+
extremes_graphs_counter[i][0] = 0;
252+
} else if (needs_calc[1] && data[k][j][1] > extremes_graphs[i][1]) {
253+
extremes_graphs[i][1] = data[k][j][1];
254+
extremes_graphs_counter[i][1] = 0;
255+
}
256+
// y-direction
257+
if (needs_calc[2] && data[k][j+1][1] < extremes_graphs[i][2]) {
258+
extremes_graphs[i][2] = data[k][j+1][1];
259+
extremes_graphs_counter[i][2] = 0;
260+
} else if (needs_calc[3] && data[k][j+1][1] > extremes_graphs[i][3]) {
261+
extremes_graphs[i][3] = data[k][j+1][1];
262+
extremes_graphs_counter[i][3] = 0;
263+
}
264+
}
265+
}
266+
251267
// Advance pos_x and rollback pos_x if exceeds max points for specific graph
252268
pos_x[i]++;
253269
if (pos_x[i] >= num_points[i]) {
@@ -256,14 +272,49 @@ void serialEvent(Serial ser) {
256272

257273
} else {
258274
// TIME GRAPH HANDLER
259-
int p = 5; // first index of double in split array
260275

261-
// j is only a counter for var in graph context
276+
int p = 5; // first index of double in split array
262277
for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) {
263278
data[pos_x[i]][j][0] = temp_time;
264279
data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]);
265280
p += 2;
281+
282+
// Check for new extremes
283+
if (data[pos_x[i]][j][1] <= extremes_graphs[i][2]) {
284+
extremes_graphs[i][2] = data[pos_x[i]][j][1];
285+
extremes_graphs_counter[i][2] = 0;
286+
} else if (data[pos_x[i]][j][1] >= extremes_graphs[i][3]) {
287+
extremes_graphs[i][3] = data[pos_x[i]][j][1];
288+
289+
extremes_graphs_counter[i][3] = 0;
290+
}
291+
266292
}
293+
294+
// Check for extremes going out of scope, to need a full new max/min calc
295+
boolean[] needs_calc = {false, false, false, false};
296+
for (int j = 2; j < 4; j++) {
297+
if (extremes_graphs_counter[i][j] > num_points[i]) {
298+
needs_calc[j] = true;
299+
} else {
300+
extremes_graphs_counter[i][j]++;
301+
}
302+
}
303+
if (needs_calc[2] || needs_calc[3]) {
304+
print("lets avoid being in this block");
305+
for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) {
306+
for (int k = 0; k < num_points[i]; k++) {
307+
if (needs_calc[2] && data[k][j][1] < extremes_graphs[i][2]) {
308+
extremes_graphs[i][2] = data[k][j][1];
309+
extremes_graphs_counter[i][2] = 0;
310+
} else if (needs_calc[3] && data[k][j][1] > extremes_graphs[i][3]) {
311+
extremes_graphs[i][3] = data[k][j][1];
312+
extremes_graphs_counter[i][3] = 0;
313+
}
314+
}
315+
}
316+
}
317+
267318
// Max timestamp of graph will be now
268319
extremes_graphs[i][1] = temp_time;
269320

@@ -279,7 +330,7 @@ void serialEvent(Serial ser) {
279330
} else {
280331
// But if hasn't fully filled array, need to estimate
281332
extremes_graphs[i][0] = temp_time -
282-
((temp_time - last_config) / pos_x[i])*num_points[i];
333+
((temp_time - data[0][first_index_graphs[i]][0]) / pos_x[i])*num_points[i];
283334
}
284335

285336
}

0 commit comments

Comments
 (0)