C++ Simulate sequence of pulse trains

2019-07-27 13:50发布

问题:

I'm trying to model a pulse waveform in my application and I need a way to keep track of the pulses so that I can repeat their sequence. From the figure shown below, what I'd like to do is simulate the first three pulses (pulse 1-3), then simulate pulse 4 immediately after pulse 3, and simulate pulse 5 immediately after 4. Then repeat the whole sequence N times.

As shown in the diagram, I have the interval in seconds, the start time of the first pulse in seconds, and the duration of each pulse also in seconds. My application will be running real time in a run loop where it will be executing at 1 Hz.

My question is, how do I keep track of all the pulses and make sure they are all simulated with respect to each other? What I mean by simulated is, for example I'd like to print a simple statement during the duration of the 1st three pulses, and the same for pulse 4 and 5. Can someone suggest a pseudo algorithm at the very least for this operation?

回答1:

Defining the class sequence as follows, we can simply check activity of each pulse by sequence::isActive. DEMO is here.

class sequence
{    
    int period_;
    int start_;
    int end_;
    std::array<std::pair<int,int>, 5> pulses;

public:
    sequence(int start, int duration, int interval, int repeat) 
        : period_(2*interval+3*duration),
          start_(start),
          end_(start+repeat*period_),
          pulses
          {{
              {0                    , duration             }, // pulse 1
              {interval             , interval  +  duration}, // pulse 2
              {2*interval           , 2*interval+  duration}, // pulse 3
              {2*interval+  duration, 2*interval+2*duration}, // pulse 4
              {2*interval+2*duration, period_              }  // pulse 5
          }}
    {
        if(duration <= 0){
            throw std::runtime_error("Duration must be positive integer.");
        }

        if(interval < 0){
            throw std::runtime_error("Interval must be non negative integer.");
        }
    }

    bool isActive(int time, std::size_t idx) const
    {
        const auto& pulse = pulses[idx];

        // 0 for each start time of sequence (pulse 1)
        const auto refTime = (time - start_)%period_;

        return (pulse.first <= refTime) && (refTime < pulse.second) && (time < end_);
    }

    int getPeriod() const{
        return period_;
    }

    int getStartTime() const{
        return start_;
    }

    int getEndTime() const{
        return end_;
    }

    std::size_t getPulseNum() const{
        return pulses.size();
    }
};


回答2:

Assuming I understood the problem correctly, the way I would do it is to use modulo-arithmetic, and characterize each pulse-train as a boolean function with a timestamp as a parameter to the function, e.g.:

// Returns true iff the pulse is present at the specified time
bool IsPulseActiveAtTime(long int theTime);

The benefit of doing it this way is that you can simulate an infinite series of pulses while using only a small, fixed amount of memory. It also allows you to efficiently query what the expected state of each pulse-train was/will-be at any past/future time (i.e. not just as at the current time), should you need to do so.

Here's a simple demonstration program that prints out a ticker-tape of four pulses over the course of 100 simulated "seconds":

#include <stdio.h>

class PulseSequence
{
public:
   PulseSequence(long int startTime, long int duration, long int interval)
      : _startTime(startTime)
      , _duration(duration)
      , _interval(interval)
   {
      // empty
   }

   bool IsPulseActiveAtTime(long int theTime) const
   {
      if (theTime < _startTime) return false;
      return ((theTime-_startTime) % _interval) < _duration;
   }

private:
   const long int _startTime;  // time at which the first pulse starts
   const long int _duration;   // length of each pulse
   const long int _interval;   // difference between the start-time of one pulse and the start-time of the next
};

// Unit test/example
int main(int, char **)
{
   const int NUM_PULSE_SEQUENCES = 4;

   const PulseSequence sequences[NUM_PULSE_SEQUENCES] = {
      PulseSequence(0, 3, 5),
      PulseSequence(1, 2, 6),
      PulseSequence(3, 3, 4),
      PulseSequence(5, 1, 3),
   };

   for (long int curTime = 0; curTime < 100; curTime++)
   {
      printf("curTime=%02li: [", curTime);
      for (int i=0; i<NUM_PULSE_SEQUENCES; i++) putchar(sequences[i].IsPulseActiveAtTime(curTime)?('0'+i):' ');
      printf("]\n");
   }
   return 0;
}

The output looks like this:

$ ./a.out
curTime=00: [0   ]
curTime=01: [01  ]
curTime=02: [01  ]
curTime=03: [  2 ]
curTime=04: [  2 ]
curTime=05: [0 23]
curTime=06: [0   ]
curTime=07: [012 ]
curTime=08: [ 123]
curTime=09: [  2 ]
curTime=10: [0   ]
curTime=11: [0 23]
curTime=12: [0 2 ]
curTime=13: [ 12 ]
[...]