
\ Signal processing for buffered Loran-C samples
\ This includes all the logic for a navigation receiver
\  - Signal quality report
\  - Convolution with pulse share filter
\  - Quest for Master and Slave pulse trains
\  - Calculation of Time Delays

\ Needs loran.txt

compiletoflash

\ -----------------------------------------------------------------------------
\  Calculate ADC voltages
\ -----------------------------------------------------------------------------

: f.n ( ncomma nwhole ndigits )
  >r
      tuck     ( nwhole ncomma nwhole )
      dabs     ( nwhole ucomma uwhole )
      0        ( nwhole ucomma uwhole 0 )
      <# #s    ( nwhole ucomma 0 0 )

      [char] , hold<
      rot      ( nwhole 0 0 ucomma )
  r> 0 ?do f# loop ( nwhole 0 0 ucomma )
      drop     ( nwhole 0 0 )

      rot      ( 0 0 nwhole )
      sign     ( 0 0 )

      #> type space ;

3,0 2variable vcc \ You can adjust value on the fly

: voltage. ( u -- )
  0 swap vcc 2@ 4096,0 f/ f*  4 f.n ." V "
;

: adc+voltage. ( u -- )
  dup . ." = " voltage.
;

\ -----------------------------------------------------------------------------
\  Get signal quality estimations
\ -----------------------------------------------------------------------------

: d/ ( d1 d2 -- d3 ) d/mod 2nip ;

: offset-double ( -- Offset )  
  0. gri@ 0 do i getsample s>d d+ loop \ Calculate offset with double intermediate result
  gri@ 0 d/ drop
;

: signedmax ( -- n ) \ Search for maximum value in buffer
  0 getsample
  gri@ 1 do i getsample max loop
;

: signedmin ( -- n ) \ Search for minimum value in buffer
  0 getsample
  gri@ 1 do i getsample min loop
;

0 variable noiseoffset

: noiselevel ( -- amplitude )
  \ Sum absolute differences to offset with double intermediate result
  0. gri@ 0 do i getsample noiseoffset @ - abs 0 d+ loop
  gri@ 0 d/ drop
;

: signalquality ( -- ) \ Prints current signal specifications
  offset-double dup noiseoffset ! 
  ." Offset " dup . ." ADC: " latestgris @ /  offset@ + voltage. cr
  noiselevel ." Noise amplitude " dup . ." ADC: " latestgris @ / voltage. cr
  signedmin ." Miminum value " dup . ." ADC: " latestgris @ / offset@ +  voltage. cr
  signedmax ." Maximum value " dup . ." ADC: " latestgris @ / offset@ +  voltage. cr
;

\ -----------------------------------------------------------------------------
\  Convolve the buffer contents with Loran-C pulse shape
\ -----------------------------------------------------------------------------

: offsetcorrection ( -- )
  \ Offset correction necessary because absolute values of negative and positive amplitudes will be compared later
  offset-double negate noiseoffset ! 
  gri@ 0 do noiseoffset @ i sample>address h+! loop
;

: convolution ( -- )
  led-blue portd-set h!
  offsetcorrection
  0 sample>address  gri@ sample>address  480 2* move    \ Copy the first samples at the end of the buffer for convolution to wrap over
  gri@ 0 do i pulseconvolution 16 rshift i sample>address h! loop  \ Apply convolution on whole buffer.
  led-blue portd-reset h!
;

\ -----------------------------------------------------------------------------
\  Find pulse trains and calculate TDs
\ -----------------------------------------------------------------------------

: wrap-sample>address ( sample# -- address )
  dup gri@ u>= if gri@ - then
  sample>address
;

: getmastertrain ( sample -- value ) \ Pulse Polarity: + - + +
  >r
  r@             sample>address h@ sign16
  r@ 2000 + wrap-sample>address h@ sign16 -
  r@ 4000 + wrap-sample>address h@ sign16 +
  r> 6000 + wrap-sample>address h@ sign16 +
  abs
;

: getslavetrain ( sample -- value ) \ Pulse Polarity: + + + -
  >r
  r@             sample>address h@ sign16
  r@ 2000 + wrap-sample>address h@ sign16 +
  r@ 4000 + wrap-sample>address h@ sign16 +
  r> 6000 + wrap-sample>address h@ sign16 -
  abs
;

: inside ( x low high -- flag ) over - >r - r>  u<= ;

: notinenvironment ( x location -- flag )
  \ Different pulse trains are at least 9900 us apart.
  \ Convolution envelope needs a "blanking out" of at least 6500 us
  \ in both directions. 7000 us seem to be a good value.

  dup ( x location location )
  7000 - dup 0< if gri@ + then \ Prepare lower limit
  ( x location low )
  swap
  ( x low location )
  7000 + dup gri@ >= if gri@ - then \ Prepare upper limit
  ( x low high )
  inside not
;

3 variable stations  \ 3 stations M, X, Y as for Sylt chain. 
                     \ Change to 4 for Lessay chain which has M, X, Y, Z.

0     variable location1
0     variable amplitude1
false variable type1

0     variable location2
0     variable amplitude2
false variable type2

0     variable location3
0     variable amplitude3
false variable type3

0     variable location4
0     variable amplitude4
false variable type4


: findpulsetrains ( -- )

  \ -----------------------------------------------------------------------------
  \ Search for most intense pulse train

  0 location1 !  0 amplitude1 !
  gri@ 0 do
    i getmastertrain i getslavetrain umax
    dup amplitude1 @ u>= if i location1 ! amplitude1 ! else drop then
  loop

  \ Check type of most intense pulse train
  location1 @ getmastertrain
  location1 @ getslavetrain u>= 
  dup type1 ! \ True for Master pulse chain
  if ." Master " else ." Slave  " then ." pulse train at " location1 @ u. ." us with intensity " amplitude1 @ u. ." found." cr

  \ -----------------------------------------------------------------------------
  \ Search for second most intense pulse train
  0 location2 !  0 amplitude2 !
  gri@ 0 do
    i location1 @ notinenvironment
    if
      i getmastertrain i getslavetrain umax
      dup amplitude2 @ u>= if i location2 ! amplitude2 ! else drop then
    then
  loop
  
  \ Check type of second most intense pulse train
  location2 @ getmastertrain
  location2 @ getslavetrain u>= 
  dup type2 ! \ True for Master pulse chain
  if ." Master " else ." Slave  " then ." pulse train at " location2 @ u. ." us with intensity " amplitude2 @ u. ." found." cr

  \ -----------------------------------------------------------------------------
  \ Search for third most intense pulse train

  0 location3 !  0 amplitude3 !
  gri@ 0 do
    i location1 @ notinenvironment
    i location2 @ notinenvironment and
    if
      i getmastertrain i getslavetrain umax
      dup amplitude3 @ u> if i location3 ! amplitude3 ! else drop then
    then
  loop
  
  \ Check type of second most intense pulse train
  location3 @ getmastertrain
  location3 @ getslavetrain u>= 
  dup type3 ! \ True for Master pulse chain
  if ." Master " else ." Slave  " then ." pulse train at " location3 @ u. ." us with intensity " amplitude3 @ u. ." found." cr

  stations @ 3 <= if exit then \ Save calculation time if three stations are available only

  \ -----------------------------------------------------------------------------
  \ Search for fourth most intense pulse train

  0 location4 !  0 amplitude4 !
  gri@ 0 do
    i location1 @ notinenvironment
    i location2 @ notinenvironment and
    i location3 @ notinenvironment and
    if
      i getmastertrain i getslavetrain umax
      dup amplitude4 @ u> if i location4 ! amplitude4 ! else drop then
    then
  loop
  
  \ Check type of second most intense pulse train
  location4 @ getmastertrain
  location4 @ getslavetrain u>= 
  dup type4 ! \ True for Master pulse chain
  if ." Master " else ." Slave  " then ." pulse train at " location4 @ u. ." us with intensity " amplitude4 @ u. ." found." cr

; \ -----------------------------------------------------------------------------

: timedelay ( master slave -- td ) \ Calculate delay with GRI wrap over

  2dup <= if swap - else gri@ + swap - then

  \    if a <= b then distance := b - a
  \              else distance := gri - a + b;
;

: calculatetds ( -- ) \ Calculate Time Delays with given pulse trains.
  ." TDs: "           \ They are given in pulse decreasing train intensity order.

  type1 @ if          location1 @ location2 @ timedelay u.
                      location1 @ location3 @ timedelay u.
    stations @ 3 > if location1 @ location4 @ timedelay u. then
    cr
  then

  type2 @ if          location2 @ location1 @ timedelay u.
                      location2 @ location3 @ timedelay u.
    stations @ 3 > if location2 @ location4 @ timedelay u. then
    cr
  then

  type3 @ if          location3 @ location1 @ timedelay u.
                      location3 @ location2 @ timedelay u.
    stations @ 3 > if location3 @ location4 @ timedelay u. then
    cr
  then

  stations @ 4 >=
  if
    type4 @ if        location4 @ location1 @ timedelay u.
                      location4 @ location2 @ timedelay u.
                      location4 @ location3 @ timedelay u.
      cr
    then
  then
;

\ -----------------------------------------------------------------------------
\  Finally: Where am I ? One complete measurement.
\  Frequency calibration has to be done before running this.
\ -----------------------------------------------------------------------------

: capture-advanced ( -- )
  offsetmeasurement
  offset@ ." Analog DC offset: " adc+voltage. cr
  griscapture @ samplegris
  signalquality
;

: locate ( -- )
  \ Switch off interrupt handler during calculations for speed
  \ No need to keep in sync meanwhile
  dint
  convolution
  findpulsetrains
  calculatetds
  eint
;

: l ( -- )
  capture-advanced
  locate
;
