# Arduino Forum

## Using Arduino => Programming Questions => Topic started by: leo_pribram on Aug 01, 2020, 10:18 pm

Title: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 01, 2020, 10:18 pm
Hello,

My task is using millis()/micros() to generate on trigger consequences of pulses of predefined length (us) and period (ms), that are organized in the trains lasting predefined time (ms).

Trigger initiates first pulse in the train as soon as possible.

The trains are repeated at some intervals (ms) as long as the trigger is ON.

TWO (or more) channels are work independently. Tens of microseconds precision for pulses and tens of milliseconds for trains are acceptable.

Using this forum explanations (mainly Nick Gammon posts) I manage to generate regular pulses (without use of delay()), however how to organize nested cycles (I suppose that is what I need) for the trains of pulses and their intervals I do not know.

Would someone experienced be so kind as to provide me with an algorithm for this task.

Leo

PS below is an example of the trains:

|||||           |||||          |||||         |||||
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: gcjr on Aug 01, 2020, 10:30 pm
it's not clear if the pulses appear at fixed intervals or are asynchronous

an asynchronous approach might determined when the output needs to change state assuming pulse widths vary.     triggering a sequence may be more about determining a relative set of times (usec)

a synchronous approach would potentially modify the output at every possibly pulse period regardless if triggered.  outputting a steady zero is the equivalent of no pulses.   when triggered, a sequence is generated and that sequence used to set/clear the output every pulse interval regardless of whether the output changes state

the asynchronous approach probably uses fewer MIPS and has more flexibility
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: aarg on Aug 01, 2020, 10:51 pm
Also please specify min, typ and max intervals for the pulses and the spaces between. "us" and "ms" are entirely too vague.
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 01, 2020, 11:06 pm
Pulses appear at fix intervals. Pulses are from 0.1 to 20 ms, period is 2 -1000 ms, train is 0.1 - 2 s, interval between trains is 0.1 - 10 s.
Thanks,
Leo
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: 6v6gt on Aug 02, 2020, 09:17 am
I've done something similar for storing and retrieving pulses for an infrared protocol generator.
There, the timings were in an array something like:

Code: [Select]
`0: 90001: 45002:  5623:  5624:  5625: 1688`

where the timings were in microseconds and even indexes 0,2,4 etc. were pulse on periods and odd indexes 1,3,5 etc., were pulse off periods. Actually, these switched a carrier signal on and off. When an interval expired, the carrier was switched on or off as required and the next interval was read from the array.

Can you represent the timing sequences you have been given in such a way ?
Is the interval between repeating groups always the same ?

Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 02, 2020, 10:16 am
As far as I understood approach hidden in "gcjr" question on synchronous pulsing and "6v6gt" suggestion, my attempt to use micros() for building a sequences of pulses was a bad idea.

Should I do the following:
1. Form carrier pulses (let say 1 us) using timer
2. Redirect pulses in two channels if I need two of them, or use two timers
3. Make a switch on each channel (how?)
4. Somehow (how?) tell the switch that the conditions (trigger ON/OFF, pulse ON/OFF time, burst ON/OFF time, train ON/OFF time) are met, and let the switch to zeroing pulses for given period.

Another way to control the switches is calculating number of carrier pulses with counters.

Is this correct approach? Will it be more precise than one using micros()? if so, how the core of the program should look like?

Leo

Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: 6v6gt on Aug 02, 2020, 10:48 am
You must have clearer requirements than you are stating.

A 1uS carrier is 1MHz. That is very high considering the clock of the Arduino runs at 16MHz. The micros() function has a resolution of 4uS because it is driven by a 250kHz timer.
Are you using the same carrier frequency for the X channels you are hoping to drive ?
Are the channels to operate simultaneously ?
You can switch timer outputs on and off by multiple methods, e.g. setting the chosen output pin to input with pinMode() would work.
Counting the number of carrier pulses is good for the bursts if you drive a timer at the carrier frequency.
In the timer ISR, you can switch the carrier output on/off at the appropriate number of pulses. This is best done if your array, which stores the sequence of on/off intervals, contains the number of carrier pulses instead of a time in microseconds.
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 02, 2020, 11:59 am
I suppose that carrier frequency for all channels should be the same, is it?

Channels are operating asynchronously, each one react on its own trigger, however +/-10us in start of each channel does not matter for this type of experiments.

Most probably the approach that requires carrier frequency (including array with sequence of pulses, calculating pulses etc) will exceed my current experience (and mental ability :).

Below is what I managed to generate so far using millis(). However I still do not understand where to introduce code that will determine bursts of pulses (redLEDburst in ms). This code reproduce only one pulse at redLED interval:

Code: [Select]
`      if (digitalRead (redTrigger) == HIGH) {                  if ( millis () - redLEDforinterval >= redLEDinterval)    {              redLEDforinterval = millis ();                        if ( micros () - redLEDforperiod >= redLEDperiod)                   redLEDforperiod = micros();                redLEDforpulseWidth = micros();                }                                if (micros() - redLEDforpulseWidth <= redLEDpulseWidth) {                    digitalWrite (redLED, HIGH);                }  else digitalWrite(redLED, LOW);                                 }  else digitalWrite(redLED, LOW); `);
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: 6v6gt on Aug 02, 2020, 01:55 pm
from post #3:

>> Pulses appear at fix intervals. Pulses are from 0.1 to 20 ms, period is 2 -1000 ms, train is 0.1 - 2 s, interval between trains is 0.1 - 10 s.

In any given train of pulses, is the pulse length, wave period (pulse length + following space) , length of pulse train, and interval between pulse trains all constant ?

You have mentioned multiple channels. Is the output of each channel identical except for the phase shift caused by the different start times ?

Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: gcjr on Aug 02, 2020, 02:52 pm
i think "clocK" is more appropriate than "carrier".

don't understand the idea of a "switch" for multiple channels.  i assume each "channel" is a separate output pin and the data for each channel is independent of the other.

Pulses appear at fix intervals. Pulses are from 0.1 to 20 ms, period is 2 -1000 ms, train is 0.1 - 2 s, interval between trains is 0.1 - 10 s.
suggests the clock is every 100 msec usec, there could be 200 consecutive pulses that are "1" (20 ms) and up to 20,000 pulse (2s) per train.
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: gcjr on Aug 02, 2020, 03:05 pm
consider

Code: [Select]
`#define Chan0 10#define Chan1 11// -----------------------------------------------------------------------------// https://en.wikipedia.org/wiki/Linear-feedback_shift_registerint lfsr1(void){    static uint16_t start_state = 0xACE1u; /* Any nonzero will work. */    static uint16_t lfsr = start_state;    uint16_t bit;       /* Must be 16-bit to allow bit<<15 later in the code */    /* taps: 16 14 13 11; feedback polynomial: x^16 + x^14 + x^13 + x^11 + 1 */    bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5)) /* & 1u */;    lfsr = (lfsr >> 1) | (bit << 15);    return lfsr & 1;}// -----------------------------------------------------------------------------void setup() {    Serial.begin(115200);    Serial.print ("setup: ");    pinMode (Chan0, OUTPUT);    pinMode (Chan1, OUTPUT);}// -----------------------------------------------------------------------------void loop() {    static unsigned long msecLst = 0;           unsigned long msec    = millis();#define Period 100    if (msec - msecLst >= Period)  {        msecLst = msec;        digitalWrite (Chan0, lfsr1());        digitalWrite (Chan1, lfsr1());    }}`
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 02, 2020, 04:26 pm
"In any given train of pulses, is the pulse length, wave period (pulse length + following space) , length of pulse train, and interval between pulse trains all constant ?"

- Yes

"You have mentioned multiple channels. Is the output of each channel identical except for the phase shift caused by the different start times ?"

- No, timing is (or can be) different.

To gcjr: Thanks for the example. Each channel is indeed a separate output.
"Linear-feedback_shift_register" is a new concept for me, I'll try to understand it and its application for the task.

Leo
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: aarg on Aug 02, 2020, 05:21 pm
Linear-feedback_shift_register" is a new concept for me, I'll try to understand it and its application for the task.
It has no application for your task. It only generates a test stream to support the example.
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: jimLee on Aug 02, 2020, 07:35 pm
Going over all this, it looks to me like you have a high frequency being toggled on and off by a low frequency. Am I right on this?

-jim lee
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: 6v6gt on Aug 02, 2020, 07:50 pm
@gcjr has produced an impressively compact solution.

I've just put this one together, based on a finite state machine model.

Code: [Select]
`class PulseTrain {    enum state_t { WAIT, TRAIN_TRIGGERED, IN_CARRIER_MARK, IN_CARRIER_SPACE, IN_TRAIN_SPACE, AT_END } ;    state_t state = WAIT ;    // from constructor    uint8_t _pulsePin ;    uint32_t _pulseLengthUs ;    uint32_t _pulseSpaceUs ;    uint32_t _trainLengthMs ;    uint32_t _trainSpaceMs ;    uint32_t trainStartMs ;    uint32_t trainSpaceStartMs ;    uint32_t pulseStartUs ;    uint32_t pulseSpaceStartUs ;  public:    PulseTrain( uint8_t pulsePin, uint32_t pulseLengthUs, uint32_t pulseSpaceUs, uint32_t trainLengthMs, uint32_t trainSpaceMs )    {      _pulsePin = pulsePin ;      _pulseLengthUs = pulseLengthUs ;      _pulseSpaceUs = pulseSpaceUs ;      _trainLengthMs = trainLengthMs ;      _trainSpaceMs = trainSpaceMs ;    }    void begin()    {      pinMode( _pulsePin, OUTPUT ) ;    }    void triggerOn()    {      state = TRAIN_TRIGGERED ;    }    void triggerOff()    {      state = AT_END ;    }    void loop() ;} ;void PulseTrain::loop(){  switch ( state ) {    case TRAIN_TRIGGERED :      trainStartMs = millis() ;      pulseStartUs = micros() ;      state = IN_CARRIER_MARK ;      digitalWrite( _pulsePin, HIGH ) ;      break ;    case IN_CARRIER_MARK :      if ( micros()  - pulseStartUs > _pulseLengthUs ) {        // end of pulse        pulseSpaceStartUs = micros() ;        state = IN_CARRIER_SPACE ;        digitalWrite( _pulsePin, LOW ) ;      }      else if ( millis() - trainStartMs > _trainLengthMs ) {        // end of train        trainSpaceStartMs = millis() ;        state = IN_TRAIN_SPACE ;        digitalWrite( _pulsePin, LOW ) ;      }      break ;    case IN_CARRIER_SPACE :      if ( micros()  - pulseSpaceStartUs > _pulseSpaceUs ) {        // start of pulse        pulseStartUs = micros() ;        state = IN_CARRIER_MARK ;        digitalWrite( _pulsePin, HIGH ) ;      }      else if ( millis() - trainStartMs > _trainLengthMs ) {        // end of train        trainSpaceStartMs = millis() ;        state = IN_TRAIN_SPACE ;        digitalWrite( _pulsePin, LOW ) ;      }      break ;    case IN_TRAIN_SPACE :      if ( millis() - trainSpaceStartMs > _trainSpaceMs ) {        state = TRAIN_TRIGGERED ;      }      break ;    case AT_END :      digitalWrite( _pulsePin, LOW ) ;      state = WAIT ;      break ;    case WAIT :      // do nothing      break ;  }}PulseTrain testSequence1( 12, 10000UL , 20000UL , 1000 , 2000 ) ;  // define test sequence 1PulseTrain testSequence2( 13, 20000UL , 50000UL , 1000 , 3000 ) ;  // define test sequence 2void setup() {  testSequence1.begin() ;  testSequence1.triggerOn() ;   // trigger test sequence 1  testSequence2.begin() ;  testSequence2.triggerOn() ;   // trigger test sequence 2}void loop() {  testSequence1.loop() ;  testSequence2.loop() ;}`

and the output from channel testSequence2 (pin 13)

(https://forum.arduino.cc/index.php?action=dlattach;topic=698461.0;attach=375844)
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: jimLee on Aug 03, 2020, 06:33 pm
Here's is another approach.

Code: [Select]
`#include "squareWave.h"#include "blinker.h"// ************************************************************** // doubleWave class// **************************************************************class doubleWave : public blinker {   public:               doubleWave(int pinNum, float hfPulseMs, float hfPeriodMs,float lfPulseMs,float lfPeriodMs);   virtual     ~doubleWave(void);               void  trigger(bool onOff);   virtual     void  pulseOn(void);   virtual     void  pulseOff(void);                  blinker     hfWave;};               doubleWave::doubleWave(int pinNum, float hfPulseMs,float hfPeriodMs,float lfPulseMs, float lfPeriodMs)   : blinker(pinNum,lfPulseMs,lfPeriodMs) {      hfWave.setPeriod(hfPeriodMs);   hfWave.setPulse(hfPulseMs);}   doubleWave::~doubleWave(void) {  }void doubleWave::pulseOn(void) { hfWave.setOnOff(true); }void doubleWave::pulseOff(void) { hfWave.setOnOff(false); }             // **************************************************************// And we make it go..// **************************************************************doubleWave blinky(13,20,100,1000,2000); // Devine your double waves. (YOu can crreate as many as you like..)void setup() {      blinky.setOnOff(true);  // Turn it on..}void loop() {    idle();                  // Let the idlers have some time.}`

You'll need this library..
LC_baseTools (https://github.com/leftCoast/LC_baseTools)

But this lets you spawn as many of these "complicated pulse patters" as you want.

-jim lee
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 03, 2020, 09:57 pm
My special thanks to gcjr for the idea of the approach and to 6v6gt for the code. I hope I'll be able to understand all its detals...

Regards,
Leo
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: leo_pribram on Aug 04, 2020, 09:38 pm
jimLee thank you for the coding example and reffering a new library.

Best,
Leo
Title: Re: Algorithm for generating complicated pattens of pulses on several channels
Post by: jimLee on Aug 05, 2020, 03:30 am
You are very welcome!

-jim lee