Project

General

Profile

Statistics
| Branch: | Revision:

root / src / scave / filternodes.cc @ a3be1d55

History | View | Annotate | Download (23.1 KB)

1
//=========================================================================
2
//  FILTERNODES.CC - part of
3
//                  OMNeT++/OMNEST
4
//           Discrete System Simulation in C++
5
//
6
//  Author: Andras Varga
7
//
8
//=========================================================================
9

    
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992-2008 Andras Varga
12
  Copyright (C) 2006-2008 OpenSim Ltd.
13

14
  This file is distributed WITHOUT ANY WARRANTY. See the file
15
  `license' for details on this and other legal matters.
16
*--------------------------------------------------------------*/
17

    
18
#include <math.h>
19
#include <stdlib.h>
20
#include "channel.h"
21
#include "filternodes.h"
22
#include "stringutil.h"
23

    
24
USING_NAMESPACE
25

    
26

    
27
bool NopNode::isReady() const
28
{
29
    return in()->length()>0;
30
}
31

    
32
void NopNode::process()
33
{
34
    int n = in()->length();
35
    for (int i=0; i<n; i++)
36
    {
37
        Datum d;
38
        in()->read(&d,1);
39
        out()->write(&d,1);
40
    }
41
}
42

    
43
//--
44

    
45
const char *NopNodeType::getDescription() const
46
{
47
    return "Does nothing";
48
}
49

    
50
void NopNodeType::getAttributes(StringMap& attrs) const
51
{
52
}
53

    
54
Node *NopNodeType::create(DataflowManager *mgr, StringMap& attrs) const
55
{
56
    checkAttrNames(attrs);
57

    
58
    Node *node = new NopNode();
59
    node->setNodeType(this);
60
    mgr->addNode(node);
61
    return node;
62
}
63

    
64
//-----
65

    
66
bool AdderNode::isReady() const
67
{
68
    return in()->length()>0;
69
}
70

    
71
void AdderNode::process()
72
{
73
    int n = in()->length();
74
    for (int i=0; i<n; i++)
75
    {
76
        Datum d;
77
        in()->read(&d,1);
78
        d.y += c;
79
        out()->write(&d,1);
80
    }
81
}
82

    
83
//--
84

    
85
const char *AdderNodeType::getDescription() const
86
{
87
    return "Adds a constant to the input: yout[k] = y[k] + c";
88
}
89

    
90
void AdderNodeType::getAttributes(StringMap& attrs) const
91
{
92
    attrs["c"] = "the additive constant";
93
}
94

    
95
Node *AdderNodeType::create(DataflowManager *mgr, StringMap& attrs) const
96
{
97
    checkAttrNames(attrs);
98

    
99
    double c = atof(attrs["c"].c_str());
100

    
101
    Node *node = new AdderNode(c);
102
    node->setNodeType(this);
103
    mgr->addNode(node);
104
    return node;
105
}
106

    
107
void AdderNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
108
{
109
    if (attrs["type"] == "enum")
110
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
111
    attrs["type"] = "double"; // XXX int?
112
}
113

    
114
//-----
115

    
116
bool MultiplierNode::isReady() const
117
{
118
    return in()->length()>0;
119
}
120

    
121
void MultiplierNode::process()
122
{
123
    int n = in()->length();
124
    for (int i=0; i<n; i++)
125
    {
126
        Datum d;
127
        in()->read(&d,1);
128
        d.y *= a;
129
        out()->write(&d,1);
130
    }
131
}
132

    
133
//--
134

    
135
const char *MultiplierNodeType::getDescription() const
136
{
137
    return "Multiplies input by a constant: yout[k] = a * y[k]";
138
}
139

    
140
void MultiplierNodeType::getAttributes(StringMap& attrs) const
141
{
142
    attrs["a"] = "the multiplier constant";
143
}
144

    
145
void MultiplierNodeType::getAttrDefaults(StringMap& attrs) const
146
{
147
    attrs["a"] = "1.0";
148
}
149

    
150
Node *MultiplierNodeType::create(DataflowManager *mgr, StringMap& attrs) const
151
{
152
    checkAttrNames(attrs);
153

    
154
    double a = atof(attrs["a"].c_str());
155

    
156
    Node *node = new MultiplierNode(a);
157
    node->setNodeType(this);
158
    mgr->addNode(node);
159
    return node;
160
}
161

    
162
void MultiplierNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
163
{
164
    if (attrs["type"] == "enum")
165
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
166
    attrs["type"] = "double"; // XXX int?
167
}
168

    
169
//-----
170

    
171
bool DividerNode::isReady() const
172
{
173
    return in()->length()>0;
174
}
175

    
176
void DividerNode::process()
177
{
178
    int n = in()->length();
179
    for (int i=0; i<n; i++)
180
    {
181
        Datum d;
182
        in()->read(&d,1);
183
        d.y /= a;
184
        out()->write(&d,1);
185
    }
186
}
187

    
188
//--
189

    
190
const char *DividerNodeType::getDescription() const
191
{
192
    return "Divides input by a constant: yout[k] = y[k] / a";
193
}
194

    
195
void DividerNodeType::getAttributes(StringMap& attrs) const
196
{
197
    attrs["a"] = "the divider constant";
198
}
199

    
200
void DividerNodeType::getAttrDefaults(StringMap& attrs) const
201
{
202
    attrs["a"] = "1.0";
203
}
204

    
205
Node *DividerNodeType::create(DataflowManager *mgr, StringMap& attrs) const
206
{
207
    checkAttrNames(attrs);
208

    
209
    double a = atof(attrs["a"].c_str());
210

    
211
    Node *node = new DividerNode(a);
212
    node->setNodeType(this);
213
    mgr->addNode(node);
214
    return node;
215
}
216

    
217
void DividerNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
218
{
219
    if (attrs["type"] == "enum")
220
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
221
    attrs["type"] = "double";
222
}
223

    
224
//-----
225

    
226
bool ModuloNode::isReady() const
227
{
228
    return in()->length()>0;
229
}
230

    
231
void ModuloNode::process()
232
{
233
    int n = in()->length();
234
    for (int i=0; i<n; i++)
235
    {
236
        //TODO: when floor(y/a)!=floor(prevy/a), insert a NaN! so they won't get connected on the line chart
237
        Datum d;
238
        in()->read(&d,1);
239
        d.y -= floor(d.y/a)*a;
240
        out()->write(&d,1);
241
    }
242
}
243

    
244
//--
245

    
246
const char *ModuloNodeType::getDescription() const
247
{
248
    return "Computes input modulo a constant: yout[k] = y[k] % a";
249
}
250

    
251
void ModuloNodeType::getAttributes(StringMap& attrs) const
252
{
253
    attrs["a"] = "the modulus";
254
}
255

    
256
void ModuloNodeType::getAttrDefaults(StringMap& attrs) const
257
{
258
    attrs["a"] = "1";
259
}
260

    
261
Node *ModuloNodeType::create(DataflowManager *mgr, StringMap& attrs) const
262
{
263
    checkAttrNames(attrs);
264

    
265
    double a = atof(attrs["a"].c_str());
266

    
267
    Node *node = new ModuloNode(a);
268
    node->setNodeType(this);
269
    mgr->addNode(node);
270
    return node;
271
}
272

    
273
void ModuloNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
274
{
275
    if (attrs["type"] == "enum")
276
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
277
    attrs["type"] = "double"; // XXX int?
278
}
279

    
280

    
281
//-----
282

    
283
bool DifferenceNode::isReady() const
284
{
285
    return in()->length()>0;
286
}
287

    
288
void DifferenceNode::process()
289
{
290
    int n = in()->length();
291
    for (int i=0; i<n; i++)
292
    {
293
        Datum d;
294
        in()->read(&d,1);
295

    
296
        double tmp = d.y;
297
        d.y -= prevy;
298
        prevy = tmp;
299

    
300
        out()->write(&d,1);
301
    }
302
}
303

    
304
//--
305

    
306
const char *DifferenceNodeType::getDescription() const
307
{
308
    return "Substracts the previous value from every value: yout[k] = y[k] - y[k-1]";
309
}
310

    
311
void DifferenceNodeType::getAttributes(StringMap& attrs) const
312
{
313
}
314

    
315
void DifferenceNodeType::getAttrDefaults(StringMap& attrs) const
316
{
317
}
318

    
319
Node *DifferenceNodeType::create(DataflowManager *mgr, StringMap& attrs) const
320
{
321
    checkAttrNames(attrs);
322

    
323
    Node *node = new DifferenceNode();
324
    node->setNodeType(this);
325
    mgr->addNode(node);
326
    return node;
327
}
328

    
329
void DifferenceNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
330
{
331
    if (attrs["type"] == "enum")
332
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
333
    if (attrs["type"] != "int")
334
        attrs["type"] = "double";
335
    // TODO interpolation-mode
336
}
337

    
338

    
339
//-----
340

    
341
bool TimeDiffNode::isReady() const
342
{
343
    return in()->length()>0;
344
}
345

    
346
void TimeDiffNode::process()
347
{
348
    int n = in()->length();
349
    for (int i=0; i<n; i++)
350
    {
351
        Datum d;
352
        in()->read(&d,1);
353

    
354
        d.y = d.x - prevx;
355
        prevx = d.x;
356

    
357
        out()->write(&d,1);
358
    }
359
}
360

    
361
//--
362

    
363
const char *TimeDiffNodeType::getDescription() const
364
{
365
    return "Returns the difference in time between this and the previous value: yout[k] = t[k] - t[k-1]";
366
}
367

    
368
void TimeDiffNodeType::getAttributes(StringMap& attrs) const
369
{
370
}
371

    
372
void TimeDiffNodeType::getAttrDefaults(StringMap& attrs) const
373
{
374
}
375

    
376
Node *TimeDiffNodeType::create(DataflowManager *mgr, StringMap& attrs) const
377
{
378
    checkAttrNames(attrs);
379

    
380
    Node *node = new TimeDiffNode();
381
    node->setNodeType(this);
382
    mgr->addNode(node);
383
    return node;
384
}
385

    
386
void TimeDiffNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
387
{
388
    attrs["type"] = "double";
389
    attrs["interpolationmode"] = "backward-sample-hold";
390
}
391

    
392

    
393
//-----
394

    
395
MovingAverageNode::MovingAverageNode(double alph)
396
{
397
    firstRead = true;
398
    prevy=0;
399
    alpha = alph;
400
}
401

    
402
bool MovingAverageNode::isReady() const
403
{
404
    return in()->length()>0;
405
}
406

    
407
void MovingAverageNode::process()
408
{
409
    if (firstRead)
410
    {
411
        Datum d;
412
        in()->read(&d,1);
413
        prevy = d.y;
414
        out()->write(&d,1);
415
        firstRead = false;
416
    }
417

    
418
    int n = in()->length();
419
    for (int i=0; i<n; i++)
420
    {
421
        Datum d;
422
        in()->read(&d,1);
423
        d.y = prevy = prevy + alpha*(d.y-prevy);
424
        out()->write(&d,1);
425
    }
426
}
427

    
428
//--
429

    
430
const char *MovingAverageNodeType::getDescription() const
431
{
432
    return "Applies the exponentially weighted moving average filter:\n"
433
           "yout[k] = yout[k-1] + alpha*(y[k]-yout[k-1])";
434
}
435

    
436
void MovingAverageNodeType::getAttributes(StringMap& attrs) const
437
{
438
    attrs["alpha"] = "smoothing constant";
439
}
440

    
441
void MovingAverageNodeType::getAttrDefaults(StringMap& attrs) const
442
{
443
    attrs["alpha"] = "0.1";
444
}
445

    
446
Node *MovingAverageNodeType::create(DataflowManager *mgr, StringMap& attrs) const
447
{
448
    checkAttrNames(attrs);
449

    
450
    double alpha = atof(attrs["alpha"].c_str());
451

    
452
    Node *node = new MovingAverageNode(alpha);
453
    node->setNodeType(this);
454
    mgr->addNode(node);
455
    return node;
456
}
457

    
458
void MovingAverageNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
459
{
460
    if (attrs["type"] == "enum")
461
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
462
    attrs["type"] = "double";
463
}
464

    
465

    
466
//-----
467

    
468
bool SumNode::isReady() const
469
{
470
    return in()->length()>0;
471
}
472

    
473
void SumNode::process()
474
{
475
    int n = in()->length();
476
    for (int i=0; i<n; i++)
477
    {
478
        Datum d;
479
        in()->read(&d,1);
480

    
481
        sum += d.y;
482
        d.y = sum;
483

    
484
        out()->write(&d,1);
485
    }
486
}
487

    
488
//--
489

    
490
const char *SumNodeType::getDescription() const
491
{
492
    return "Sums up values: yout[k] = SUM(y[i], i=0..k)";
493
}
494

    
495
void SumNodeType::getAttributes(StringMap& attrs) const
496
{
497
}
498

    
499
void SumNodeType::getAttrDefaults(StringMap& attrs) const
500
{
501
}
502

    
503
Node *SumNodeType::create(DataflowManager *mgr, StringMap& attrs) const
504
{
505
    checkAttrNames(attrs);
506

    
507
    Node *node = new SumNode();
508
    node->setNodeType(this);
509
    mgr->addNode(node);
510
    return node;
511
}
512

    
513
void SumNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
514
{
515
    if (attrs["type"] == "enum")
516
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
517
    if (attrs["type"] != "int")
518
        attrs["type"] = "double";
519
}
520

    
521

    
522
//------
523

    
524
bool TimeShiftNode::isReady() const
525
{
526
    return in()->length()>0;
527
}
528

    
529
void TimeShiftNode::process()
530
{
531
    int n = in()->length();
532
    for (int i=0; i<n; i++)
533
    {
534
        Datum d;
535
        in()->read(&d,1);
536
        d.x += dt;
537
        d.xp = BigDecimal::Nil;
538
        out()->write(&d,1);
539
    }
540
}
541

    
542
//--
543

    
544
const char *TimeShiftNodeType::getDescription() const
545
{
546
    return "Shifts the input series in time by a constant: tout[k] = t[k] + dt";
547
}
548

    
549
void TimeShiftNodeType::getAttributes(StringMap& attrs) const
550
{
551
    attrs["dt"] = "the time shift";
552
}
553

    
554
Node *TimeShiftNodeType::create(DataflowManager *mgr, StringMap& attrs) const
555
{
556
    checkAttrNames(attrs);
557

    
558
    double dt = atof(attrs["dt"].c_str());
559

    
560
    Node *node = new TimeShiftNode(dt);
561
    node->setNodeType(this);
562
    mgr->addNode(node);
563
    return node;
564
}
565

    
566
//------
567

    
568
bool LinearTrendNode::isReady() const
569
{
570
    return in()->length()>0;
571
}
572

    
573
void LinearTrendNode::process()
574
{
575
    int n = in()->length();
576
    for (int i=0; i<n; i++)
577
    {
578
        Datum d;
579
        in()->read(&d,1);
580
        d.y += a * d.x;
581
        out()->write(&d,1);
582
    }
583
}
584

    
585
//--
586

    
587
const char *LinearTrendNodeType::getDescription() const
588
{
589
    return "Adds linear component to input series: yout[k] = y[k] + a * t[k]";
590
}
591

    
592
void LinearTrendNodeType::getAttributes(StringMap& attrs) const
593
{
594
    attrs["a"] = "coeffient of linear component";
595
}
596

    
597
void LinearTrendNodeType::getAttrDefaults(StringMap& attrs) const
598
{
599
    attrs["a"] = "1.0";
600
}
601

    
602
Node *LinearTrendNodeType::create(DataflowManager *mgr, StringMap& attrs) const
603
{
604
    checkAttrNames(attrs);
605

    
606
    double a = atof(attrs["a"].c_str());
607

    
608
    Node *node = new LinearTrendNode(a);
609
    node->setNodeType(this);
610
    mgr->addNode(node);
611
    return node;
612
}
613

    
614
void LinearTrendNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
615
{
616
    if (attrs["type"] == "enum")
617
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
618
    attrs["type"] = "double";
619
}
620

    
621

    
622
//-----
623

    
624
bool CropNode::isReady() const
625
{
626
    return in()->length()>0;
627
}
628

    
629
void CropNode::process()
630
{
631
    int n = in()->length();
632
    for (int i=0; i<n; i++)
633
    {
634
        Datum d;
635
        in()->read(&d,1);
636
        if (d.x >= from && d.x <= to)
637
            out()->write(&d,1);
638
    }
639
}
640

    
641
//--
642

    
643
const char *CropNodeType::getDescription() const
644
{
645
    return "Discards values outside the [t1, t2] interval";
646
}
647

    
648
void CropNodeType::getAttributes(StringMap& attrs) const
649
{
650
    attrs["t1"] = "`from' time";
651
    attrs["t2"] = "`to' time";
652
}
653

    
654
Node *CropNodeType::create(DataflowManager *mgr, StringMap& attrs) const
655
{
656
    checkAttrNames(attrs);
657

    
658
    double t1 = atof(attrs["t1"].c_str());
659
    double t2 = atof(attrs["t2"].c_str());
660

    
661
    Node *node = new CropNode(t1,t2);
662
    node->setNodeType(this);
663
    mgr->addNode(node);
664
    return node;
665
}
666

    
667
//----
668

    
669
bool MeanNode::isReady() const
670
{
671
    return in()->length()>0;
672
}
673

    
674
void MeanNode::process()
675
{
676
    int n = in()->length();
677
    for (int i=0; i<n; i++)
678
    {
679
        Datum d;
680
        in()->read(&d,1);
681
        sum += d.y;
682
        count++;
683
        d.y = sum/count;
684
        out()->write(&d,1);
685
    }
686
}
687

    
688
void MeanNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
689
{
690
    if (attrs["type"] == "enum")
691
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
692
    attrs["type"] = "double";
693
}
694

    
695

    
696
//--
697

    
698
const char *MeanNodeType::getDescription() const
699
{
700
    return "Calculates mean on (0,t)";
701
}
702

    
703
void MeanNodeType::getAttributes(StringMap& attrs) const
704
{
705
}
706

    
707
Node *MeanNodeType::create(DataflowManager *mgr, StringMap& attrs) const
708
{
709
    checkAttrNames(attrs);
710

    
711
    Node *node = new MeanNode();
712
    node->setNodeType(this);
713
    mgr->addNode(node);
714
    return node;
715
}
716

    
717
//-----
718

    
719
bool RemoveRepeatsNode::isReady() const
720
{
721
    return in()->length()>0;
722
}
723

    
724
void RemoveRepeatsNode::process()
725
{
726
    int n = in()->length();
727
    for (int i=0; i<n; i++)
728
    {
729
        Datum d;
730
        in()->read(&d,1);
731

    
732
        if (first || prevy != d.y) {
733
            first = false;
734
            prevy = d.y;
735
            out()->write(&d,1);
736
        }
737
    }
738
}
739

    
740
//--
741

    
742
const char *RemoveRepeatsNodeType::getDescription() const
743
{
744
    return "Removes repeated y values";
745
}
746

    
747
void RemoveRepeatsNodeType::getAttributes(StringMap& attrs) const
748
{
749
}
750

    
751
void RemoveRepeatsNodeType::getAttrDefaults(StringMap& attrs) const
752
{
753
}
754

    
755
Node *RemoveRepeatsNodeType::create(DataflowManager *mgr, StringMap& attrs) const
756
{
757
    checkAttrNames(attrs);
758

    
759
    Node *node = new RemoveRepeatsNode();
760
    node->setNodeType(this);
761
    mgr->addNode(node);
762
    return node;
763
}
764

    
765
void RemoveRepeatsNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
766
{
767
    // TODO interpolationmode
768
}
769

    
770

    
771
//-----
772

    
773
bool CompareNode::isReady() const
774
{
775
    return in()->length()>0;
776
}
777

    
778
void CompareNode::process()
779
{
780
    int n = in()->length();
781
    for (int i=0; i<n; i++)
782
    {
783
        Datum d;
784
        in()->read(&d,1);
785

    
786
        if (d.y < threshold)
787
        {
788
             if (replaceIfLess)
789
                 d.y = valueIfLess;
790
        }
791
        else if (d.y > threshold)
792
        {
793
             if (replaceIfGreater)
794
                 d.y = valueIfGreater;
795
        }
796
        else
797
        {
798
             if (replaceIfEqual)
799
                 d.y = valueIfEqual;
800
        }
801
        out()->write(&d,1);
802
    }
803
}
804

    
805
//--
806

    
807
const char *CompareNodeType::getDescription() const
808
{
809
    return "Compares value against a threshold, and optionally replaces it with a constant";
810
}
811

    
812
void CompareNodeType::getAttributes(StringMap& attrs) const
813
{
814
    attrs["threshold"] = "constant to compare against";
815
    attrs["ifLess"] = "number to output if y < threshold (empty=no change)";
816
    attrs["ifEqual"] = "number to output if y == threshold (empty=no change)";
817
    attrs["ifGreater"] = "number to output if y > threshold (empty=no change)";
818
}
819

    
820
void CompareNodeType::getAttrDefaults(StringMap& attrs) const
821
{
822
}
823

    
824
Node *CompareNodeType::create(DataflowManager *mgr, StringMap& attrs) const
825
{
826
    checkAttrNames(attrs);
827

    
828
    CompareNode *node = new CompareNode();
829
    node->setNodeType(this);
830

    
831
    node->setThreshold(atof(attrs["threshold"].c_str()));
832
    if (!opp_isblank(attrs["ifLess"].c_str()))
833
        node->setLessValue(atof(attrs["ifLess"].c_str()));
834
    if (!opp_isblank(attrs["ifEqual"].c_str()))
835
        node->setEqualValue(atof(attrs["ifEqual"].c_str()));
836
    if (!opp_isblank(attrs["ifGreater"].c_str()))
837
        node->setGreaterValue(atof(attrs["ifGreater"].c_str()));
838

    
839
    mgr->addNode(node);
840
    return node;
841
}
842

    
843
//-----
844

    
845
bool IntegrateNode::isReady() const
846
{
847
    return in()->length()>0;
848
}
849

    
850
void IntegrateNode::process()
851
{
852
    int n = in()->length();
853
    for (int i=0; i<n; i++)
854
    {
855
        Datum d;
856
        in()->read(&d,1);
857

    
858
        if (!isPrevValid)
859
        {
860
            prevx = d.x;
861
            prevy = d.y;
862
            isPrevValid = true;
863
            d.y = 0;
864
            out()->write(&d,1);
865
        }
866
        else
867
        {
868
            switch (interpolationmode) {
869
                case SAMPLE_HOLD: integral += prevy * (d.x-prevx); break;
870
                case BACKWARD_SAMPLE_HOLD: integral += d.y * (d.x-prevx); break;
871
                case LINEAR: integral += (prevy+d.y)/2 * (d.x-prevx); break;
872
                default: Assert(false);
873
            }
874
            prevx = d.x;
875
            prevy = d.y;
876
            d.y = integral;
877
            out()->write(&d,1);
878
        }
879
    }
880
}
881

    
882
//--
883

    
884
const char *IntegrateNodeType::getDescription() const
885
{
886
    return "Integrates the input as a step function (sample-hold or backward-sample-hold) or with linear interpolation";
887
}
888

    
889
void IntegrateNodeType::getAttributes(StringMap& attrs) const
890
{
891
    attrs["interpolation-mode"] = "sample-hold, backward-sample-hold, or linear";
892
}
893

    
894
void IntegrateNodeType::getAttrDefaults(StringMap& attrs) const
895
{
896
    attrs["interpolation-mode"] = "sample-hold";
897
}
898

    
899
Node *IntegrateNodeType::create(DataflowManager *mgr, StringMap& attrs) const
900
{
901
    checkAttrNames(attrs);
902

    
903
    //TODO we should really support combobox selection on the UI for this...
904
    InterpolationMode mode;
905
    const std::string modeString = attrs["interpolation-mode"];
906
    if (modeString == "" || modeString == "sample-hold")
907
        mode = SAMPLE_HOLD;
908
    else if (modeString == "backward-sample-hold")
909
        mode = BACKWARD_SAMPLE_HOLD;
910
    else if (modeString == "linear")
911
        mode = LINEAR;
912
    else
913
        throw opp_runtime_error("unknown interpolation mode: %s", modeString.c_str());
914

    
915
    Node *node = new IntegrateNode(mode);
916
    node->setNodeType(this);
917
    mgr->addNode(node);
918
    return node;
919
}
920

    
921
void IntegrateNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
922
{
923
    if (attrs["type"] == "enum")
924
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
925
    attrs["type"] = "double";
926
}
927

    
928

    
929
//-----
930

    
931
bool TimeAverageNode::isReady() const
932
{
933
    return in()->length()>0;
934
}
935

    
936
void TimeAverageNode::process()
937
{
938
    int n = in()->length();
939
    for (int i=0; i<n; i++)
940
    {
941
        Datum d;
942
        in()->read(&d,1);
943

    
944
        if (!isPrevValid)
945
        {
946
            prevx = d.x;
947
            prevy = d.y;
948
            isPrevValid = true;
949
        }
950
        else
951
        {
952
            switch (interpolationmode) {
953
                case SAMPLE_HOLD: integral += prevy * (d.x-prevx); break;
954
                case BACKWARD_SAMPLE_HOLD: integral += d.y * (d.x-prevx); break;
955
                case LINEAR: integral += (prevy+d.y)/2 * (d.x-prevx); break;
956
                default: Assert(false);
957
            }
958
            prevx = d.x;
959
            prevy = d.y;
960
            if (d.x != startx)  // suppress 0/0 = NaN values
961
            {
962
                d.y = integral / (d.x - startx);
963
                out()->write(&d,1);
964
            }
965
        }
966
    }
967
}
968

    
969
//--
970

    
971
const char *TimeAverageNodeType::getDescription() const
972
{
973
    return "Calculates the time average of the input (integral divided by time)";
974
}
975

    
976
void TimeAverageNodeType::getAttributes(StringMap& attrs) const
977
{
978
    attrs["interpolation-mode"] = "sample-hold, backward-sample-hold, or linear";
979
}
980

    
981
void TimeAverageNodeType::getAttrDefaults(StringMap& attrs) const
982
{
983
    attrs["interpolation-mode"] = "sample-hold";
984
}
985

    
986
Node *TimeAverageNodeType::create(DataflowManager *mgr, StringMap& attrs) const
987
{
988
    checkAttrNames(attrs);
989

    
990
    //TODO we should really support combobox selection on the UI for this...
991
    InterpolationMode mode;
992
    const std::string modeString = attrs["interpolation-mode"];
993
    if (modeString == "" || modeString == "sample-hold")
994
        mode = SAMPLE_HOLD;
995
    else if (modeString == "backward-sample-hold")
996
        mode = BACKWARD_SAMPLE_HOLD;
997
    else if (modeString == "linear")
998
        mode = LINEAR;
999
    else
1000
        throw opp_runtime_error("unknown interpolation mode: %s", modeString.c_str());
1001

    
1002
    Node *node = new TimeAverageNode(mode);
1003
    node->setNodeType(this);
1004
    mgr->addNode(node);
1005
    return node;
1006
}
1007

    
1008
void TimeAverageNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
1009
{
1010
    if (attrs["type"] == "enum")
1011
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
1012
    attrs["type"] = "double";
1013
}
1014

    
1015
//-----
1016

    
1017
bool DivideByTimeNode::isReady() const
1018
{
1019
    return in()->length()>0;
1020
}
1021

    
1022
void DivideByTimeNode::process()
1023
{
1024
    int n = in()->length();
1025
    for (int i=0; i<n; i++)
1026
    {
1027
        Datum d;
1028
        in()->read(&d,1);
1029
        d.y /= d.x;
1030
        out()->write(&d,1);
1031
    }
1032
}
1033

    
1034
//--
1035

    
1036
const char *DivideByTimeNodeType::getDescription() const
1037
{
1038
    return "Divides input by the current time: yout[k] = y[k] / t[k]";
1039
}
1040

    
1041
void DivideByTimeNodeType::getAttributes(StringMap& attrs) const
1042
{
1043
}
1044

    
1045
Node *DivideByTimeNodeType::create(DataflowManager *mgr, StringMap& attrs) const
1046
{
1047
    checkAttrNames(attrs);
1048

    
1049
    Node *node = new DivideByTimeNode();
1050
    node->setNodeType(this);
1051
    mgr->addNode(node);
1052
    return node;
1053
}
1054

    
1055
void DivideByTimeNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
1056
{
1057
    if (attrs["type"] == "enum")
1058
        warnings.push_back(std::string("Applying '") + getName() + "' to an enum");
1059
    attrs["type"] = "double";
1060
}
1061

    
1062
// ---
1063

    
1064
bool TimeToSerialNode::isReady() const
1065
{
1066
    return in()->length()>0;
1067
}
1068

    
1069
void TimeToSerialNode::process()
1070
{
1071
    int n = in()->length();
1072
    for (int i=0; i<n; i++)
1073
    {
1074
        Datum d;
1075
        in()->read(&d,1);
1076
        d.x = serial;
1077
        d.xp = BigDecimal(serial);
1078
        serial++;
1079
        out()->write(&d,1);
1080
    }
1081
}
1082

    
1083
//--
1084

    
1085
const char *TimeToSerialNodeType::getDescription() const
1086
{
1087
    return "Replaces time values with their index: tout[k] = k";
1088
}
1089

    
1090
void TimeToSerialNodeType::getAttributes(StringMap& attrs) const
1091
{
1092
}
1093

    
1094
Node *TimeToSerialNodeType::create(DataflowManager *mgr, StringMap& attrs) const
1095
{
1096
    checkAttrNames(attrs);
1097

    
1098
    Node *node = new TimeToSerialNode();
1099
    node->setNodeType(this);
1100
    mgr->addNode(node);
1101
    return node;
1102
}
1103

    
1104
void TimeToSerialNodeType::mapVectorAttributes(/*inout*/StringMap &attrs, /*out*/StringVector &warnings) const
1105
{
1106
}
1107