Module: PWN::FFI::FFTW
- Extended by:
- Library
- Defined in:
- lib/pwn/ffi/fftw.rb
Overview
Thin single-precision FFTW3 binding (libfftw3f).
Used by PWN::SDR::* spectrum work (GQRX FFT snapshots, wideband energy
detectors) when MHz-rate FFTs outgrow pure-Ruby DFT. Missing library
degrades cleanly via .available? — callers keep pure-Ruby fallbacks.
No compile step at gem install; no shells. Plans are built with FFTW_ESTIMATE so first-call latency stays acceptable for REPL use.
Constant Summary collapse
- FFTW_ESTIMATE =
(1 << 6)
- FFTW_MEASURE =
0- FFTW_FORWARD =
-1
- FFTW_BACKWARD =
1
Class Attribute Summary collapse
-
.load_error ⇒ Object
readonly
Returns the value of attribute load_error.
Class Method Summary collapse
-
.authors ⇒ Object
- Author(s)
0day Inc.
-
.available? ⇒ Boolean
- Supported Method Parameters
PWN::FFI::FFTW.available?.
-
.cfft(opts = {}) ⇒ Object
- Supported Method Parameters
spectrum = PWN::FFI::FFTW.cfft( iq: 'required - interleaved Array
I/Q (even length)', n: 'optional - number of complex samples (default iq.length/2)', sign: 'optional - :forward (default) or :backward' ) Returns Array of [re, im] pairs length n.
-
.help ⇒ Object
Display Usage for this Module.
-
.rfft(opts = {}) ⇒ Object
- Supported Method Parameters
spectrum = PWN::FFI::FFTW.rfft( samples: 'required - Array
real input (length = n)', n: 'optional - FFT size (default samples.length; zero-pads/truncates)' ) Returns Array of [re, im] pairs, length n/2+1 (DC .. Nyquist).
-
.rfft_magnitude(opts = {}) ⇒ Object
- Supported Method Parameters
mag = PWN::FFI::FFTW.rfft_magnitude( samples: 'required - Array
', n: 'optional - FFT size' ) Returns Array of |X| for k=0..n/2.
-
.rfft_power_db(opts = {}) ⇒ Object
- Supported Method Parameters
power_db = PWN::FFI::FFTW.rfft_power_db( samples: 'required - Array
', n: 'optional - FFT size', floor: 'optional - dB floor for zeros (default -120.0)' ) Returns Array of 20*log10(|X|) with a noise floor.
Class Attribute Details
.load_error ⇒ Object (readonly)
Returns the value of attribute load_error.
33 34 35 |
# File 'lib/pwn/ffi/fftw.rb', line 33 def load_error @load_error end |
Class Method Details
.authors ⇒ Object
- Author(s)
0day Inc. support@0dayinc.com
173 174 175 |
# File 'lib/pwn/ffi/fftw.rb', line 173 public_class_method def self. "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n" end |
.available? ⇒ Boolean
- Supported Method Parameters
PWN::FFI::FFTW.available?
63 64 65 66 67 |
# File 'lib/pwn/ffi/fftw.rb', line 63 public_class_method def self.available? !@load_error && respond_to?(:fftwf_malloc, true) rescue StandardError false end |
.cfft(opts = {}) ⇒ Object
- Supported Method Parameters
spectrum = PWN::FFI::FFTW.cfft(
iq: 'required - interleaved Array
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/pwn/ffi/fftw.rb', line 141 public_class_method def self.cfft(opts = {}) raise 'ERROR: libfftw3f not available' unless available? iq = opts[:iq] n = (opts[:n] || (iq.length / 2)).to_i raise 'ERROR: n must be >= 1' if n < 1 sign = opts[:sign] == :backward ? FFTW_BACKWARD : FFTW_FORWARD bytes = n * 2 * 4 in_ptr = fftwf_malloc(bytes) out_ptr = fftwf_malloc(bytes) raise 'ERROR: fftwf_malloc failed' if in_ptr.null? || out_ptr.null? src = iq.first([2 * n, iq.length].min).map(&:to_f) padded = src + Array.new((2 * n) - src.length, 0.0) in_ptr.write_array_of_float(padded) plan = fftwf_plan_dft_1d(n, in_ptr, out_ptr, sign, FFTW_ESTIMATE) raise 'ERROR: fftwf_plan_dft_1d failed' if plan.null? fftwf_execute(plan) flat = out_ptr.read_array_of_float(n * 2) result = Array.new(n) { |i| [flat[2 * i], flat[(2 * i) + 1]] } fftwf_destroy_plan(plan) fftwf_free(in_ptr) fftwf_free(out_ptr) result end |
.help ⇒ Object
Display Usage for this Module
179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/pwn/ffi/fftw.rb', line 179 public_class_method def self.help puts "USAGE: #{self}.available? # => true/false #{self}.rfft(samples:, n: nil) # real→complex, [[re,im],…] #{self}.rfft_magnitude(samples:, n: nil) # |X[k]| #{self}.rfft_power_db(samples:, n:, floor: -120.0) #{self}.cfft(iq:, n: nil, sign: :forward) # complex FFT #{self}.authors " end |
.rfft(opts = {}) ⇒ Object
- Supported Method Parameters
spectrum = PWN::FFI::FFTW.rfft(
samples: 'required - Array
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/pwn/ffi/fftw.rb', line 76 public_class_method def self.rfft(opts = {}) raise 'ERROR: libfftw3f not available' unless available? samples = opts[:samples] n = (opts[:n] || samples.length).to_i raise 'ERROR: n must be >= 1' if n < 1 in_ptr = fftwf_malloc(n * 4) out_bins = (n / 2) + 1 out_ptr = fftwf_malloc(out_bins * 2 * 4) raise 'ERROR: fftwf_malloc failed' if in_ptr.null? || out_ptr.null? # zero + copy in_ptr.write_array_of_float(Array.new(n, 0.0)) src = samples.first([n, samples.length].min).map(&:to_f) in_ptr.write_array_of_float(src + Array.new(n - src.length, 0.0)) if src.length < n in_ptr.write_array_of_float(src) if src.length == n plan = fftwf_plan_dft_r2c_1d(n, in_ptr, out_ptr, FFTW_ESTIMATE) raise 'ERROR: fftwf_plan_dft_r2c_1d failed' if plan.null? fftwf_execute(plan) flat = out_ptr.read_array_of_float(out_bins * 2) result = Array.new(out_bins) { |i| [flat[2 * i], flat[(2 * i) + 1]] } fftwf_destroy_plan(plan) fftwf_free(in_ptr) fftwf_free(out_ptr) result end |
.rfft_magnitude(opts = {}) ⇒ Object
- Supported Method Parameters
mag = PWN::FFI::FFTW.rfft_magnitude(
samples: 'required - Array
114 115 116 |
# File 'lib/pwn/ffi/fftw.rb', line 114 public_class_method def self.rfft_magnitude(opts = {}) rfft(opts).map { |re, im| Math.sqrt((re * re) + (im * im)) } end |
.rfft_power_db(opts = {}) ⇒ Object
- Supported Method Parameters
power_db = PWN::FFI::FFTW.rfft_power_db(
samples: 'required - Array
126 127 128 129 130 131 |
# File 'lib/pwn/ffi/fftw.rb', line 126 public_class_method def self.rfft_power_db(opts = {}) floor = (opts[:floor] || -120.0).to_f rfft_magnitude(opts).map do |m| m.positive? ? (20.0 * Math.log10(m)) : floor end end |