OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/rtp_rtcp/test/BWEStandAlone/MatlabPlot.h" | |
12 | |
13 #include <math.h> | |
14 #include <stdio.h> | |
15 | |
16 #include <algorithm> | |
17 #include <sstream> | |
18 | |
19 #ifdef MATLAB | |
20 #include "engine.h" // NOLINT(build/include) | |
21 #endif | |
22 | |
23 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
24 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
25 #include "webrtc/system_wrappers/include/tick_util.h" | |
26 | |
27 using webrtc::CriticalSectionScoped; | |
28 using webrtc::CriticalSectionWrapper; | |
29 using webrtc::EventWrapper; | |
30 using webrtc::TickTime; | |
31 | |
32 #ifdef MATLAB | |
33 MatlabEngine eng; | |
34 | |
35 MatlabLine::MatlabLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, c
onst char *name /*= NULL*/) | |
36 : | |
37 _xArray(NULL), | |
38 _yArray(NULL), | |
39 _maxLen(maxLen), | |
40 _plotAttribute(), | |
41 _name() | |
42 { | |
43 if (_maxLen > 0) | |
44 { | |
45 _xArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); | |
46 _yArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); | |
47 } | |
48 | |
49 if (plotAttrib) | |
50 { | |
51 _plotAttribute = plotAttrib; | |
52 } | |
53 | |
54 if (name) | |
55 { | |
56 _name = name; | |
57 } | |
58 } | |
59 | |
60 MatlabLine::~MatlabLine() | |
61 { | |
62 if (_xArray != NULL) | |
63 { | |
64 mxDestroyArray(_xArray); | |
65 } | |
66 if (_yArray != NULL) | |
67 { | |
68 mxDestroyArray(_yArray); | |
69 } | |
70 } | |
71 | |
72 void MatlabLine::Append(double x, double y) | |
73 { | |
74 if (_maxLen > 0 && _xData.size() > static_cast<uint32_t>(_maxLen)) | |
75 { | |
76 _xData.resize(_maxLen); | |
77 _yData.resize(_maxLen); | |
78 } | |
79 | |
80 _xData.push_front(x); | |
81 _yData.push_front(y); | |
82 } | |
83 | |
84 | |
85 // append y-data with running integer index as x-data | |
86 void MatlabLine::Append(double y) | |
87 { | |
88 if (_xData.empty()) | |
89 { | |
90 // first element is index 0 | |
91 Append(0, y); | |
92 } | |
93 else | |
94 { | |
95 // take last x-value and increment | |
96 double temp = _xData.back(); // last x-value | |
97 Append(temp + 1, y); | |
98 } | |
99 } | |
100 | |
101 | |
102 void MatlabLine::SetMaxLen(int maxLen) | |
103 { | |
104 if (maxLen <= 0) | |
105 { | |
106 // means no maxLen | |
107 _maxLen = -1; | |
108 } | |
109 else | |
110 { | |
111 _maxLen = maxLen; | |
112 | |
113 if (_xArray != NULL) | |
114 { | |
115 mxDestroyArray(_xArray); | |
116 mxDestroyArray(_yArray); | |
117 } | |
118 _xArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); | |
119 _yArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); | |
120 | |
121 maxLen = ((unsigned int)maxLen <= _xData.size()) ? maxLen : (int)_xData.
size(); | |
122 _xData.resize(maxLen); | |
123 _yData.resize(maxLen); | |
124 | |
125 //// reserve the right amount of memory | |
126 //_xData.reserve(_maxLen); | |
127 //_yData.reserve(_maxLen); | |
128 } | |
129 } | |
130 | |
131 void MatlabLine::SetAttribute(char *plotAttrib) | |
132 { | |
133 _plotAttribute = plotAttrib; | |
134 } | |
135 | |
136 void MatlabLine::SetName(char *name) | |
137 { | |
138 _name = name; | |
139 } | |
140 | |
141 void MatlabLine::GetPlotData(mxArray** xData, mxArray** yData) | |
142 { | |
143 // Make sure we have enough Matlab allocated memory. | |
144 // Assuming both arrays (x and y) are of the same size. | |
145 if (_xData.empty()) | |
146 { | |
147 return; // No data | |
148 } | |
149 unsigned int size = 0; | |
150 if (_xArray != NULL) | |
151 { | |
152 size = (unsigned int)mxGetNumberOfElements(_xArray); | |
153 } | |
154 if (size < _xData.size()) | |
155 { | |
156 if (_xArray != NULL) | |
157 { | |
158 mxDestroyArray(_xArray); | |
159 mxDestroyArray(_yArray); | |
160 } | |
161 _xArray = mxCreateDoubleMatrix(1, _xData.size(), mxREAL); | |
162 _yArray = mxCreateDoubleMatrix(1, _yData.size(), mxREAL); | |
163 } | |
164 | |
165 if (!_xData.empty()) | |
166 { | |
167 double* x = mxGetPr(_xArray); | |
168 | |
169 std::list<double>::iterator it = _xData.begin(); | |
170 | |
171 for (int i = 0; it != _xData.end(); it++, i++) | |
172 { | |
173 x[i] = *it; | |
174 } | |
175 } | |
176 | |
177 if (!_yData.empty()) | |
178 { | |
179 double* y = mxGetPr(_yArray); | |
180 | |
181 std::list<double>::iterator it = _yData.begin(); | |
182 | |
183 for (int i = 0; it != _yData.end(); it++, i++) | |
184 { | |
185 y[i] = *it; | |
186 } | |
187 } | |
188 *xData = _xArray; | |
189 *yData = _yArray; | |
190 } | |
191 | |
192 std::string MatlabLine::GetXName() | |
193 { | |
194 std::ostringstream xString; | |
195 xString << "x_" << _name; | |
196 return xString.str(); | |
197 } | |
198 | |
199 std::string MatlabLine::GetYName() | |
200 { | |
201 std::ostringstream yString; | |
202 yString << "y_" << _name; | |
203 return yString.str(); | |
204 } | |
205 | |
206 std::string MatlabLine::GetPlotString() | |
207 { | |
208 | |
209 std::ostringstream s; | |
210 | |
211 if (_xData.size() == 0) | |
212 { | |
213 s << "[0 1], [0 1]"; // To get an empty plot | |
214 } | |
215 else | |
216 { | |
217 s << GetXName() << "(1:" << _xData.size() << "),"; | |
218 s << GetYName() << "(1:" << _yData.size() << ")"; | |
219 } | |
220 | |
221 s << ", '"; | |
222 s << _plotAttribute; | |
223 s << "'"; | |
224 | |
225 return s.str(); | |
226 } | |
227 | |
228 std::string MatlabLine::GetRefreshString() | |
229 { | |
230 std::ostringstream s; | |
231 | |
232 if (_xData.size() > 0) | |
233 { | |
234 s << "set(h,'xdata',"<< GetXName() <<"(1:" << _xData.size() << "),'ydata
',"<< GetYName() << "(1:" << _yData.size() << "));"; | |
235 } | |
236 else | |
237 { | |
238 s << "set(h,'xdata',[NaN],'ydata',[NaN]);"; | |
239 } | |
240 return s.str(); | |
241 } | |
242 | |
243 std::string MatlabLine::GetLegendString() | |
244 { | |
245 return ("'" + _name + "'"); | |
246 } | |
247 | |
248 bool MatlabLine::hasLegend() | |
249 { | |
250 return (!_name.empty()); | |
251 } | |
252 | |
253 | |
254 // remove data points, but keep attributes | |
255 void MatlabLine::Reset() | |
256 { | |
257 _xData.clear(); | |
258 _yData.clear(); | |
259 } | |
260 | |
261 | |
262 void MatlabLine::UpdateTrendLine(MatlabLine * sourceData, double slope, double o
ffset) | |
263 { | |
264 Reset(); // reset data, not attributes and name | |
265 | |
266 double thexMin = sourceData->xMin(); | |
267 double thexMax = sourceData->xMax(); | |
268 Append(thexMin, thexMin * slope + offset); | |
269 Append(thexMax, thexMax * slope + offset); | |
270 } | |
271 | |
272 double MatlabLine::xMin() | |
273 { | |
274 if (!_xData.empty()) | |
275 { | |
276 std::list<double>::iterator theStart = _xData.begin(); | |
277 std::list<double>::iterator theEnd = _xData.end(); | |
278 return(*min_element(theStart, theEnd)); | |
279 } | |
280 return (0.0); | |
281 } | |
282 | |
283 double MatlabLine::xMax() | |
284 { | |
285 if (!_xData.empty()) | |
286 { | |
287 std::list<double>::iterator theStart = _xData.begin(); | |
288 std::list<double>::iterator theEnd = _xData.end(); | |
289 return(*max_element(theStart, theEnd)); | |
290 } | |
291 return (0.0); | |
292 } | |
293 | |
294 double MatlabLine::yMin() | |
295 { | |
296 if (!_yData.empty()) | |
297 { | |
298 std::list<double>::iterator theStart = _yData.begin(); | |
299 std::list<double>::iterator theEnd = _yData.end(); | |
300 return(*min_element(theStart, theEnd)); | |
301 } | |
302 return (0.0); | |
303 } | |
304 | |
305 double MatlabLine::yMax() | |
306 { | |
307 if (!_yData.empty()) | |
308 { | |
309 std::list<double>::iterator theStart = _yData.begin(); | |
310 std::list<double>::iterator theEnd = _yData.end(); | |
311 return(*max_element(theStart, theEnd)); | |
312 } | |
313 return (0.0); | |
314 } | |
315 | |
316 | |
317 | |
318 MatlabTimeLine::MatlabTimeLine(int horizonSeconds /*= -1*/, const char *plotAttr
ib /*= NULL*/, | |
319 const char *name /*= NULL*/, | |
320 int64_t refTimeMs /* = -1*/) | |
321 : | |
322 _timeHorizon(horizonSeconds), | |
323 MatlabLine(-1, plotAttrib, name) // infinite number of elements | |
324 { | |
325 if (refTimeMs < 0) | |
326 _refTimeMs = TickTime::MillisecondTimestamp(); | |
327 else | |
328 _refTimeMs = refTimeMs; | |
329 } | |
330 | |
331 void MatlabTimeLine::Append(double y) | |
332 { | |
333 MatlabLine::Append(static_cast<double>(TickTime::MillisecondTimestamp() - _r
efTimeMs) / 1000.0, y); | |
334 | |
335 PurgeOldData(); | |
336 } | |
337 | |
338 | |
339 void MatlabTimeLine::PurgeOldData() | |
340 { | |
341 if (_timeHorizon > 0) | |
342 { | |
343 // remove old data | |
344 double historyLimit = static_cast<double>(TickTime::MillisecondTimestamp
() - _refTimeMs) / 1000.0 | |
345 - _timeHorizon; // remove data points older than this | |
346 | |
347 std::list<double>::reverse_iterator ritx = _xData.rbegin(); | |
348 uint32_t removeCount = 0; | |
349 while (ritx != _xData.rend()) | |
350 { | |
351 if (*ritx >= historyLimit) | |
352 { | |
353 break; | |
354 } | |
355 ritx++; | |
356 removeCount++; | |
357 } | |
358 if (removeCount == 0) | |
359 { | |
360 return; | |
361 } | |
362 | |
363 // remove the range [begin, it). | |
364 //if (removeCount > 10) | |
365 //{ | |
366 // printf("Removing %lu elements\n", removeCount); | |
367 //} | |
368 _xData.resize(_xData.size() - removeCount); | |
369 _yData.resize(_yData.size() - removeCount); | |
370 } | |
371 } | |
372 | |
373 | |
374 int64_t MatlabTimeLine::GetRefTime() | |
375 { | |
376 return(_refTimeMs); | |
377 } | |
378 | |
379 | |
380 | |
381 | |
382 MatlabPlot::MatlabPlot() | |
383 : | |
384 _figHandle(-1), | |
385 _smartAxis(false), | |
386 _critSect(CriticalSectionWrapper::CreateCriticalSection()), | |
387 _timeToPlot(false), | |
388 _plotting(false), | |
389 _enabled(true), | |
390 _firstPlot(true), | |
391 _legendEnabled(true), | |
392 _donePlottingEvent(EventWrapper::Create()) | |
393 { | |
394 CriticalSectionScoped cs(_critSect); | |
395 | |
396 _xlim[0] = 0; | |
397 _xlim[1] = 0; | |
398 _ylim[0] = 0; | |
399 _ylim[1] = 0; | |
400 | |
401 #ifdef PLOT_TESTING | |
402 _plotStartTime = -1; | |
403 _plotDelay = 0; | |
404 #endif | |
405 | |
406 } | |
407 | |
408 | |
409 MatlabPlot::~MatlabPlot() | |
410 { | |
411 _critSect->Enter(); | |
412 | |
413 // delete all line objects | |
414 while (!_line.empty()) | |
415 { | |
416 delete *(_line.end() - 1); | |
417 _line.pop_back(); | |
418 } | |
419 | |
420 delete _critSect; | |
421 delete _donePlottingEvent; | |
422 } | |
423 | |
424 | |
425 int MatlabPlot::AddLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/,
const char *name /*= NULL*/) | |
426 { | |
427 CriticalSectionScoped cs(_critSect); | |
428 if (!_enabled) | |
429 { | |
430 return -1; | |
431 } | |
432 | |
433 MatlabLine *newLine = new MatlabLine(maxLen, plotAttrib, name); | |
434 _line.push_back(newLine); | |
435 | |
436 return (static_cast<int>(_line.size() - 1)); // index of newly inserted line | |
437 } | |
438 | |
439 | |
440 int MatlabPlot::AddTimeLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL
*/, const char *name /*= NULL*/, | |
441 int64_t refTimeMs /*= -1*/) | |
442 { | |
443 CriticalSectionScoped cs(_critSect); | |
444 | |
445 if (!_enabled) | |
446 { | |
447 return -1; | |
448 } | |
449 | |
450 MatlabTimeLine *newLine = new MatlabTimeLine(maxLen, plotAttrib, name, refTi
meMs); | |
451 _line.push_back(newLine); | |
452 | |
453 return (static_cast<int>(_line.size() - 1)); // index of newly inserted line | |
454 } | |
455 | |
456 | |
457 int MatlabPlot::GetLineIx(const char *name) | |
458 { | |
459 CriticalSectionScoped cs(_critSect); | |
460 | |
461 if (!_enabled) | |
462 { | |
463 return -1; | |
464 } | |
465 | |
466 // search the list for a matching line name | |
467 std::vector<MatlabLine*>::iterator it = _line.begin(); | |
468 bool matchFound = false; | |
469 int lineIx = 0; | |
470 | |
471 for (; it != _line.end(); it++, lineIx++) | |
472 { | |
473 if ((*it)->_name == name) | |
474 { | |
475 matchFound = true; | |
476 break; | |
477 } | |
478 } | |
479 | |
480 if (matchFound) | |
481 { | |
482 return (lineIx); | |
483 } | |
484 else | |
485 { | |
486 return (-1); | |
487 } | |
488 } | |
489 | |
490 | |
491 void MatlabPlot::Append(int lineIndex, double x, double y) | |
492 { | |
493 CriticalSectionScoped cs(_critSect); | |
494 | |
495 if (!_enabled) | |
496 { | |
497 return; | |
498 } | |
499 | |
500 // sanity for index | |
501 if (lineIndex < 0 || lineIndex >= static_cast<int>(_line.size())) | |
502 { | |
503 throw "Line index out of range"; | |
504 exit(1); | |
505 } | |
506 | |
507 return (_line[lineIndex]->Append(x, y)); | |
508 } | |
509 | |
510 | |
511 void MatlabPlot::Append(int lineIndex, double y) | |
512 { | |
513 CriticalSectionScoped cs(_critSect); | |
514 | |
515 if (!_enabled) | |
516 { | |
517 return; | |
518 } | |
519 | |
520 // sanity for index | |
521 if (lineIndex < 0 || lineIndex >= static_cast<int>(_line.size())) | |
522 { | |
523 throw "Line index out of range"; | |
524 exit(1); | |
525 } | |
526 | |
527 return (_line[lineIndex]->Append(y)); | |
528 } | |
529 | |
530 | |
531 int MatlabPlot::Append(const char *name, double x, double y) | |
532 { | |
533 CriticalSectionScoped cs(_critSect); | |
534 | |
535 if (!_enabled) | |
536 { | |
537 return -1; | |
538 } | |
539 | |
540 // search the list for a matching line name | |
541 int lineIx = GetLineIx(name); | |
542 | |
543 if (lineIx < 0) //(!matchFound) | |
544 { | |
545 // no match; append new line | |
546 lineIx = AddLine(-1, NULL, name); | |
547 } | |
548 | |
549 // append data to line | |
550 Append(lineIx, x, y); | |
551 return (lineIx); | |
552 } | |
553 | |
554 int MatlabPlot::Append(const char *name, double y) | |
555 { | |
556 CriticalSectionScoped cs(_critSect); | |
557 | |
558 if (!_enabled) | |
559 { | |
560 return -1; | |
561 } | |
562 | |
563 // search the list for a matching line name | |
564 int lineIx = GetLineIx(name); | |
565 | |
566 if (lineIx < 0) //(!matchFound) | |
567 { | |
568 // no match; append new line | |
569 lineIx = AddLine(-1, NULL, name); | |
570 } | |
571 | |
572 // append data to line | |
573 Append(lineIx, y); | |
574 return (lineIx); | |
575 } | |
576 | |
577 int MatlabPlot::Length(char *name) | |
578 { | |
579 CriticalSectionScoped cs(_critSect); | |
580 | |
581 if (!_enabled) | |
582 { | |
583 return -1; | |
584 } | |
585 | |
586 int ix = GetLineIx(name); | |
587 if (ix >= 0) | |
588 { | |
589 return (static_cast<int>(_line[ix]->_xData.size())); | |
590 } | |
591 else | |
592 { | |
593 return (-1); | |
594 } | |
595 } | |
596 | |
597 | |
598 void MatlabPlot::SetPlotAttribute(char *name, char *plotAttrib) | |
599 { | |
600 CriticalSectionScoped cs(_critSect); | |
601 | |
602 if (!_enabled) | |
603 { | |
604 return; | |
605 } | |
606 | |
607 int lineIx = GetLineIx(name); | |
608 | |
609 if (lineIx >= 0) | |
610 { | |
611 _line[lineIx]->SetAttribute(plotAttrib); | |
612 } | |
613 } | |
614 | |
615 // Must be called under critical section _critSect | |
616 void MatlabPlot::UpdateData(Engine* ep) | |
617 { | |
618 if (!_enabled) | |
619 { | |
620 return; | |
621 } | |
622 | |
623 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(
); it++) | |
624 { | |
625 mxArray* xData = NULL; | |
626 mxArray* yData = NULL; | |
627 (*it)->GetPlotData(&xData, &yData); | |
628 if (xData != NULL) | |
629 { | |
630 std::string xName = (*it)->GetXName(); | |
631 std::string yName = (*it)->GetYName(); | |
632 _critSect->Leave(); | |
633 #ifdef MATLAB6 | |
634 mxSetName(xData, xName.c_str()); | |
635 mxSetName(yData, yName.c_str()); | |
636 engPutArray(ep, xData); | |
637 engPutArray(ep, yData); | |
638 #else | |
639 int ret = engPutVariable(ep, xName.c_str(), xData); | |
640 assert(ret == 0); | |
641 ret = engPutVariable(ep, yName.c_str(), yData); | |
642 assert(ret == 0); | |
643 #endif | |
644 _critSect->Enter(); | |
645 } | |
646 } | |
647 } | |
648 | |
649 bool MatlabPlot::GetPlotCmd(std::ostringstream & cmd, Engine* ep) | |
650 { | |
651 _critSect->Enter(); | |
652 | |
653 if (!DataAvailable()) | |
654 { | |
655 return false; | |
656 } | |
657 | |
658 if (_firstPlot) | |
659 { | |
660 GetPlotCmd(cmd); | |
661 _firstPlot = false; | |
662 } | |
663 else | |
664 { | |
665 GetRefreshCmd(cmd); | |
666 } | |
667 | |
668 UpdateData(ep); | |
669 | |
670 _critSect->Leave(); | |
671 | |
672 return true; | |
673 } | |
674 | |
675 // Call inside critsect | |
676 void MatlabPlot::GetPlotCmd(std::ostringstream & cmd) | |
677 { | |
678 // we have something to plot | |
679 // empty the stream | |
680 cmd.str(""); // (this seems to be the only way) | |
681 | |
682 cmd << "figure; h" << _figHandle << "= plot("; | |
683 | |
684 // first line | |
685 std::vector<MatlabLine*>::iterator it = _line.begin(); | |
686 cmd << (*it)->GetPlotString(); | |
687 | |
688 it++; | |
689 | |
690 // remaining lines | |
691 for (; it != _line.end(); it++) | |
692 { | |
693 cmd << ", "; | |
694 cmd << (*it)->GetPlotString(); | |
695 } | |
696 | |
697 cmd << "); "; | |
698 | |
699 if (_legendEnabled) | |
700 { | |
701 GetLegendCmd(cmd); | |
702 } | |
703 | |
704 if (_smartAxis) | |
705 { | |
706 double xMin = _xlim[0]; | |
707 double xMax = _xlim[1]; | |
708 double yMax = _ylim[1]; | |
709 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.
end(); it++) | |
710 { | |
711 xMax = std::max(xMax, (*it)->xMax()); | |
712 xMin = std::min(xMin, (*it)->xMin()); | |
713 | |
714 yMax = std::max(yMax, (*it)->yMax()); | |
715 yMax = std::max(yMax, fabs((*it)->yMin())); | |
716 } | |
717 _xlim[0] = xMin; | |
718 _xlim[1] = xMax; | |
719 _ylim[0] = -yMax; | |
720 _ylim[1] = yMax; | |
721 | |
722 cmd << "axis([" << _xlim[0] << ", " << _xlim[1] << ", " << _ylim[0] << "
, " << _ylim[1] << "]);"; | |
723 } | |
724 | |
725 int i=1; | |
726 for (it = _line.begin(); it != _line.end(); i++, it++) | |
727 { | |
728 cmd << "set(h" << _figHandle << "(" << i << "), 'Tag', " << (*it)->GetLe
gendString() << ");"; | |
729 } | |
730 } | |
731 | |
732 // Call inside critsect | |
733 void MatlabPlot::GetRefreshCmd(std::ostringstream & cmd) | |
734 { | |
735 cmd.str(""); // (this seems to be the only way) | |
736 std::vector<MatlabLine*>::iterator it = _line.begin(); | |
737 for (it = _line.begin(); it != _line.end(); it++) | |
738 { | |
739 cmd << "h = findobj(0, 'Tag', " << (*it)->GetLegendString() << ");"; | |
740 cmd << (*it)->GetRefreshString(); | |
741 } | |
742 //if (_legendEnabled) | |
743 //{ | |
744 // GetLegendCmd(cmd); | |
745 //} | |
746 } | |
747 | |
748 void MatlabPlot::GetLegendCmd(std::ostringstream & cmd) | |
749 { | |
750 std::vector<MatlabLine*>::iterator it = _line.begin(); | |
751 bool anyLegend = false; | |
752 for (; it != _line.end(); it++) | |
753 { | |
754 anyLegend = anyLegend || (*it)->hasLegend(); | |
755 } | |
756 if (anyLegend) | |
757 { | |
758 // create the legend | |
759 | |
760 cmd << "legend(h" << _figHandle << ",{"; | |
761 | |
762 | |
763 // iterate lines | |
764 int i = 0; | |
765 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.
end(); it++) | |
766 { | |
767 if (i > 0) | |
768 { | |
769 cmd << ", "; | |
770 } | |
771 cmd << (*it)->GetLegendString(); | |
772 i++; | |
773 } | |
774 | |
775 cmd << "}, 2); "; // place legend in upper-left corner | |
776 } | |
777 } | |
778 | |
779 // Call inside critsect | |
780 bool MatlabPlot::DataAvailable() | |
781 { | |
782 if (!_enabled) | |
783 { | |
784 return false; | |
785 } | |
786 | |
787 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(
); it++) | |
788 { | |
789 (*it)->PurgeOldData(); | |
790 } | |
791 | |
792 return true; | |
793 } | |
794 | |
795 void MatlabPlot::Plot() | |
796 { | |
797 CriticalSectionScoped cs(_critSect); | |
798 | |
799 _timeToPlot = true; | |
800 | |
801 #ifdef PLOT_TESTING | |
802 _plotStartTime = TickTime::MillisecondTimestamp(); | |
803 #endif | |
804 } | |
805 | |
806 | |
807 void MatlabPlot::Reset() | |
808 { | |
809 CriticalSectionScoped cs(_critSect); | |
810 | |
811 _enabled = true; | |
812 | |
813 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(
); it++) | |
814 { | |
815 (*it)->Reset(); | |
816 } | |
817 | |
818 } | |
819 | |
820 void MatlabPlot::SetFigHandle(int handle) | |
821 { | |
822 CriticalSectionScoped cs(_critSect); | |
823 | |
824 if (handle > 0) | |
825 _figHandle = handle; | |
826 } | |
827 | |
828 bool | |
829 MatlabPlot::TimeToPlot() | |
830 { | |
831 CriticalSectionScoped cs(_critSect); | |
832 return _enabled && _timeToPlot; | |
833 } | |
834 | |
835 void | |
836 MatlabPlot::Plotting() | |
837 { | |
838 CriticalSectionScoped cs(_critSect); | |
839 _plotting = true; | |
840 } | |
841 | |
842 void | |
843 MatlabPlot::DonePlotting() | |
844 { | |
845 CriticalSectionScoped cs(_critSect); | |
846 _timeToPlot = false; | |
847 _plotting = false; | |
848 _donePlottingEvent->Set(); | |
849 } | |
850 | |
851 void | |
852 MatlabPlot::DisablePlot() | |
853 { | |
854 _critSect->Enter(); | |
855 while (_plotting) | |
856 { | |
857 _critSect->Leave(); | |
858 _donePlottingEvent->Wait(WEBRTC_EVENT_INFINITE); | |
859 _critSect->Enter(); | |
860 } | |
861 _enabled = false; | |
862 } | |
863 | |
864 int MatlabPlot::MakeTrend(const char *sourceName, const char *trendName, double
slope, double offset, const char *plotAttrib) | |
865 { | |
866 CriticalSectionScoped cs(_critSect); | |
867 | |
868 int sourceIx; | |
869 int trendIx; | |
870 | |
871 sourceIx = GetLineIx(sourceName); | |
872 if (sourceIx < 0) | |
873 { | |
874 // could not find source | |
875 return (-1); | |
876 } | |
877 | |
878 trendIx = GetLineIx(trendName); | |
879 if (trendIx < 0) | |
880 { | |
881 // no trend found; add new line | |
882 trendIx = AddLine(2 /*maxLen*/, plotAttrib, trendName); | |
883 } | |
884 | |
885 _line[trendIx]->UpdateTrendLine(_line[sourceIx], slope, offset); | |
886 | |
887 return (trendIx); | |
888 | |
889 } | |
890 | |
891 | |
892 MatlabEngine::MatlabEngine() | |
893 : | |
894 _critSect(CriticalSectionWrapper::CreateCriticalSection()), | |
895 _eventPtr(NULL), | |
896 _running(false), | |
897 _numPlots(0) | |
898 { | |
899 _eventPtr = EventWrapper::Create(); | |
900 | |
901 _plotThread(MatlabEngine::PlotThread, this, | |
902 kLowPriority, "MatlabPlot"); | |
903 _running = true; | |
904 _plotThread->Start(); | |
905 } | |
906 | |
907 MatlabEngine::~MatlabEngine() | |
908 { | |
909 _critSect->Enter(); | |
910 | |
911 if (_plotThread) | |
912 { | |
913 _running = false; | |
914 _eventPtr->Set(); | |
915 | |
916 _plotThread->Stop(); | |
917 } | |
918 | |
919 _plots.clear(); | |
920 | |
921 delete _eventPtr; | |
922 _eventPtr = NULL; | |
923 | |
924 _critSect->Leave(); | |
925 delete _critSect; | |
926 | |
927 } | |
928 | |
929 MatlabPlot * MatlabEngine::NewPlot(MatlabPlot *newPlot) | |
930 { | |
931 CriticalSectionScoped cs(_critSect); | |
932 | |
933 //MatlabPlot *newPlot = new MatlabPlot(); | |
934 | |
935 if (newPlot) | |
936 { | |
937 newPlot->SetFigHandle(++_numPlots); // first plot is number 1 | |
938 _plots.push_back(newPlot); | |
939 } | |
940 | |
941 return (newPlot); | |
942 | |
943 } | |
944 | |
945 | |
946 void MatlabEngine::DeletePlot(MatlabPlot *plot) | |
947 { | |
948 CriticalSectionScoped cs(_critSect); | |
949 | |
950 if (plot == NULL) | |
951 { | |
952 return; | |
953 } | |
954 | |
955 std::vector<MatlabPlot *>::iterator it; | |
956 for (it = _plots.begin(); it < _plots.end(); it++) | |
957 { | |
958 if (plot == *it) | |
959 { | |
960 break; | |
961 } | |
962 } | |
963 | |
964 assert (plot == *it); | |
965 | |
966 (*it)->DisablePlot(); | |
967 | |
968 _plots.erase(it); | |
969 --_numPlots; | |
970 | |
971 delete plot; | |
972 } | |
973 | |
974 | |
975 bool MatlabEngine::PlotThread(void *obj) | |
976 { | |
977 if (!obj) | |
978 { | |
979 return (false); | |
980 } | |
981 | |
982 MatlabEngine *eng = (MatlabEngine *) obj; | |
983 | |
984 Engine *ep = engOpen(NULL); | |
985 if (!ep) | |
986 { | |
987 throw "Cannot open Matlab engine"; | |
988 return (false); | |
989 } | |
990 | |
991 engSetVisible(ep, true); | |
992 engEvalString(ep, "close all;"); | |
993 | |
994 while (eng->_running) | |
995 { | |
996 eng->_critSect->Enter(); | |
997 | |
998 // iterate through all plots | |
999 for (unsigned int ix = 0; ix < eng->_plots.size(); ix++) | |
1000 { | |
1001 MatlabPlot *plot = eng->_plots[ix]; | |
1002 if (plot->TimeToPlot()) | |
1003 { | |
1004 plot->Plotting(); | |
1005 eng->_critSect->Leave(); | |
1006 std::ostringstream cmd; | |
1007 | |
1008 if (engEvalString(ep, cmd.str().c_str())) | |
1009 { | |
1010 // engine dead | |
1011 return (false); | |
1012 } | |
1013 | |
1014 // empty the stream | |
1015 cmd.str(""); // (this seems to be the only way) | |
1016 if (plot->GetPlotCmd(cmd, ep)) | |
1017 { | |
1018 // things to plot, we have already accessed what we need in
the plot | |
1019 plot->DonePlotting(); | |
1020 | |
1021 int64_t start = TickTime::MillisecondTimestamp(); | |
1022 // plot it | |
1023 int ret = engEvalString(ep, cmd.str().c_str()); | |
1024 printf("time=%I64i\n", TickTime::MillisecondTimestamp() - st
art); | |
1025 if (ret) | |
1026 { | |
1027 // engine dead | |
1028 return (false); | |
1029 } | |
1030 | |
1031 #ifdef PLOT_TESTING | |
1032 if(plot->_plotStartTime >= 0) | |
1033 { | |
1034 plot->_plotDelay = TickTime::MillisecondTimestamp() - pl
ot->_plotStartTime; | |
1035 plot->_plotStartTime = -1; | |
1036 } | |
1037 #endif | |
1038 } | |
1039 eng->_critSect->Enter(); | |
1040 } | |
1041 } | |
1042 | |
1043 eng->_critSect->Leave(); | |
1044 // wait a while | |
1045 eng->_eventPtr->Wait(66); // 33 ms | |
1046 } | |
1047 | |
1048 if (ep) | |
1049 { | |
1050 engClose(ep); | |
1051 ep = NULL; | |
1052 } | |
1053 | |
1054 return (true); | |
1055 | |
1056 } | |
1057 | |
1058 #endif // MATLAB | |
OLD | NEW |