Module: Radio::Filter::Iq

Defined in:
lib/radio/filters/iq.rb

Defined Under Namespace

Modules: Complex

Instance Method Summary collapse

Instance Method Details

#adjust!(data, phase, gain) ⇒ Object



106
107
108
109
110
# File 'lib/radio/filters/iq.rb', line 106

def adjust! data, phase, gain
  data.collect! do |v|
    Complex(v.real + phase * v.imag, v.imag * gain)
  end
end

#analyzeObject

Once per call, we will do an FFT to either start a new round of guessing or try again on the current set.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/radio/filters/iq.rb', line 70

def analyze
  return unless @cur_fft or @next_fft
  if !@cur_fft_count or @cur_fft_count > @tries
    @cur_fft = @next_fft
    @cur_fft_count = 0
    fft = @cur_fft.dup
    adjust! fft, @phase, @gain
    @cur_fft_best = detect_energies FFTW3::fft(fft)
  else
    @cur_fft_count += 1
    phaseIncrement = @iq_rate * rand_direction
    gainIncrement = @iq_rate * rand_direction
    fft = @cur_fft.dup
    adjust! fft, @phase + phaseIncrement, @gain + gainIncrement
    det = detect_energies FFTW3::fft(fft)
    if det > @cur_fft_best
      @cur_fft_best = det
      @gain += gainIncrement
      @phase += phaseIncrement
    end
  end
end

#collect(data) ⇒ Object

This maintains a buffer of recent data that we can grab for analysis



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/radio/filters/iq.rb', line 50

def collect data
  i = 0
  data_size = data.size
  while i < data_size
    remaining = data_size - i
    space = @bins - @fft_pos
    actual = [remaining,space].min
    new_fft_pos = @fft_pos + actual
    @fft[@fft_pos...new_fft_pos] = data[i...i+actual]
    @fft_pos = new_fft_pos
    if @fft_pos == @bins
      @fft_pos = 0
      @next_fft = @fft.dup
    end
    i += actual
  end
end

#detect_energies(spectrum) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/radio/filters/iq.rb', line 112

def detect_energies spectrum
  result = 0.0
  length = @bins.size
  halfLength = length / 2
  start = (0.20 * halfLength).round
  finish = (0.90 * halfLength).round
  spectrum = spectrum.abs
  frag = spectrum[start..finish]
  min = frag.min
  max = frag.max
  threshold = max - (max-min) * 0.5
  (start..finish).each do |i|
    cur = spectrum[length - 1 - i]
    next unless cur > threshold
    diff = cur - spectrum[i]
    next unless diff > 0
    result += diff
  end
  result
end

#rand_directionObject

this is the IQ detection idea from the sdr# project



134
135
136
# File 'lib/radio/filters/iq.rb', line 134

def rand_direction
  rand*2-1
end

#remove_dc_bias!(data) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/radio/filters/iq.rb', line 94

def remove_dc_bias! data
  data.collect! do |v|
    temp = @biasI * (1 - @dc_rate) + v.real * @dc_rate
    @biasI = temp unless temp.nan?
    real = v.real - @biasQ
    temp = @biasQ * (1 - @dc_rate) + v.imag * @dc_rate
    @biasQ = temp unless temp.nan?
    imag = v.imag - @biasQ
    Complex(real,imag)
  end
end

#setupObject



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/radio/filters/iq.rb', line 21

def setup
  @bins = 512
  @tries = 5
  @dc_rate = 0.00001
  @iq_rate = 0.0001
  @biasI = 0.0
  @biasQ = 0.0
  @gain = 1.0
  @phase = 0.0
  @fft = NArray.scomplex @bins
  @fft_pos = 0
end