paddlec 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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +56 -0
- data/ext/libpaddlec/arithmetic.c +2486 -0
- data/ext/libpaddlec/comparison.c +683 -0
- data/ext/libpaddlec/complex.c +349 -0
- data/ext/libpaddlec/delay.c +240 -0
- data/ext/libpaddlec/fir_filter.c +724 -0
- data/ext/libpaddlec/fir_filter_avx.c +2645 -0
- data/ext/libpaddlec/fir_filter_neon.c +1767 -0
- data/ext/libpaddlec/fir_filter_sse.c +1677 -0
- data/ext/libpaddlec/libpaddlec.c +933 -0
- data/ext/libpaddlec/libpaddlec.h +473 -0
- data/ext/libpaddlec/math.c +563 -0
- data/ext/libpaddlec/no_fast_math.c +955 -0
- data/ext/libpaddlec/rounding.c +503 -0
- data/ext/paddlec/complex_buffer.c +3555 -0
- data/ext/paddlec/complex_buffer.h +28 -0
- data/ext/paddlec/delay.c +214 -0
- data/ext/paddlec/delay.h +29 -0
- data/ext/paddlec/extconf.rb +106 -0
- data/ext/paddlec/fir_filter.c +892 -0
- data/ext/paddlec/fir_filter.h +28 -0
- data/ext/paddlec/float_buffer.c +4770 -0
- data/ext/paddlec/float_buffer.h +28 -0
- data/ext/paddlec/paddlec.c +788 -0
- data/ext/paddlec/paddlec.h +76 -0
- data/ext/paddlec/pulseaudio.c +6767 -0
- data/ext/paddlec/pulseaudio.h +30 -0
- data/lib/paddlec.rb +26 -0
- data/lib/paddlec/version.rb +3 -0
- data/paddlec.gemspec +55 -0
- data/samples/fmdemod.rb +121 -0
- data/samples/fmdemod_chunk.rb +120 -0
- data/samples/fmdemod_chunk_buffer.rb +144 -0
- data/samples/stereo_chunk.rb +161 -0
- metadata +99 -0
| @@ -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: []
         |