paddlec 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'roctave'
4
+ require '../lib/paddlec'
5
+
6
+ def show_bar(f, t = 80.0)
7
+ p = (f.pos * t / f.size).round
8
+ STDOUT.write "\r[#{'='*p}>#{'-'*(t - p)}] "
9
+ STDOUT.flush
10
+ end
11
+
12
+
13
+ show_filters = false
14
+
15
+ fs = 2.048e6
16
+
17
+ # b = File.binread(File.expand_path '~/sdrrec/pouet.raw').unpack('C*').each_slice(2).collect{|a| Complex((a.first - 128) / 128.0, (a.last - 128) / 128.0)}.to_complex_buffer
18
+ # puts b.length
19
+ # File.binwrite('pouet_cf32le.raw', b.pack)
20
+ # exit
21
+
22
+
23
+ unless File.file? 'coefficients.f32le' then
24
+ STDOUT.write 'Generating filter coeficients... '; STDOUT.flush
25
+ now = Time.now
26
+
27
+ b_bbdecimator = Roctave.fir1(254, 95e3*2/fs)
28
+ Roctave.freqz(b_bbdecimator, :magnitude, nb_points: 2048, fs: fs) if show_filters
29
+
30
+ b_differentiator = Roctave.fir_differentiator(32)
31
+ Roctave.freqz(b_differentiator, :magnitude, nb_points: 2048, fs: fs/8) if show_filters
32
+
33
+ b_adecimator = Roctave.fir_low_pass(512, 15e3*2/256e3)
34
+ Roctave.freqz(b_adecimator, :magnitude, nb_points: 2048, fs: fs/8) if show_filters
35
+
36
+ tau = 50e-6
37
+ ts = 8*8/fs
38
+ b = [1 - Math.exp(-ts/tau)]
39
+ a = [1, -Math.exp(-ts/tau)]
40
+ h, w = Roctave.freqz(b, a, nb_points: 1024)
41
+ h.collect!{|v| v.abs}
42
+ w.collect!{|v| v/w.last}
43
+ n = 2048
44
+ b_deemphasis = Roctave.fir2(n, w, h, :odd_symmetry)
45
+ Roctave.freqz(b_deemphasis, :magnitude, nb_points: 2048, fs: fs/8/8) if show_filters
46
+
47
+ b_bppilote = Roctave.fir_band_pass(256, 2*19e3/(fs/8), 2*1e3/(fs/8))
48
+ Roctave.freqz(b_bppilote, :magnitude, nb_points: 2048, fs: fs/8) if show_filters
49
+
50
+ b_hilbert = Roctave.fir_hilbert(48, window: :blackman)
51
+ Roctave.freqz(b_hilbert, :magnitude, nb_points: 2048, fs: fs/8) if show_filters
52
+
53
+ b_bplmr = Roctave.fir_band_pass(256, 2*38e3/(fs/8), 2*30e3/(fs/8), window: :blackman)
54
+ Roctave.freqz(b_bplmr, :magnitude, nb_points: 2048, fs: fs/8) if show_filters
55
+
56
+ puts (Time.now - now).round(3)
57
+
58
+ File.open('coefficients.f32le', 'wb') do |ofile|
59
+ ofile.write b_bbdecimator.pack('f*')
60
+ ofile.write b_differentiator.pack('f*')
61
+ ofile.write b_adecimator.pack('f*')
62
+ ofile.write b_deemphasis.pack('f*')
63
+ ofile.write b_bppilote.pack('f*')
64
+ ofile.write b_hilbert.pack('f*')
65
+ ofile.write b_bplmr.pack('f*')
66
+ end
67
+ else
68
+ ifile = File.open('coefficients.f32le', 'rb')
69
+ b = ifile.read.unpack('f*')
70
+ ifile.close
71
+ b_bbdecimator = b.shift(255)
72
+ b_differentiator = b.shift(33)
73
+ b_adecimator = b.shift(513)
74
+ b_deemphasis = b.shift(2049)
75
+ b_bppilote = b.shift(257)
76
+ b_hilbert = b.shift(49)
77
+ b_bplmr = b.shift(257)
78
+ end
79
+
80
+
81
+
82
+ bbdecimator = PaddleC::FirDecimator.new b_bbdecimator, 8
83
+ differentiator = PaddleC::FirFilter.new b_differentiator
84
+ adecimator_lpr = PaddleC::FirDecimator.new b_adecimator, 8
85
+ adecimator_lmr = PaddleC::FirDecimator.new b_adecimator, 8
86
+ deemphasis_lpr = PaddleC::FirFilter.new b_deemphasis
87
+ deemphasis_lmr = PaddleC::FirFilter.new b_deemphasis
88
+ bppilote = PaddleC::FirFilter.new b_bppilote
89
+ bplmr = PaddleC::FirFilter.new b_bplmr
90
+ hilbert = PaddleC::FirTransformer.new b_hilbert
91
+ delay_p = PaddleC::Delay.new 152
92
+ delay_h = PaddleC::Delay.new 24
93
+
94
+ time_chunk = 100e-3
95
+ len = (32e3 * time_chunk).round
96
+
97
+ decoding = 0.0
98
+ waiting = 0.0
99
+ fname = '~/sdrrec/102.4MHz_2.048Msps_cu8.raw'
100
+ fname = '~/sdrrec/102.4MHz_2.048Msps_cu8_1.raw'
101
+ fname = '~/sdrrec/102.4MHz_2.048Msps_cu8_2.raw'
102
+ fname = '~/sdrrec/102.4MHz_2.048Msps_cu8_3.raw'
103
+ fname = '~/sdrrec/pouet.raw'
104
+ fname = '~/sdrrec/95.0MHz_2.048Msps_cu8.raw'
105
+ PaddleC::PulseAudio::Simple::Sink.open(stream_name: fname, sample_spec: 'float32 2ch 32000Hz') do |sink|
106
+ File.open(File.expand_path(fname), 'rb') do |f|
107
+ loop do
108
+ show_bar(f)
109
+
110
+ now = Time.now
111
+
112
+ if2MHz_complex = PaddleC::ComplexBuffer.unpack(f.read(8*8*len*2), :u8)
113
+
114
+ baseband256kHz_complex = bbdecimator.decimate(if2MHz_complex)
115
+
116
+ baseband_diff_complex, baseband_delayed_complex = differentiator.filter(baseband256kHz_complex, delayed: true)
117
+
118
+ demodulated = (baseband_diff_complex.imag*baseband_delayed_complex.real - baseband_diff_complex.real*baseband_delayed_complex.imag) / baseband_delayed_complex.abs2
119
+
120
+ pilote19 = bppilote.filter demodulated
121
+ pilote19c = hilbert.transform pilote19
122
+ pilote_phase = pilote19c.phase * 2
123
+ pilote38 = pilote_phase.sin
124
+
125
+ lmrh = bplmr.filter demodulated
126
+ lmrhd = delay_h.delay lmrh
127
+ lmrm = lmrhd * pilote38
128
+ lmremph = adecimator_lmr.decimate(lmrm)
129
+ lmr = deemphasis_lmr.filter(lmremph) * 0.25
130
+
131
+ lpremphdelayed = delay_p.delay demodulated
132
+ lpremph = adecimator_lpr.decimate(lpremphdelayed)
133
+ lpr = deemphasis_lpr.filter(lpremph) * 0.25
134
+
135
+ left = (lpr + lmr) / 2
136
+ right = (lpr - lmr) / 2
137
+
138
+ stereo = PaddleC::ComplexBuffer.new(left, right)
139
+
140
+ decoding += Time.now - now
141
+
142
+ now = Time.now
143
+
144
+ sink << stereo
145
+
146
+ waiting += Time.now - now
147
+
148
+ break if f.eof?
149
+ end
150
+ show_bar(f)
151
+ puts
152
+ end
153
+ end
154
+
155
+
156
+ puts "decoding took #{decoding.round(3)}s"
157
+ puts "waiting took #{waiting.round(3)}s"
158
+
159
+
160
+
161
+
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paddlec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Théotime Bollengier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: roctave
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.1
33
+ description: PaddleC is a Ruby C extension attempting to provide objects and methods
34
+ to rapidly set up real-time signal processing test benches in Ruby.
35
+ email: theotime.bollengier@gmail.com
36
+ executables: []
37
+ extensions:
38
+ - ext/paddlec/extconf.rb
39
+ extra_rdoc_files: []
40
+ files:
41
+ - LICENSE
42
+ - README.md
43
+ - ext/libpaddlec/arithmetic.c
44
+ - ext/libpaddlec/comparison.c
45
+ - ext/libpaddlec/complex.c
46
+ - ext/libpaddlec/delay.c
47
+ - ext/libpaddlec/fir_filter.c
48
+ - ext/libpaddlec/fir_filter_avx.c
49
+ - ext/libpaddlec/fir_filter_neon.c
50
+ - ext/libpaddlec/fir_filter_sse.c
51
+ - ext/libpaddlec/libpaddlec.c
52
+ - ext/libpaddlec/libpaddlec.h
53
+ - ext/libpaddlec/math.c
54
+ - ext/libpaddlec/no_fast_math.c
55
+ - ext/libpaddlec/rounding.c
56
+ - ext/paddlec/complex_buffer.c
57
+ - ext/paddlec/complex_buffer.h
58
+ - ext/paddlec/delay.c
59
+ - ext/paddlec/delay.h
60
+ - ext/paddlec/extconf.rb
61
+ - ext/paddlec/fir_filter.c
62
+ - ext/paddlec/fir_filter.h
63
+ - ext/paddlec/float_buffer.c
64
+ - ext/paddlec/float_buffer.h
65
+ - ext/paddlec/paddlec.c
66
+ - ext/paddlec/paddlec.h
67
+ - ext/paddlec/pulseaudio.c
68
+ - ext/paddlec/pulseaudio.h
69
+ - lib/paddlec.rb
70
+ - lib/paddlec/version.rb
71
+ - paddlec.gemspec
72
+ - samples/fmdemod.rb
73
+ - samples/fmdemod_chunk.rb
74
+ - samples/fmdemod_chunk_buffer.rb
75
+ - samples/stereo_chunk.rb
76
+ homepage: https://gitlab.com/theotime_bollengier/paddlec
77
+ licenses:
78
+ - GPL-3.0+
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.0.6
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: A Ruby C extension for real-time signal processing.
99
+ test_files: []