radio 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +202 -0
- data/README.md +67 -1
- data/bin/radio-server +8 -0
- data/lib/radio.rb +41 -1
- data/lib/radio/controls/null.rb +32 -0
- data/lib/radio/controls/si570avr.rb +77 -0
- data/lib/radio/filter.rb +69 -0
- data/lib/radio/filters/fir.rb +65 -0
- data/lib/radio/gif.rb +84 -0
- data/lib/radio/http/file.rb +88 -0
- data/lib/radio/http/script.rb +133 -0
- data/lib/radio/http/server.rb +94 -0
- data/lib/radio/http/session.rb +43 -0
- data/lib/radio/input.rb +62 -0
- data/lib/radio/inputs/alsa.rb +135 -0
- data/lib/radio/inputs/coreaudio.rb +102 -0
- data/lib/radio/inputs/file.rb +60 -0
- data/lib/radio/inputs/wav.rb +124 -0
- data/lib/radio/psk31/bit_detect.rb +19 -4
- data/lib/radio/psk31/decoder.rb +18 -3
- data/lib/radio/psk31/fir_coef.rb +6 -1
- data/lib/radio/psk31/rx.rb +27 -32
- data/lib/radio/psk31/varicode.rb +15 -0
- data/lib/radio/rig.rb +46 -0
- data/lib/radio/rig/lo.rb +57 -0
- data/lib/radio/rig/rx.rb +61 -0
- data/lib/radio/rig/spectrum.rb +96 -0
- data/lib/radio/version.rb +3 -0
- data/test/test.rb +76 -0
- data/test/wav/bpsk8k.wav +0 -0
- data/test/wav/qpsk8k.wav +0 -0
- data/test/wav/ssb.wav +0 -0
- data/www/index.erb +40 -0
- data/www/jquery-1.7.js +9300 -0
- data/www/lo.erb +21 -0
- data/www/setup/input.erb +64 -0
- data/www/setup/lo.erb +36 -0
- data/www/waterfall.erb +20 -0
- metadata +77 -9
- data/lib/radio/psk31/filters.rb +0 -220
data/www/lo.erb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
<% if xhr?
|
2
|
+
$rig.lo = params['freq'].to_f
|
3
|
+
@response.body = [$rig.lo.to_s]
|
4
|
+
@response.headers['Content-Type'] = 'text/plain'
|
5
|
+
end -%>
|
6
|
+
<form action="lo" id="freqForm">
|
7
|
+
<input type="text" name="freq" value="<%= $rig.lo %>" %>
|
8
|
+
</form>
|
9
|
+
<script type="text/javascript">
|
10
|
+
$("#freqForm").submit(function(event) {
|
11
|
+
event.preventDefault();
|
12
|
+
var $form = $( this ),
|
13
|
+
term = $form.find( 'input[name="freq"]' ).val(),
|
14
|
+
url = $form.attr( 'action' );
|
15
|
+
$.post( url, { freq: term },
|
16
|
+
function( data ) {
|
17
|
+
$form.find( 'input[name="freq"]' ).val(data)
|
18
|
+
}
|
19
|
+
);
|
20
|
+
});
|
21
|
+
</script>
|
data/www/setup/input.erb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
<%
|
2
|
+
if post?
|
3
|
+
$rig ||= Radio::Rig.new
|
4
|
+
channel_i, channel_q = case params['channel']
|
5
|
+
when 'iq' then [0,1]
|
6
|
+
when 'qi' then [1,0]
|
7
|
+
else [0,nil]
|
8
|
+
end
|
9
|
+
$rig.rx = Radio::Input.new params['type'], params['id'], params['rate'].to_i, channel_i, channel_q
|
10
|
+
response.redirect '/'
|
11
|
+
end
|
12
|
+
unless response.redirection? -%>
|
13
|
+
<!DOCTYPE html>
|
14
|
+
<html>
|
15
|
+
<head>
|
16
|
+
<style type="text/css" media="screen">
|
17
|
+
body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}
|
18
|
+
select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}
|
19
|
+
</style>
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
|
23
|
+
<h2>Input Sources</h2>
|
24
|
+
<% if (input_sources = Radio::Input.sources).empty? -%>
|
25
|
+
No input sources found.
|
26
|
+
<% else -%>
|
27
|
+
<dl>
|
28
|
+
<% input_sources.each do |k, opts| -%>
|
29
|
+
<form action='?' method="post">
|
30
|
+
<% input_type, input_id = k -%>
|
31
|
+
<dt>
|
32
|
+
<input type="submit" value="Select"%>
|
33
|
+
<input type="hidden" name="type" value="<%=h input_type %>" %>
|
34
|
+
<input type="hidden" name="id" value="<%=h input_id %>" %>
|
35
|
+
<%=h input_type %>: <%=h opts[:name] %>
|
36
|
+
</dt>
|
37
|
+
<dd>
|
38
|
+
<% opts[:rates].reverse.each_with_index do |rate, index| %>
|
39
|
+
<input type="radio" name="rate" value="<%=h rate %>" <%= "checked=checked" if index==0 %> /><%=h rate %>
|
40
|
+
<% end -%>
|
41
|
+
</dd>
|
42
|
+
<dd>
|
43
|
+
<% if opts[:channels] == 1 or input_type != :File %>
|
44
|
+
<input type="radio" name="channel" value="i" checked="checked" />LPCM
|
45
|
+
<% end -%>
|
46
|
+
<% if opts[:channels] == 2 %>
|
47
|
+
<input type="radio" name="channel" value="iq" />I/Q
|
48
|
+
<input type="radio" name="channel" value="qi" checked="checked" />Q/I
|
49
|
+
<% end -%>
|
50
|
+
</dd>
|
51
|
+
</form>
|
52
|
+
<br />
|
53
|
+
<% end -%>
|
54
|
+
</dl>
|
55
|
+
<% end -%>
|
56
|
+
|
57
|
+
<h2>Driver Status</h2>
|
58
|
+
<% Radio::Input.status.each do |k, v| -%>
|
59
|
+
<%=h k %>: <%=h v %> <br />
|
60
|
+
<% end -%>
|
61
|
+
|
62
|
+
</body>
|
63
|
+
</html>
|
64
|
+
<% end -%>
|
data/www/setup/lo.erb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
<%
|
2
|
+
if post?
|
3
|
+
$rig.lo = case params['type']
|
4
|
+
when 'softrock' then Radio::Controls::Si570AVR.new
|
5
|
+
else Radio::Controls::Null.new
|
6
|
+
end
|
7
|
+
response.redirect '/'
|
8
|
+
end
|
9
|
+
unless response.redirection? -%>
|
10
|
+
<!DOCTYPE html>
|
11
|
+
<html>
|
12
|
+
<head>
|
13
|
+
<style type="text/css" media="screen">
|
14
|
+
body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}
|
15
|
+
select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
<body>
|
19
|
+
|
20
|
+
<h2>Local Oscillator Control</h2>
|
21
|
+
<form action='?' method="post">
|
22
|
+
<input type="submit" value="Select"%>
|
23
|
+
<input type="hidden" name="type" value="null" %>
|
24
|
+
No control.
|
25
|
+
</form>
|
26
|
+
<br />
|
27
|
+
<form action='?' method="post">
|
28
|
+
<input type="submit" value="Select"%>
|
29
|
+
<input type="hidden" name="type" value="softrock" %>
|
30
|
+
SoftRock Si570 (DG8SAQ/PE0FKO)
|
31
|
+
</form>
|
32
|
+
<br />
|
33
|
+
|
34
|
+
</body>
|
35
|
+
</html>
|
36
|
+
<% end -%>
|
data/www/waterfall.erb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
<%
|
2
|
+
$waterfall_gradient ||= (0..127).collect do |i|
|
3
|
+
r = g = b = Math.log((i+16)**6.35)*18-312
|
4
|
+
redshift = i - 64
|
5
|
+
if redshift > 0
|
6
|
+
b = g -= redshift * 3
|
7
|
+
end
|
8
|
+
b *= 0.95
|
9
|
+
[r,g,b]
|
10
|
+
end
|
11
|
+
spectrum = case
|
12
|
+
when $rig.rate <= 24000 then $rig.spectrum 1024, 1.0
|
13
|
+
when $rig.rate <= 48000 then $rig.spectrum 2048, 2.0
|
14
|
+
when $rig.rate <= 96000 then $rig.spectrum 2048, 4.0
|
15
|
+
else $rig.spectrum 2048, 8.0
|
16
|
+
end
|
17
|
+
@response.body = [Radio::Gif.waterfall($waterfall_gradient, [spectrum])]
|
18
|
+
@response.headers['Content-Type'] = 'image/gif'
|
19
|
+
@response.headers["Cache-Control"] = 'max-age=0, private, must-revalidate'
|
20
|
+
%>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: radio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,88 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
12
|
+
date: 2012-02-14 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fftw3
|
16
|
+
requirement: &2198866920 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2198866920
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: thin
|
27
|
+
requirement: &2198866220 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2198866220
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: libusb
|
38
|
+
requirement: &2198865360 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2198865360
|
14
47
|
description:
|
15
48
|
email:
|
16
49
|
- dturnbull@gmail.com
|
17
|
-
executables:
|
50
|
+
executables:
|
51
|
+
- radio-server
|
18
52
|
extensions: []
|
19
53
|
extra_rdoc_files: []
|
20
54
|
files:
|
55
|
+
- bin/radio-server
|
56
|
+
- lib/radio/controls/null.rb
|
57
|
+
- lib/radio/controls/si570avr.rb
|
58
|
+
- lib/radio/filter.rb
|
59
|
+
- lib/radio/filters/fir.rb
|
60
|
+
- lib/radio/gif.rb
|
61
|
+
- lib/radio/http/file.rb
|
62
|
+
- lib/radio/http/script.rb
|
63
|
+
- lib/radio/http/server.rb
|
64
|
+
- lib/radio/http/session.rb
|
65
|
+
- lib/radio/input.rb
|
66
|
+
- lib/radio/inputs/alsa.rb
|
67
|
+
- lib/radio/inputs/coreaudio.rb
|
68
|
+
- lib/radio/inputs/file.rb
|
69
|
+
- lib/radio/inputs/wav.rb
|
21
70
|
- lib/radio/psk31/bit_detect.rb
|
22
71
|
- lib/radio/psk31/decoder.rb
|
23
|
-
- lib/radio/psk31/filters.rb
|
24
72
|
- lib/radio/psk31/fir_coef.rb
|
25
73
|
- lib/radio/psk31/rx.rb
|
26
74
|
- lib/radio/psk31/varicode.rb
|
75
|
+
- lib/radio/rig/lo.rb
|
76
|
+
- lib/radio/rig/rx.rb
|
77
|
+
- lib/radio/rig/spectrum.rb
|
78
|
+
- lib/radio/rig.rb
|
79
|
+
- lib/radio/version.rb
|
27
80
|
- lib/radio.rb
|
81
|
+
- www/index.erb
|
82
|
+
- www/jquery-1.7.js
|
83
|
+
- www/lo.erb
|
84
|
+
- www/setup/input.erb
|
85
|
+
- www/setup/lo.erb
|
86
|
+
- www/waterfall.erb
|
28
87
|
- README.md
|
29
|
-
|
88
|
+
- LICENSE
|
89
|
+
- test/test.rb
|
90
|
+
- test/wav/bpsk8k.wav
|
91
|
+
- test/wav/qpsk8k.wav
|
92
|
+
- test/wav/ssb.wav
|
93
|
+
homepage: https://github.com/ham21/radio
|
30
94
|
licenses: []
|
31
95
|
post_install_message:
|
32
96
|
rdoc_options: []
|
@@ -46,9 +110,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
110
|
version: '0'
|
47
111
|
requirements: []
|
48
112
|
rubyforge_project:
|
49
|
-
rubygems_version: 1.8.
|
113
|
+
rubygems_version: 1.8.10
|
50
114
|
signing_key:
|
51
115
|
specification_version: 3
|
52
|
-
summary: Amateur
|
53
|
-
test_files:
|
116
|
+
summary: The Twenty-First Century Amateur Radio Project
|
117
|
+
test_files:
|
118
|
+
- test/test.rb
|
119
|
+
- test/wav/bpsk8k.wav
|
120
|
+
- test/wav/qpsk8k.wav
|
121
|
+
- test/wav/ssb.wav
|
54
122
|
has_rdoc:
|
data/lib/radio/psk31/filters.rb
DELETED
@@ -1,220 +0,0 @@
|
|
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
|
-
|