Module: PWN::SDR::Decoder::APT
- Defined in:
- lib/pwn/sdr/decoder/apt.rb
Overview
Pure-Ruby NOAA APT (Automatic Picture Transmission) decoder for the 137 MHz polar-orbiting weather satellites (NOAA-15/18/19).
APT is a 2400 Hz AM subcarrier inside a ~34 kHz-wide FM downlink
carrying two 909-pixel image channels at 2 lines/second (2080
words/line). This module envelope-demodulates the 2400 Hz carrier
from audio, resamples to 4160 words/sec with continuous phase, and
aligns the initial line on a Sync-A correlation candidate. Fixed-rate
rows update a bounded rolling P5 PGM; there is no drift tracking or
satellite identification. Line contrast is normalized independently.
No sox, no noaa-apt.
Defined Under Namespace
Classes: Demod
Constant Summary collapse
- WORDS_PER_LINE =
2080- LINES_PER_SEC =
2- WORD_RATE =
4160 Hz
WORDS_PER_LINE * LINES_PER_SEC
- SYNC_A =
Sync-A: 7 cycles of 1040 Hz square = 1 1 0 0 repeated 7 times
(Array.new(4, 0) + ([1, 1, 0, 0] * 7) + Array.new(7, 0)).freeze
Class Method Summary collapse
-
.authors ⇒ Object
- Author(s)
0day Inc.
- .decode(opts = {}) ⇒ Object
-
.detect(opts = {}) ⇒ Object
Energy detection only; does not identify or decode APT payloads.
-
.help ⇒ Object
Display Usage for this Module.
Class Method Details
.authors ⇒ Object
- Author(s)
0day Inc. [email protected]
173 174 175 |
# File 'lib/pwn/sdr/decoder/apt.rb', line 173 public_class_method def self. "AUTHOR(S):\n 0day Inc. <[email protected]>\n" end |
.decode(opts = {}) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/pwn/sdr/decoder/apt.rb', line 149 public_class_method def self.decode(opts = {}) freq_obj = opts[:freq_obj] raise 'ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash) want_iq = opts[:source] || opts[:file] || freq_obj[:iq_source] || freq_obj[:iq_file] rate = if want_iq opts[:sample_rate] || freq_obj[:iq_rate] || 48_000 else opts[:rate] || 48_000 end demod = Demod.new(rate: rate, out_path: opts[:out_path], max_lines: opts.fetch(:max_lines, 1024)) common = opts.merge(freq_obj: freq_obj, protocol: 'NOAA-APT', demod: demod) if want_iq PWN::SDR::Decoder::Base.run_iq(common.merge( sample_rate: rate.to_i, fm_demod: true, fallback: :raise, note: 'NOAA APT: FM-demod I/Q then 2400 Hz AM envelope → rolling PGM.' )) else PWN::SDR::Decoder::Base.run_native(common.merge(rate: rate.to_i)) end end |
.detect(opts = {}) ⇒ Object
Energy detection only; does not identify or decode APT payloads.
- Supported Method Parameters
APT.detect(freq_obj: Hash, threshold: 8.0, on_frame: Proc)
141 142 143 144 145 146 147 |
# File 'lib/pwn/sdr/decoder/apt.rb', line 141 public_class_method def self.detect(opts = {}) Base.run_detector(opts.merge( protocol: 'APT', note: 'Energy detection only; no protocol payload decoding.', describe: proc { |_burst| { event: 'detection', capability: 'energy-detection', decoded: false } } )) end |
.help ⇒ Object
Display Usage for this Module
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/pwn/sdr/decoder/apt.rb', line 179 public_class_method def self.help puts "USAGE: # Detect energy only (not protocol payloads); accepts Base runner controls. #{self}.detect(freq_obj: {}, threshold: 8.0, on_frame: nil) # Run decode and return its result #{self}.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq', source: 'optional - source value consumed by #decode', file: 'optional - filesystem path', out_path: 'optional - out path value consumed by #decode', sample_rate: 'optional - I/Q audio rate Hz (default 48000 or freq_obj[:iq_rate])', rate: 'optional - native audio rate Hz (default 48000)', max_lines: 'optional - rolling image height limit (default 1024)', on_frame: 'optional - callback receiving each line Hash after atomic PGM update', output: 'optional - IO for immediate JSONL events (default stdout)', interactive: 'optional - stop on ENTER (default true)', duration: 'optional - maximum stream seconds', stop: 'optional - callable cancellation predicate', queue_size: 'optional - bounded Base input queue size', log_file: 'optional - JSONL log path or false to disable' ) # Print the AUTHOR(S) string for this module. #{self}.authors " constants.sort end |