Class: PWN::SDR::Decoder::Morse::Demod

Inherits:
Object
  • Object
show all
Defined in:
lib/pwn/sdr/decoder/morse.rb

Overview

Stateful, streaming CW demodulator fed by Base.run_native.

Instance Method Summary collapse

Constructor Details

#initialize(rate: 48_000) ⇒ Demod

Returns a new instance of Demod.



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/pwn/sdr/decoder/morse.rb', line 17

def initialize(rate: 48_000)
  @rate    = rate
  # single-pole low-pass on |x|; τ ≈ 5 ms
  @env_a   = Math.exp(-1.0 / (rate * 0.005))
  @env     = 0.0
  @floor   = 0.0
  @peak    = 0.0
  @state   = :off
  @run     = 0
  @dit     = rate * 60 / 1000 # seed 60 ms (≈ 20 WPM)
  @sym     = +''
  @word    = +''
end

Instance Method Details

#feed(samples) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/pwn/sdr/decoder/morse.rb', line 31

def feed(samples, &)
  samples.each do |x|
    @env = (@env_a * @env) + ((1.0 - @env_a) * x.abs)
    # slow trackers for adaptive threshold (attack fast, decay slow)
    @peak  = @env > @peak ? ((@peak * 0.7) + (@env * 0.3)) : (@peak * 0.9999)
    @floor = @env < @floor ? @env : ((@floor * 0.9999) + (@env * 0.0001))
    thresh = @floor + ((@peak - @floor) * 0.4)
    on = @env > thresh && (@peak - @floor) > 0.01
    if on == (@state == :on)
      @run += 1
    else
      classify_run(&)
      @state = on ? :on : :off
      @run   = 1
    end
  end
  return unless @state == :off && @run > 5 * @dit && !(@sym.empty? && @word.empty?)

  flush_char
  flush_word(&)
end