You are reading a single comment by @BitMeddler and its replies. Click here to read the full conversation.
  • Thanks Gordon,

    I've been developing the idea fully in JS, but from the outset I suspected I'd have to compile it, or perhaps bash it out in ASM.

    function BiPhaseDecoder() {
      // gaps
      this.last_B_period = 0.0 ;
      this.this_period   = 0.0 ;
      this.big_periods   = 0.0 ;
      this.small_periods = 0.0 ;
      // FSM
      this.in_long_gap   = false ;
      this.in_first_half = false ;
      // booting
      this.till_booted   = 32 ; // arbitrary
      // The bit I'm decoding
      this.bit           = -1 ;
    
      // register Event
      this.bitEvent = function(){};
    }
    
    // process
    BiPhaseDecoder.prototype.tick = function( event_data ) {
      // get the time since last crossing
      this.this_period = (event_data.time - event_data.lastTime) ;
      // determine if it's a long or short period
      // cf: http://www.avrfreaks.net/forum/tut-pc-av­r-softunderstanding-bi-phase-mark-coding­
      // "If it's more than 3/4 of the bit period, you've just received a zero;
      // otherwise, you got half of a one."
      // Note: by only ever comparing current period to long-ifyied last period, we
      // can tolerate increases in speed of transmission, if gradual; and need no
      // a priori data on expected rate / samps per sec.
      if( (this.this_period * 4.0) > (this.last_B_period * 3.0) ) {
        // this is a long period
        this.last_B_period = this.this_period ;
        this.in_long_gap   = true ;
        // get stats
        this.big_periods += this.this_period ;
        this.big_periods *= 0.5 ;
      } else {
        // otherwise a short period
        this.last_B_period = this.this_period * 2.0 ; // last_B_period is always big
        this.in_long_gap   = false ;
        // get stats
        this.small_periods += this.this_period ;
        this.small_periods *= 0.5 ;
      } // if this_period > (3/4 * last_B_period)
    
      // a long gap == bit 0; or two short gaps == bit 1
      if( this.in_long_gap ) {
        this.in_first_half = false ;
        this.bit = 0 ;
      } else {
        if (this.in_first_half) {
          this.in_first_half = false ;
          this.bit = 1 ;
        } else {
          this.in_first_half = true ;
          this.bit = -1 ; // not ready to TX yet
        }
      } // if in_long_gap
      
      if( this.till_booted < 0 ) {
        // emit the bit if ready
        if( (this.bit >= 0) ) {
          this.bitEvent( this.bit ) ;
        }
      } else {
        // it will take some time to get a good sampling of big and small periods
        this.till_booted-- ;
        // keep flushing the stats till it stabilizes
        this.big_periods   = 0.0 ;
        this.small_periods = 0.0 ;
        // possibly, 'if( Math.abs( (small * 2.0) - big ) < 1e-5 ) till_booted = -1 ;'
      } // if booted
    } ;
    

    Which is pretty heavy, but easier to debug. This method makes no assumptions about the short bit period, and would tolerate a 'ripple' in the transmission rate. First step would be minifying it I guess, and maybe ditching the avg. gap length I'm keeping.

    I'm then pushing the 'bit' into a Uint16Array - like a LIFO - lots of shifts and carrys (probably better in ASM too) then it's just 'bitfield[4] & 0x3FFD' to find the sync word.

    I didn't know about the x.y.bind(x) gotcha - thanks for that.

About

Avatar for BitMeddler @BitMeddler started