radio 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +1 -0
- data/lib/radio.rb +14 -0
- data/lib/radio/psk31/bit_detect.rb +46 -0
- data/lib/radio/psk31/decoder.rb +65 -0
- data/lib/radio/psk31/filters.rb +220 -0
- data/lib/radio/psk31/fir_coef.rb +287 -0
- data/lib/radio/psk31/rx.rb +52 -0
- data/lib/radio/psk31/varicode.rb +275 -0
- metadata +54 -0
data/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Amateur radio software
|
data/lib/radio.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Radio
|
|
2
|
+
|
|
3
|
+
class PSK31
|
|
4
|
+
|
|
5
|
+
class BitDetect
|
|
6
|
+
|
|
7
|
+
AVG_SAMPLES = 50.freeze
|
|
8
|
+
CHANGE_DELAY = 5
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@averages = Array.new 21
|
|
12
|
+
reset
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def reset
|
|
16
|
+
@averages.fill 0.0
|
|
17
|
+
@phase = 0
|
|
18
|
+
@peak = 0
|
|
19
|
+
@next_peak = 0
|
|
20
|
+
@change_at = 0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call sample_x, sample_y
|
|
24
|
+
yield if @phase == @peak
|
|
25
|
+
@peak = @next_peak if @phase == @change_at
|
|
26
|
+
energy = sample_x**2 + sample_y**2
|
|
27
|
+
@averages[@phase] = (1.0-1.0/AVG_SAMPLES)*@averages[@phase] + (1.0/AVG_SAMPLES)*energy
|
|
28
|
+
@phase += 1
|
|
29
|
+
if @phase > 15
|
|
30
|
+
@phase = 0
|
|
31
|
+
max = -1e10
|
|
32
|
+
for i in 0...16
|
|
33
|
+
energy = @averages[i]
|
|
34
|
+
if energy > max
|
|
35
|
+
@next_peak = i
|
|
36
|
+
@change_at = (i + CHANGE_DELAY) & 0x0F
|
|
37
|
+
max = energy
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class Radio
|
|
2
|
+
class PSK31
|
|
3
|
+
|
|
4
|
+
class Decoder
|
|
5
|
+
|
|
6
|
+
attr_accessor :mode # :bpsk or :qpsk or :qpsklsb
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@mode = :bpsk
|
|
10
|
+
reset
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def reset
|
|
14
|
+
@prev_i = 0.0
|
|
15
|
+
@prev_q = 0.0
|
|
16
|
+
@this_i = 0.0
|
|
17
|
+
@this_q = 0.0
|
|
18
|
+
@code = 0
|
|
19
|
+
@prev_bit = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def call new_i, new_q
|
|
23
|
+
@prev_i = @this_i
|
|
24
|
+
@prev_q = @this_q
|
|
25
|
+
@this_i = new_i
|
|
26
|
+
@this_q = new_q
|
|
27
|
+
vect_y = @prev_i*@this_i + @prev_q*@this_q
|
|
28
|
+
if @mode == :bpsk
|
|
29
|
+
bit = vect_y >= 0.0 ? 1 : 0
|
|
30
|
+
else
|
|
31
|
+
vect_x = @prev_i*@this_q - @this_i*@prev_q
|
|
32
|
+
if vect_y == 0.0 # atan2 errors on (0,0)
|
|
33
|
+
angle = PI
|
|
34
|
+
elsif @mode == :qpsklsb
|
|
35
|
+
angle = PI + Math.atan2(vect_y, -vect_x)
|
|
36
|
+
else # :qpsk or :bpsk
|
|
37
|
+
angle = PI + Math.atan2(vect_y, vect_x)
|
|
38
|
+
end
|
|
39
|
+
bit = viterbi angle
|
|
40
|
+
end
|
|
41
|
+
if bit==0 and @prev_bit==0
|
|
42
|
+
if @code != 0
|
|
43
|
+
@code >>= 2
|
|
44
|
+
@code &= 0x07FF
|
|
45
|
+
ch = VARICODE_DECODE_TABLE[@code]
|
|
46
|
+
yield ch if ch
|
|
47
|
+
@code = 0
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
@code <<= 1
|
|
51
|
+
@code |= bit
|
|
52
|
+
@prev_bit = bit
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def viterbi
|
|
59
|
+
raise 'todo'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
class Radio
|
|
2
|
+
|
|
3
|
+
class PSK31
|
|
4
|
+
|
|
5
|
+
# An instance of Filters handles everything from 48kHz to 500Hz.
|
|
6
|
+
# PSK31/PSK63/PSK125 emit at 500Hz/1000Hz/2000Hz respectively.
|
|
7
|
+
|
|
8
|
+
class Filters
|
|
9
|
+
|
|
10
|
+
attr_accessor :frequency
|
|
11
|
+
attr_accessor :clock # 8000.0 +/-
|
|
12
|
+
attr_accessor :phase_inc
|
|
13
|
+
attr_accessor :speed # 31 | 63 | 125
|
|
14
|
+
|
|
15
|
+
# Format of the input data stream is specified in the same
|
|
16
|
+
# format as String#unpack. Here are some examples:
|
|
17
|
+
# 'C' 8-bit unsigned mono
|
|
18
|
+
# 'xxv' Little-endian 16-bit right channel
|
|
19
|
+
# Not everything is supported outside this native Ruby implementation.
|
|
20
|
+
# The following are guaranteed to be in a C or Java implementation.
|
|
21
|
+
# x - ignores a byte (in an unused channel)
|
|
22
|
+
# C/c - Unsigned/signed bytes
|
|
23
|
+
# n/v - Unsigned 16-bit words in big/little endian format
|
|
24
|
+
|
|
25
|
+
# You must supply at least one of the dec16, dec8, or dec4 filters and
|
|
26
|
+
# it must be appropriate for the speed you desire. The dec4 filter can
|
|
27
|
+
# be used for all speeds, dec8 only for PSK63, and dec16 only for PSK31.
|
|
28
|
+
|
|
29
|
+
def initialize sample_rate, format, frequency, filters
|
|
30
|
+
@do_dec6 = case sample_rate
|
|
31
|
+
when 8000 then false
|
|
32
|
+
when 48000 then true
|
|
33
|
+
else raise 'only 8000 and 48000 Hz sample rates are supported'
|
|
34
|
+
end
|
|
35
|
+
@format = format
|
|
36
|
+
@sample_size = [0].pack(format).size
|
|
37
|
+
case ("\x80"*16).unpack(format)[0]
|
|
38
|
+
when 128
|
|
39
|
+
@max = 128
|
|
40
|
+
@offset = -128
|
|
41
|
+
when -128
|
|
42
|
+
@max = 128
|
|
43
|
+
@offset = 0
|
|
44
|
+
when 32768 + 128
|
|
45
|
+
@max = 32768
|
|
46
|
+
@offset = -32768
|
|
47
|
+
when -32768 + 128
|
|
48
|
+
@max = 32768
|
|
49
|
+
@offset = 0
|
|
50
|
+
else
|
|
51
|
+
raise 'unable to interpret format'
|
|
52
|
+
end
|
|
53
|
+
@frequency = frequency
|
|
54
|
+
@clock = 8000.0
|
|
55
|
+
@phase = 0.0
|
|
56
|
+
@speed = 31
|
|
57
|
+
@pulse = 0
|
|
58
|
+
if filters[:dec6]
|
|
59
|
+
@dec6_coef = NArray.to_na filters[:dec6]*2
|
|
60
|
+
@dec6_data = NArray.float filters[:dec6].size
|
|
61
|
+
@dec6_pos = 0
|
|
62
|
+
@dec6_pulse = 6
|
|
63
|
+
elsif @do_dec6
|
|
64
|
+
raise 'no 48000 Hz filter found'
|
|
65
|
+
end
|
|
66
|
+
if filters[:dec16]
|
|
67
|
+
@dec16_coef = NArray.to_na filters[:dec16]*2
|
|
68
|
+
@dec16_sin = NArray.float filters[:dec16].size
|
|
69
|
+
@dec16_cos = NArray.float filters[:dec16].size
|
|
70
|
+
@dec16_pos = 0
|
|
71
|
+
else
|
|
72
|
+
@dec16_coef = nil
|
|
73
|
+
end
|
|
74
|
+
if filters[:dec8]
|
|
75
|
+
@dec8_coef = NArray.to_na filters[:dec8]*2
|
|
76
|
+
@dec8_sin = NArray.float filters[:dec8].size
|
|
77
|
+
@dec8_cos = NArray.float filters[:dec8].size
|
|
78
|
+
@dec8_pos = 0
|
|
79
|
+
else
|
|
80
|
+
@dec8_coef = nil
|
|
81
|
+
end
|
|
82
|
+
if filters[:dec4]
|
|
83
|
+
@dec4_coef = NArray.to_na filters[:dec4]*2
|
|
84
|
+
@dec4a_sin = NArray.float filters[:dec4].size
|
|
85
|
+
@dec4a_cos = NArray.float filters[:dec4].size
|
|
86
|
+
@dec4a_pos = 0
|
|
87
|
+
@dec4b_sin = NArray.float filters[:dec4].size
|
|
88
|
+
@dec4b_cos = NArray.float filters[:dec4].size
|
|
89
|
+
@dec4b_pos = 0
|
|
90
|
+
else
|
|
91
|
+
@dec4_coef = nil
|
|
92
|
+
end
|
|
93
|
+
@bit_coef = NArray.to_na filters[:bit]*2
|
|
94
|
+
@bit_sin = NArray.float filters[:bit].size
|
|
95
|
+
@bit_cos = NArray.float filters[:bit].size
|
|
96
|
+
@bit_pos = 0
|
|
97
|
+
recalc_phase_inc
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def reset
|
|
101
|
+
if @dec6_coef
|
|
102
|
+
@dec6_data.fill 0.0
|
|
103
|
+
end
|
|
104
|
+
if @dec16_coef
|
|
105
|
+
@dec16_sin_data.fill 0.0
|
|
106
|
+
@dec16_cos_data.fill 0.0
|
|
107
|
+
end
|
|
108
|
+
if @dec8_coef
|
|
109
|
+
@dec8_sin_data.fill 0.0
|
|
110
|
+
@dec8_cos_data.fill 0.0
|
|
111
|
+
end
|
|
112
|
+
if @dec4_coef
|
|
113
|
+
@dec4a_sin.fill 0.0
|
|
114
|
+
@dec4a_cos.fill 0.0
|
|
115
|
+
@dec4b_sin.fill 0.0
|
|
116
|
+
@dec4b_cos.fill 0.0
|
|
117
|
+
end
|
|
118
|
+
@bit_sin.fill 0.0
|
|
119
|
+
@bit_cos.fill 0.0
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def recalc_phase_inc
|
|
123
|
+
@phase_inc = PI2 * @frequency / @clock
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def call sample_data
|
|
127
|
+
raise 'alignment error' unless sample_data.size % @sample_size == 0
|
|
128
|
+
sample_data.force_encoding('binary') # Ensure slice is fast like Ruby 1.9.3 byteslice
|
|
129
|
+
mod16_8 = @speed == 63 ? 8 : 16
|
|
130
|
+
pos = 0
|
|
131
|
+
while pos < sample_data.size
|
|
132
|
+
pos += @sample_size
|
|
133
|
+
sample = sample_data.slice(pos,@sample_size).unpack(@format)[0] || 0
|
|
134
|
+
sample = (sample + @offset).to_f / @max
|
|
135
|
+
if @do_dec6
|
|
136
|
+
@dec6_pos = @dec6_data.size if @dec6_pos == 0
|
|
137
|
+
@dec6_pos -= 1
|
|
138
|
+
@dec6_data[@dec6_pos] = sample
|
|
139
|
+
@dec6_pulse -= 1
|
|
140
|
+
next unless @dec6_pulse == 0
|
|
141
|
+
@dec6_pulse = 6
|
|
142
|
+
sample = @dec6_data.fir(@dec6_coef, @dec6_pos)
|
|
143
|
+
end
|
|
144
|
+
@phase += @phase_inc
|
|
145
|
+
@phase -= PI2 if @phase > PI2
|
|
146
|
+
if @dec16_coef and @speed == 31
|
|
147
|
+
@dec16_pos = @dec16_sin.size if @dec16_pos == 0
|
|
148
|
+
@dec16_pos -= 1
|
|
149
|
+
@dec16_sin[@dec16_pos] = sample * Math.sin(@phase)
|
|
150
|
+
@dec16_cos[@dec16_pos] = sample * Math.cos(@phase)
|
|
151
|
+
next unless ((@pulse = @pulse + 1 & 0xFF) % 16) == 0
|
|
152
|
+
ival = @dec16_sin.fir(@dec16_coef, @dec16_pos)
|
|
153
|
+
qval = @dec16_cos.fir(@dec16_coef, @dec16_pos)
|
|
154
|
+
elsif @dec8_coef and @speed == 63
|
|
155
|
+
@dec8_pos = @dec8_sin.size if @dec8_pos == 0
|
|
156
|
+
@dec8_pos -= 1
|
|
157
|
+
@dec8_sin[@dec8_pos] = sample * Math.sin(@phase)
|
|
158
|
+
@dec8_cos[@dec8_pos] = sample * Math.cos(@phase)
|
|
159
|
+
next unless ((@pulse = @pulse + 1 & 0xFF) % 8) == 0
|
|
160
|
+
ival = @dec8_sin.fir(@dec8_coef, @dec8_pos)
|
|
161
|
+
qval = @dec8_cos.fir(@dec8_coef, @dec8_pos)
|
|
162
|
+
elsif @dec4_coef
|
|
163
|
+
@dec4a_pos = @dec4a_sin.size if @dec4a_pos == 0
|
|
164
|
+
@dec4a_pos -= 1
|
|
165
|
+
@dec4a_sin[@dec4a_pos] = sample * Math.sin(@phase)
|
|
166
|
+
@dec4a_cos[@dec4a_pos] = sample * Math.cos(@phase)
|
|
167
|
+
next unless ((@pulse = @pulse + 1 & 0xFF) % 4) == 0
|
|
168
|
+
@dec4b_pos = @dec4b_sin.size if @dec4b_pos == 0
|
|
169
|
+
@dec4b_pos -= 1
|
|
170
|
+
ival = @dec4b_sin[@dec4b_pos] = @dec4a_sin.fir(@dec4_coef, @dec4a_pos)
|
|
171
|
+
qval = @dec4b_cos[@dec4b_pos] = @dec4a_cos.fir(@dec4_coef, @dec4a_pos)
|
|
172
|
+
next unless @speed == 125 or (@pulse % mod16_8 == 0)
|
|
173
|
+
unless @speed == 125
|
|
174
|
+
ival = @dec4b_sin.fir(@dec4_coef, @dec4b_pos)
|
|
175
|
+
qval = @dec4b_cos.fir(@dec4_coef, @dec4b_pos)
|
|
176
|
+
end
|
|
177
|
+
else
|
|
178
|
+
raise 'no suitable filter found'
|
|
179
|
+
end
|
|
180
|
+
@bit_pos = @bit_sin.size if @bit_pos == 0
|
|
181
|
+
@bit_pos -= 1
|
|
182
|
+
@bit_sin[@bit_pos] = ival
|
|
183
|
+
@bit_cos[@bit_pos] = qval
|
|
184
|
+
yield @bit_sin.fir(@bit_coef, @bit_pos), @bit_cos.fir(@bit_coef, @bit_pos)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# NArray can easily double filter performance
|
|
189
|
+
begin
|
|
190
|
+
require 'narray'
|
|
191
|
+
class ::NArray
|
|
192
|
+
def fir filter, pos
|
|
193
|
+
(self * filter[size-pos..-1-pos]).sum
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
rescue LoadError => e
|
|
197
|
+
# Pure Ruby fake NArray
|
|
198
|
+
class NArray < Array
|
|
199
|
+
def self.float arg
|
|
200
|
+
new arg, 0.0
|
|
201
|
+
end
|
|
202
|
+
def self.to_na arg
|
|
203
|
+
new(arg).freeze
|
|
204
|
+
end
|
|
205
|
+
def fir filter, pos
|
|
206
|
+
acc = 0.0
|
|
207
|
+
index = size - pos
|
|
208
|
+
each do |val|
|
|
209
|
+
acc += val * filter[index]
|
|
210
|
+
index += 1
|
|
211
|
+
end
|
|
212
|
+
acc
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
class Radio
|
|
2
|
+
class PSK31
|
|
3
|
+
|
|
4
|
+
FIR_DEC6 = [
|
|
5
|
+
-0.001026086585,
|
|
6
|
+
-0.002131424398,
|
|
7
|
+
-0.003473651912,
|
|
8
|
+
-0.005415991401,
|
|
9
|
+
-0.007094896149,
|
|
10
|
+
-0.008685456592,
|
|
11
|
+
-0.009325598368,
|
|
12
|
+
-0.009096149588,
|
|
13
|
+
-0.007453841473,
|
|
14
|
+
-0.004787743788,
|
|
15
|
+
-0.001155271744,
|
|
16
|
+
0.002594565142,
|
|
17
|
+
0.005930466661,
|
|
18
|
+
0.007902971637,
|
|
19
|
+
0.008117998323,
|
|
20
|
+
0.006209532708,
|
|
21
|
+
0.002565394219,
|
|
22
|
+
-0.002211033166,
|
|
23
|
+
-0.006928668876,
|
|
24
|
+
-0.010456837484,
|
|
25
|
+
-0.011638240040,
|
|
26
|
+
-0.009915015895,
|
|
27
|
+
-0.005261804435,
|
|
28
|
+
0.001469200215,
|
|
29
|
+
0.008865519609,
|
|
30
|
+
0.015027698257,
|
|
31
|
+
0.018157576105,
|
|
32
|
+
0.016869453853,
|
|
33
|
+
0.010745489111,
|
|
34
|
+
0.000474997075,
|
|
35
|
+
-0.012015135186,
|
|
36
|
+
-0.023901641616,
|
|
37
|
+
-0.031878023716,
|
|
38
|
+
-0.032876349281,
|
|
39
|
+
-0.024689692215,
|
|
40
|
+
-0.006586586958,
|
|
41
|
+
0.020417464549,
|
|
42
|
+
0.053543134171,
|
|
43
|
+
0.088652482149,
|
|
44
|
+
0.120891532319,
|
|
45
|
+
0.145553464727,
|
|
46
|
+
0.158910442030,
|
|
47
|
+
0.158910442030,
|
|
48
|
+
0.145553464727,
|
|
49
|
+
0.120891532319,
|
|
50
|
+
0.088652482149,
|
|
51
|
+
0.053543134171,
|
|
52
|
+
0.020417464549,
|
|
53
|
+
-0.006586586958,
|
|
54
|
+
-0.024689692215,
|
|
55
|
+
-0.032876349281,
|
|
56
|
+
-0.031878023716,
|
|
57
|
+
-0.023901641616,
|
|
58
|
+
-0.012015135186,
|
|
59
|
+
0.000474997075,
|
|
60
|
+
0.010745489111,
|
|
61
|
+
0.016869453853,
|
|
62
|
+
0.018157576105,
|
|
63
|
+
0.015027698257,
|
|
64
|
+
0.008865519609,
|
|
65
|
+
0.001469200215,
|
|
66
|
+
-0.005261804435,
|
|
67
|
+
-0.009915015895,
|
|
68
|
+
-0.011638240040,
|
|
69
|
+
-0.010456837484,
|
|
70
|
+
-0.006928668876,
|
|
71
|
+
-0.002211033166,
|
|
72
|
+
0.002565394219,
|
|
73
|
+
0.006209532708,
|
|
74
|
+
0.008117998323,
|
|
75
|
+
0.007902971637,
|
|
76
|
+
0.005930466661,
|
|
77
|
+
0.002594565142,
|
|
78
|
+
-0.001155271744,
|
|
79
|
+
-0.004787743788,
|
|
80
|
+
-0.007453841473,
|
|
81
|
+
-0.009096149588,
|
|
82
|
+
-0.009325598368,
|
|
83
|
+
-0.008685456592,
|
|
84
|
+
-0.007094896149,
|
|
85
|
+
-0.005415991401,
|
|
86
|
+
-0.003473651912,
|
|
87
|
+
-0.002131424398,
|
|
88
|
+
-0.001026086585
|
|
89
|
+
].freeze
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# 64-tap raised-cosine
|
|
93
|
+
FIR_DEC16 = [
|
|
94
|
+
0.000000,
|
|
95
|
+
0.000038,
|
|
96
|
+
0.000150,
|
|
97
|
+
0.000336,
|
|
98
|
+
0.000595,
|
|
99
|
+
0.000922,
|
|
100
|
+
0.001317,
|
|
101
|
+
0.001773,
|
|
102
|
+
0.002288,
|
|
103
|
+
0.002856,
|
|
104
|
+
0.003472,
|
|
105
|
+
0.004130,
|
|
106
|
+
0.004823,
|
|
107
|
+
0.005545,
|
|
108
|
+
0.006288,
|
|
109
|
+
0.007047,
|
|
110
|
+
0.007812,
|
|
111
|
+
0.008578,
|
|
112
|
+
0.009337,
|
|
113
|
+
0.010080,
|
|
114
|
+
0.010802,
|
|
115
|
+
0.011495,
|
|
116
|
+
0.012153,
|
|
117
|
+
0.012769,
|
|
118
|
+
0.013337,
|
|
119
|
+
0.013852,
|
|
120
|
+
0.014308,
|
|
121
|
+
0.014703,
|
|
122
|
+
0.015030,
|
|
123
|
+
0.015289,
|
|
124
|
+
0.015475,
|
|
125
|
+
0.015587,
|
|
126
|
+
0.015625,
|
|
127
|
+
0.015587,
|
|
128
|
+
0.015475,
|
|
129
|
+
0.015289,
|
|
130
|
+
0.015030,
|
|
131
|
+
0.014703,
|
|
132
|
+
0.014308,
|
|
133
|
+
0.013852,
|
|
134
|
+
0.013337,
|
|
135
|
+
0.012769,
|
|
136
|
+
0.012153,
|
|
137
|
+
0.011495,
|
|
138
|
+
0.010802,
|
|
139
|
+
0.010080,
|
|
140
|
+
0.009337,
|
|
141
|
+
0.008578,
|
|
142
|
+
0.007813,
|
|
143
|
+
0.007047,
|
|
144
|
+
0.006288,
|
|
145
|
+
0.005545,
|
|
146
|
+
0.004823,
|
|
147
|
+
0.004130,
|
|
148
|
+
0.003472,
|
|
149
|
+
0.002856,
|
|
150
|
+
0.002288,
|
|
151
|
+
0.001773,
|
|
152
|
+
0.001317,
|
|
153
|
+
0.000922,
|
|
154
|
+
0.000595,
|
|
155
|
+
0.000336,
|
|
156
|
+
0.000150,
|
|
157
|
+
0.000038
|
|
158
|
+
].freeze
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# Design method: Parks-McClellan method
|
|
162
|
+
# Number of taps = 35
|
|
163
|
+
# Number of bands = 2
|
|
164
|
+
# Band Lower Upper Value Weight
|
|
165
|
+
# edge edge
|
|
166
|
+
# 1 0.0 .0125 1.0 1
|
|
167
|
+
# 2 .125 .5 .000001 10
|
|
168
|
+
FIR_DEC4 = [
|
|
169
|
+
-0.00021203644,
|
|
170
|
+
-0.00070252426,
|
|
171
|
+
-0.0016680526,
|
|
172
|
+
-0.0031934799,
|
|
173
|
+
-0.0051899752,
|
|
174
|
+
-0.0072862086,
|
|
175
|
+
-0.0087714235,
|
|
176
|
+
-0.0086272102,
|
|
177
|
+
-0.0056735648,
|
|
178
|
+
0.0011784719,
|
|
179
|
+
0.01261353,
|
|
180
|
+
0.028615709,
|
|
181
|
+
0.048280707,
|
|
182
|
+
0.069812051,
|
|
183
|
+
0.090735013,
|
|
184
|
+
0.10830381,
|
|
185
|
+
0.12001897,
|
|
186
|
+
0.12413413,
|
|
187
|
+
0.12001897,
|
|
188
|
+
0.10830381,
|
|
189
|
+
0.090735013,
|
|
190
|
+
0.069812051,
|
|
191
|
+
0.048280707,
|
|
192
|
+
0.028615709,
|
|
193
|
+
0.01261353,
|
|
194
|
+
0.0011784719,
|
|
195
|
+
-0.0056735648,
|
|
196
|
+
-0.0086272102,
|
|
197
|
+
-0.0087714235,
|
|
198
|
+
-0.0072862086,
|
|
199
|
+
-0.0051899752,
|
|
200
|
+
-0.0031934799,
|
|
201
|
+
-0.0016680526,
|
|
202
|
+
-0.00070252426,
|
|
203
|
+
-0.00021203644
|
|
204
|
+
].freeze
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# 16 Hz bw LP filter for data recovery
|
|
208
|
+
# Filter type: Multiband filter
|
|
209
|
+
# Design method: Parks-McClellan method
|
|
210
|
+
# Number of taps = 65
|
|
211
|
+
# Number of bands = 2
|
|
212
|
+
# Band Lower Upper Value Weight
|
|
213
|
+
# edge edge
|
|
214
|
+
#
|
|
215
|
+
# 1 0.0 .03125 1. 1.
|
|
216
|
+
# 2 .0625 .5 .0000 286.
|
|
217
|
+
FIR_BIT = [
|
|
218
|
+
4.3453566e-005,
|
|
219
|
+
-0.00049122414,
|
|
220
|
+
-0.00078771292,
|
|
221
|
+
-0.0013507826,
|
|
222
|
+
-0.0021287814,
|
|
223
|
+
-0.003133466,
|
|
224
|
+
-0.004366817,
|
|
225
|
+
-0.0058112187,
|
|
226
|
+
-0.0074249976,
|
|
227
|
+
-0.0091398882,
|
|
228
|
+
-0.010860157,
|
|
229
|
+
-0.012464086,
|
|
230
|
+
-0.013807772,
|
|
231
|
+
-0.014731191,
|
|
232
|
+
-0.015067057,
|
|
233
|
+
-0.014650894,
|
|
234
|
+
-0.013333425,
|
|
235
|
+
-0.01099166,
|
|
236
|
+
-0.0075431246,
|
|
237
|
+
-0.0029527849,
|
|
238
|
+
0.0027546292,
|
|
239
|
+
0.0094932775,
|
|
240
|
+
0.017113308,
|
|
241
|
+
0.025403511,
|
|
242
|
+
0.034099681,
|
|
243
|
+
0.042895839,
|
|
244
|
+
0.051458575,
|
|
245
|
+
0.059444853,
|
|
246
|
+
0.066521003,
|
|
247
|
+
0.072381617,
|
|
248
|
+
0.076767694,
|
|
249
|
+
0.079481619,
|
|
250
|
+
0.080420311,
|
|
251
|
+
0.079481619,
|
|
252
|
+
0.076767694,
|
|
253
|
+
0.072381617,
|
|
254
|
+
0.066521003,
|
|
255
|
+
0.059444853,
|
|
256
|
+
0.051458575,
|
|
257
|
+
0.042895839,
|
|
258
|
+
0.034099681,
|
|
259
|
+
0.025403511,
|
|
260
|
+
0.017113308,
|
|
261
|
+
0.0094932775,
|
|
262
|
+
0.0027546292,
|
|
263
|
+
-0.0029527849,
|
|
264
|
+
-0.0075431246,
|
|
265
|
+
-0.01099166,
|
|
266
|
+
-0.013333425,
|
|
267
|
+
-0.014650894,
|
|
268
|
+
-0.015067057,
|
|
269
|
+
-0.014731191,
|
|
270
|
+
-0.013807772,
|
|
271
|
+
-0.012464086,
|
|
272
|
+
-0.010860157,
|
|
273
|
+
-0.0091398882,
|
|
274
|
+
-0.0074249976,
|
|
275
|
+
-0.0058112187,
|
|
276
|
+
-0.004366817,
|
|
277
|
+
-0.003133466,
|
|
278
|
+
-0.0021287814,
|
|
279
|
+
-0.0013507826,
|
|
280
|
+
-0.00078771292,
|
|
281
|
+
-0.00049122414,
|
|
282
|
+
4.3453566e-005
|
|
283
|
+
].freeze
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
end
|
|
287
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class Radio
|
|
2
|
+
|
|
3
|
+
class PSK31
|
|
4
|
+
|
|
5
|
+
class Rx
|
|
6
|
+
|
|
7
|
+
def initialize sample_rate, format, frequency
|
|
8
|
+
@filter = Filters.new sample_rate, format, frequency,
|
|
9
|
+
:dec6 => FIR_DEC6,
|
|
10
|
+
:dec16 => FIR_DEC16,
|
|
11
|
+
:dec4 => FIR_DEC4,
|
|
12
|
+
:bit => FIR_BIT
|
|
13
|
+
@bit_detect = BitDetect.new
|
|
14
|
+
@decoder = Decoder.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call sample_data
|
|
18
|
+
decoded = ''
|
|
19
|
+
@filter.call sample_data do |i, q|
|
|
20
|
+
@bit_detect.call i, q do
|
|
21
|
+
@decoder.call i, q do |symbol|
|
|
22
|
+
decoded += symbol
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
decoded
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def frequency= frequency
|
|
30
|
+
if frequency != @filter.frequency
|
|
31
|
+
@filter.frequency = frequency
|
|
32
|
+
@filter.recalc_phase_inc
|
|
33
|
+
reset
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# To compensate for bad clock in A-D conversion
|
|
38
|
+
def adjust_sample_clock ppm
|
|
39
|
+
@filter.clock = 8000.0 * ppm / 1000000 + 8000
|
|
40
|
+
@filter.recalc_phase_inc
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reset
|
|
44
|
+
@filter.reset
|
|
45
|
+
@bit_detect.reset
|
|
46
|
+
@decoder.reset
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
class Radio
|
|
2
|
+
|
|
3
|
+
class PSK31
|
|
4
|
+
|
|
5
|
+
VARICODE_TABLE = [
|
|
6
|
+
0xAAC0, # 0 1010101011
|
|
7
|
+
0xB6C0, # 1 1011011011
|
|
8
|
+
0xBB40, # 2 1011101101
|
|
9
|
+
0xDDC0, # 3 1101110111
|
|
10
|
+
0xBAC0, # 4 1011101011
|
|
11
|
+
0xD7C0, # 5 1101011111
|
|
12
|
+
0xBBC0, # 6 1011101111
|
|
13
|
+
0xBF40, # 7 1011111101
|
|
14
|
+
0xBFC0, # 8 1011111111
|
|
15
|
+
0xEF00, # 9 11101111
|
|
16
|
+
0xE800, # 10 11101
|
|
17
|
+
0xDBC0, # 11 1101101111
|
|
18
|
+
0xB740, # 12 1011011101
|
|
19
|
+
0xF800, # 13 11111
|
|
20
|
+
0xDD40, # 14 1101110101
|
|
21
|
+
0xEAC0, # 15 1110101011
|
|
22
|
+
0xBDC0, # 16 1011110111
|
|
23
|
+
0xBD40, # 17 1011110101
|
|
24
|
+
0xEB40, # 18 1110101101
|
|
25
|
+
0xEBC0, # 19 1110101111
|
|
26
|
+
0xD6C0, # 20 1101011011
|
|
27
|
+
0xDAC0, # 21 1101101011
|
|
28
|
+
0xDB40, # 22 1101101101
|
|
29
|
+
0xD5C0, # 23 1101010111
|
|
30
|
+
0xDEC0, # 24 1101111011
|
|
31
|
+
0xDF40, # 25 1101111101
|
|
32
|
+
0xEDC0, # 26 1110110111
|
|
33
|
+
0xD540, # 27 1101010101
|
|
34
|
+
0xD740, # 28 1101011101
|
|
35
|
+
0xEEC0, # 29 1110111011
|
|
36
|
+
0xBEC0, # 30 1011111011
|
|
37
|
+
0xDFC0, # 31 1101111111
|
|
38
|
+
0x8000, # ' ' 1
|
|
39
|
+
0xFF80, # '!' 111111111
|
|
40
|
+
0xAF80, # '"' 101011111
|
|
41
|
+
0xFA80, # '#' 111110101
|
|
42
|
+
0xED80, # '$' 111011011
|
|
43
|
+
0xB540, # '%' 1011010101
|
|
44
|
+
0xAEC0, # '&' 1010111011
|
|
45
|
+
0xBF80, # ''' 101111111
|
|
46
|
+
0xFB00, # '(' 11111011
|
|
47
|
+
0xF700, # ')' 11110111
|
|
48
|
+
0xB780, # '*' 101101111
|
|
49
|
+
0xEF80, # '+' 111011111
|
|
50
|
+
0xEA00, # ',' 1110101
|
|
51
|
+
0xD400, # '-' 110101
|
|
52
|
+
0xAE00, # '.' 1010111
|
|
53
|
+
0xD780, # '/' 110101111
|
|
54
|
+
0xB700, # '0' 10110111
|
|
55
|
+
0xBD00, # '1' 10111101
|
|
56
|
+
0xED00, # '2' 11101101
|
|
57
|
+
0xFF00, # '3' 11111111
|
|
58
|
+
0xBB80, # '4' 101110111
|
|
59
|
+
0xAD80, # '5' 101011011
|
|
60
|
+
0xB580, # '6' 101101011
|
|
61
|
+
0xD680, # '7' 110101101
|
|
62
|
+
0xD580, # '8' 110101011
|
|
63
|
+
0xDB80, # '9' 110110111
|
|
64
|
+
0xF500, # ':' 11110101
|
|
65
|
+
0xDE80, # ';' 110111101
|
|
66
|
+
0xF680, # '<' 111101101
|
|
67
|
+
0xAA00, # '=' 1010101
|
|
68
|
+
0xEB80, # '>' 111010111
|
|
69
|
+
0xABC0, # '?' 1010101111
|
|
70
|
+
0xAF40, # '@' 1010111101
|
|
71
|
+
0xFA00, # 'A' 1111101
|
|
72
|
+
0xEB00, # 'B' 11101011
|
|
73
|
+
0xAD00, # 'C' 10101101
|
|
74
|
+
0xB500, # 'D' 10110101
|
|
75
|
+
0xEE00, # 'E' 1110111
|
|
76
|
+
0xDB00, # 'F' 11011011
|
|
77
|
+
0xFD00, # 'G' 11111101
|
|
78
|
+
0xAA80, # 'H' 101010101
|
|
79
|
+
0xFE00, # 'I' 1111111
|
|
80
|
+
0xFE80, # 'J' 111111101
|
|
81
|
+
0xBE80, # 'K' 101111101
|
|
82
|
+
0xD700, # 'L' 11010111
|
|
83
|
+
0xBB00, # 'M' 10111011
|
|
84
|
+
0xDD00, # 'N' 11011101
|
|
85
|
+
0xAB00, # 'O' 10101011
|
|
86
|
+
0xD500, # 'P' 11010101
|
|
87
|
+
0xEE80, # 'Q' 111011101
|
|
88
|
+
0xAF00, # 'R' 10101111
|
|
89
|
+
0xDE00, # 'S' 1101111
|
|
90
|
+
0xDA00, # 'T' 1101101
|
|
91
|
+
0xAB80, # 'U' 101010111
|
|
92
|
+
0xDA80, # 'V' 110110101
|
|
93
|
+
0xAE80, # 'W' 101011101
|
|
94
|
+
0xBA80, # 'X' 101110101
|
|
95
|
+
0xBD80, # 'Y' 101111011
|
|
96
|
+
0xAB40, # 'Z' 1010101101
|
|
97
|
+
0xFB80, # '[' 111110111
|
|
98
|
+
0xF780, # '\' 111101111
|
|
99
|
+
0xFD80, # ']' 111111011
|
|
100
|
+
0xAFC0, # '^' 1010111111
|
|
101
|
+
0xB680, # '_' 101101101
|
|
102
|
+
0xB7C0, # '`' 1011011111
|
|
103
|
+
0xB000, # 'a' 1011
|
|
104
|
+
0xBE00, # 'b' 1011111
|
|
105
|
+
0xBC00, # 'c' 101111
|
|
106
|
+
0xB400, # 'd' 101101
|
|
107
|
+
0xC000, # 'e' 11
|
|
108
|
+
0xF400, # 'f' 111101
|
|
109
|
+
0xB600, # 'g' 1011011
|
|
110
|
+
0xAC00, # 'h' 101011
|
|
111
|
+
0xD000, # 'i' 1101
|
|
112
|
+
0xF580, # 'j' 111101011
|
|
113
|
+
0xBF00, # 'k' 10111111
|
|
114
|
+
0xD800, # 'l' 11011
|
|
115
|
+
0xEC00, # 'm' 111011
|
|
116
|
+
0xF000, # 'n' 1111
|
|
117
|
+
0xE000, # 'o' 111
|
|
118
|
+
0xFC00, # 'p' 111111
|
|
119
|
+
0xDF80, # 'q' 110111111
|
|
120
|
+
0xA800, # 'r' 10101
|
|
121
|
+
0xB800, # 's' 10111
|
|
122
|
+
0xA000, # 't' 101
|
|
123
|
+
0xDC00, # 'u' 110111
|
|
124
|
+
0xF600, # 'v' 1111011
|
|
125
|
+
0xD600, # 'w' 1101011
|
|
126
|
+
0xDF00, # 'x' 11011111
|
|
127
|
+
0xBA00, # 'y' 1011101
|
|
128
|
+
0xEA80, # 'z' 111010101
|
|
129
|
+
0xADC0, # '{' 1010110111
|
|
130
|
+
0xDD80, # '|' 110111011
|
|
131
|
+
0xAD40, # '}' 1010110101
|
|
132
|
+
0xB5C0, # '~' 1011010111
|
|
133
|
+
0xED40, # 127 1110110101
|
|
134
|
+
0xEF40, # 128 1110111101
|
|
135
|
+
0xEFC0, # 129 1110111111
|
|
136
|
+
0xF540, # 130 1111010101
|
|
137
|
+
0xF5C0, # 131 1111010111
|
|
138
|
+
0xF6C0, # 132 1111011011
|
|
139
|
+
0xF740, # 133 1111011101
|
|
140
|
+
0xF7C0, # 134 1111011111
|
|
141
|
+
0xFAC0, # 135 1111101011
|
|
142
|
+
0xFB40, # 136 1111101101
|
|
143
|
+
0xFBC0, # 137 1111101111
|
|
144
|
+
0xFD40, # 138 1111110101
|
|
145
|
+
0xFDC0, # 139 1111110111
|
|
146
|
+
0xFEC0, # 140 1111111011
|
|
147
|
+
0xFF40, # 141 1111111101
|
|
148
|
+
0xFFC0, # 142 1111111111
|
|
149
|
+
0xAAA0, # 143 10101010101
|
|
150
|
+
0xAAE0, # 144 10101010111
|
|
151
|
+
0xAB60, # 145 10101011011
|
|
152
|
+
0xABA0, # 146 10101011101
|
|
153
|
+
0xABE0, # 147 10101011111
|
|
154
|
+
0xAD60, # 148 10101101011
|
|
155
|
+
0xADA0, # 149 10101101101
|
|
156
|
+
0xADE0, # 150 10101101111
|
|
157
|
+
0xAEA0, # 151 10101110101
|
|
158
|
+
0xAEE0, # 152 10101110111
|
|
159
|
+
0xAF60, # 153 10101111011
|
|
160
|
+
0xAFA0, # 154 10101111101
|
|
161
|
+
0xAFE0, # 155 10101111111
|
|
162
|
+
0xB560, # 156 10110101011
|
|
163
|
+
0xB5A0, # 157 10110101101
|
|
164
|
+
0xB5E0, # 158 10110101111
|
|
165
|
+
0xB6A0, # 159 10110110101
|
|
166
|
+
0xB6E0, # 160 10110110111
|
|
167
|
+
0xB760, # 161 10110111011
|
|
168
|
+
0xB7A0, # 162 10110111101
|
|
169
|
+
0xB7E0, # 163 10110111111
|
|
170
|
+
0xBAA0, # 164 10111010101
|
|
171
|
+
0xBAE0, # 165 10111010111
|
|
172
|
+
0xBB60, # 166 10111011011
|
|
173
|
+
0xBBA0, # 167 10111011101
|
|
174
|
+
0xBBE0, # 168 10111011111
|
|
175
|
+
0xBD60, # 169 10111101011
|
|
176
|
+
0xBDA0, # 170 10111101101
|
|
177
|
+
0xBDE0, # 171 10111101111
|
|
178
|
+
0xBEA0, # 172 10111110101
|
|
179
|
+
0xBEE0, # 173 10111110111
|
|
180
|
+
0xBF60, # 174 10111111011
|
|
181
|
+
0xBFA0, # 175 10111111101
|
|
182
|
+
0xBFE0, # 176 10111111111
|
|
183
|
+
0xD560, # 177 11010101011
|
|
184
|
+
0xD5A0, # 178 11010101101
|
|
185
|
+
0xD5E0, # 179 11010101111
|
|
186
|
+
0xD6A0, # 180 11010110101
|
|
187
|
+
0xD6E0, # 181 11010110111
|
|
188
|
+
0xD760, # 182 11010111011
|
|
189
|
+
0xD7A0, # 183 11010111101
|
|
190
|
+
0xD7E0, # 184 11010111111
|
|
191
|
+
0xDAA0, # 185 11011010101
|
|
192
|
+
0xDAE0, # 186 11011010111
|
|
193
|
+
0xDB60, # 187 11011011011
|
|
194
|
+
0xDBA0, # 188 11011011101
|
|
195
|
+
0xDBE0, # 189 11011011111
|
|
196
|
+
0xDD60, # 190 11011101011
|
|
197
|
+
0xDDA0, # 191 11011101101
|
|
198
|
+
0xDDE0, # 192 11011101111
|
|
199
|
+
0xDEA0, # 193 11011110101
|
|
200
|
+
0xDEE0, # 194 11011110111
|
|
201
|
+
0xDF60, # 195 11011111011
|
|
202
|
+
0xDFA0, # 196 11011111101
|
|
203
|
+
0xDFE0, # 197 11011111111
|
|
204
|
+
0xEAA0, # 198 11101010101
|
|
205
|
+
0xEAE0, # 199 11101010111
|
|
206
|
+
0xEB60, # 200 11101011011
|
|
207
|
+
0xEBA0, # 201 11101011101
|
|
208
|
+
0xEBE0, # 202 11101011111
|
|
209
|
+
0xED60, # 203 11101101011
|
|
210
|
+
0xEDA0, # 204 11101101101
|
|
211
|
+
0xEDE0, # 205 11101101111
|
|
212
|
+
0xEEA0, # 206 11101110101
|
|
213
|
+
0xEEE0, # 207 11101110111
|
|
214
|
+
0xEF60, # 208 11101111011
|
|
215
|
+
0xEFA0, # 209 11101111101
|
|
216
|
+
0xEFE0, # 210 11101111111
|
|
217
|
+
0xF560, # 211 11110101011
|
|
218
|
+
0xF5A0, # 212 11110101101
|
|
219
|
+
0xF5E0, # 213 11110101111
|
|
220
|
+
0xF6A0, # 214 11110110101
|
|
221
|
+
0xF6E0, # 215 11110110111
|
|
222
|
+
0xF760, # 216 11110111011
|
|
223
|
+
0xF7A0, # 217 11110111101
|
|
224
|
+
0xF7E0, # 218 11110111111
|
|
225
|
+
0xFAA0, # 219 11111010101
|
|
226
|
+
0xFAE0, # 220 11111010111
|
|
227
|
+
0xFB60, # 221 11111011011
|
|
228
|
+
0xFBA0, # 222 11111011101
|
|
229
|
+
0xFBE0, # 223 11111011111
|
|
230
|
+
0xFD60, # 224 11111101011
|
|
231
|
+
0xFDA0, # 225 11111101101
|
|
232
|
+
0xFDE0, # 226 11111101111
|
|
233
|
+
0xFEA0, # 227 11111110101
|
|
234
|
+
0xFEE0, # 228 11111110111
|
|
235
|
+
0xFF60, # 229 11111111011
|
|
236
|
+
0xFFA0, # 230 11111111101
|
|
237
|
+
0xFFE0, # 231 11111111111
|
|
238
|
+
0xAAB0, # 232 101010101011
|
|
239
|
+
0xAAD0, # 233 101010101101
|
|
240
|
+
0xAAF0, # 234 101010101111
|
|
241
|
+
0xAB50, # 235 101010110101
|
|
242
|
+
0xAB70, # 236 101010110111
|
|
243
|
+
0xABB0, # 237 101010111011
|
|
244
|
+
0xABD0, # 238 101010111101
|
|
245
|
+
0xABF0, # 239 101010111111
|
|
246
|
+
0xAD50, # 240 101011010101
|
|
247
|
+
0xAD70, # 241 101011010111
|
|
248
|
+
0xADB0, # 242 101011011011
|
|
249
|
+
0xADD0, # 243 101011011101
|
|
250
|
+
0xADF0, # 244 101011011111
|
|
251
|
+
0xAEB0, # 245 101011101011
|
|
252
|
+
0xAED0, # 246 101011101101
|
|
253
|
+
0xAEF0, # 247 101011101111
|
|
254
|
+
0xAF50, # 248 101011110101
|
|
255
|
+
0xAF70, # 249 101011110111
|
|
256
|
+
0xAFB0, # 250 101011111011
|
|
257
|
+
0xAFD0, # 251 101011111101
|
|
258
|
+
0xAFF0, # 252 101011111111
|
|
259
|
+
0xB550, # 253 101101010101
|
|
260
|
+
0xB570, # 254 101101010111
|
|
261
|
+
0xB5B0 # 255 101101011011
|
|
262
|
+
].freeze
|
|
263
|
+
|
|
264
|
+
VARICODE_DECODE_TABLE = []
|
|
265
|
+
for i in 0...256
|
|
266
|
+
wTemp = VARICODE_TABLE[i]
|
|
267
|
+
wTemp >>= 4
|
|
268
|
+
wTemp >>= 1 until (wTemp&1 == 1)
|
|
269
|
+
wTemp >>= 1
|
|
270
|
+
VARICODE_DECODE_TABLE[wTemp] = i.chr
|
|
271
|
+
end
|
|
272
|
+
VARICODE_DECODE_TABLE.freeze
|
|
273
|
+
|
|
274
|
+
end
|
|
275
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: radio
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- David Turnbull
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2011-11-11 00:00:00.000000000Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description:
|
|
15
|
+
email:
|
|
16
|
+
- dturnbull@gmail.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- lib/radio/psk31/bit_detect.rb
|
|
22
|
+
- lib/radio/psk31/decoder.rb
|
|
23
|
+
- lib/radio/psk31/filters.rb
|
|
24
|
+
- lib/radio/psk31/fir_coef.rb
|
|
25
|
+
- lib/radio/psk31/rx.rb
|
|
26
|
+
- lib/radio/psk31/varicode.rb
|
|
27
|
+
- lib/radio.rb
|
|
28
|
+
- README.md
|
|
29
|
+
homepage: https://github.com/dturnbull/radio
|
|
30
|
+
licenses: []
|
|
31
|
+
post_install_message:
|
|
32
|
+
rdoc_options: []
|
|
33
|
+
require_paths:
|
|
34
|
+
- lib
|
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
36
|
+
none: false
|
|
37
|
+
requirements:
|
|
38
|
+
- - ! '>='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
42
|
+
none: false
|
|
43
|
+
requirements:
|
|
44
|
+
- - ! '>='
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
requirements: []
|
|
48
|
+
rubyforge_project:
|
|
49
|
+
rubygems_version: 1.8.6
|
|
50
|
+
signing_key:
|
|
51
|
+
specification_version: 3
|
|
52
|
+
summary: Amateur radio software
|
|
53
|
+
test_files: []
|
|
54
|
+
has_rdoc:
|