Skip to content

Commit

Permalink
add server-side demode/demode
Browse files Browse the repository at this point in the history
  • Loading branch information
baskiton committed Jul 28, 2024
1 parent 8cce563 commit 1ba014f
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 64 deletions.
80 changes: 42 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,44 +170,46 @@ Each satellite object contain:
#### frequencies
Each frequency object contain:

| Field | Type | Description |
|:--------------------|:----------------|:-------------------------------------------------------------------------------------------------------------------------|
| freq | Number | Basic signal frequency, Hz |
| bandwidth | Number | Received signal bandwidth, Hz |
| demode_out_sr | Number | _Optional._ Demodulator out samplerate. Equal to `bandwidth` by default |
| enabled | Boolean | _Optional._ Enable/Disable this frequency. `true` by default |
| subname | String | _Optional._ Subname added to result filename. Empty by default |
| freq_correction | Boolean | _Optional._ Correction for basic frequency, Hz. `0` by default |
| mode | String | _Optional._ Modulation option (see [modulations](#modulations)). `RAW` by default |
| decode | String | _Optional._ Decoder option (see [decoders](#decoders)). `RAW` by default |
| iq_waterfall | Object | _Optional._ Write also IQ waterfall for bandwidth. `none` by default. See below for object info |
| iq_dump | Boolean | _Optional._ Dump and send IQ file for current bandwidth. `false` by default |
| channels | Array of Number | _Required only for **FSK**, **GFSK**, **GMSK** mode._ Demodulation baudrates, bps. `[1200, 2400, 4800, 9600]` by default |
| deviation_factor | Number | _Required only for **FSK**, **GFSK**, **GMSK** mode._ Deviation frequency factor (baudrate / factor), `5` by default |
| grs_file | String | _Optional. Only for **SATS** decoder._ See [gr-satellites](#gr-satellites) for details |
| grs_name | String | _Optional. Only for **SATS** decoder._ See [gr-satellites](#gr-satellites) for details |
| grs_norad | Integer | _Optional. Only for **SATS** decoder._ See [gr-satellites](#gr-satellites) for details |
| grs_tlm_decode | Boolean | _Optional. Only for **SATS** decoder._ Save decoded telemetry. `true` by default |
| qpsk_baudrate | Number | _Required only for **(O)QPSK** mode._ (O)QPSK Baudrate, bps |
| qpsk_excess_bw | Number | _Optional. Only for **(O)QPSK** mode._ (O)QPSK Excess bandwidth. `0.35` by default |
| qpsk_ntaps | Integer | _Optional. Only for **(O)QPSK** mode._ (O)QPSK number of taps. `33` by default |
| qpsk_costas_bw | Number | _Optional. Only for **(O)QPSK** mode._ (O)QPSK Costas bandwidth. `0.005` by default |
| sstv_wsr | Number | _Optional. Only for **SSTV** decoder._ SSTV work samplerate. `16000` by default |
| sstv_sync | Number | _Optional. Only for **SSTV** decoder._ SSTV syncing. `true` by default |
| sstv_live_exec | Number | _Optional. Only for **SSTV** decoder._ SSTV live executing. `false` by default |
| ccc_frame_size | Number | _Optional. Only for **CCSDSCC** decoder._ Frame size, bytes. `892` by default |
| ccc_pre_deint | Boolean | _Optional. Only for **CCSDSCC** decoder._ Pre-Deinterleaving. `false` by default |
| ccc_diff | Boolean | _Optional. Only for **CCSDSCC** decoder._ Differential Decoding. `true` by default |
| ccc_rs_dualbasis | Boolean | _Optional. Only for **CCSDSCC** decoder._ Reed-Solomon Dualbasis. `false` by default |
| ccc_rs_interleaving | Number | _Optional. Only for **CCSDSCC** decoder._ Reed-Solomon Interleaving. `4` by default |
| ccc_derandomize | Boolean | _Optional. Only for **CCSDSCC** decoder._ Descrambling. `true` by default |
| quad_gain | Number | _Optional. Only for **QUAD**, **SSTV_QUAD** modes._ Quadrature demodulation gain. `1.0` by default |
| raw_out_format | String | _Optional. Only for **RAW** decoder._ WAV output format. `WAV` by default |
| raw_out_subformat | String | _Optional. Only for **RAW** decoder._ WAV output subformat. `FLOAT` by default |
| proto_deframer | String | _Optional. Only for **PROTO** decoder._ Name of the gr-satellites deframer. See [proto](#proto) for detail. |
| proto_options | String | _Optional. Only for **PROTO** decoder._ Deframer options. See [proto](#proto) for detail. |
| ssb_bandwidth | Number | _Optional. Only for **SSB**-family mode._ SSB Bandwidth, Hz. `4600` for DSB nd `2800` foa another by default |
| ssb_out_sr | Number | _Optional. Only for **SSB**-family mode._ SSB out sample rate, Hz. `8000` by default |
| Field | Type | Description |
|:--------------------|:----------------|:-----------------------------------------------------------------------------------------------------------------------------------|
| freq | Number | Basic signal frequency, Hz |
| bandwidth | Number | Received signal bandwidth, Hz |
| demode_out_sr | Number | _Optional._ Demodulator out samplerate. Equal to `bandwidth` by default |
| enabled | Boolean | _Optional._ Enable/Disable this frequency. `true` by default |
| subname | String | _Optional._ Subname added to result filename. Empty by default |
| freq_correction | Boolean | _Optional._ Correction for basic frequency, Hz. `0` by default |
| mode | String | _Optional._ Modulation option (see [modulations](#modulations)). `RAW` by default |
| decode | String | _Optional._ Decoder option (see [decoders](#decoders)). `RAW` by default |
| iq_waterfall | Object | _Optional._ Write also IQ waterfall for bandwidth. `none` by default. See below for object info |
| iq_dump | Boolean | _Optional._ Dump and send IQ file for current bandwidth. `false` by default |
| channels | Array of Number | _Required only for **FSK**, **GFSK**, **GMSK** mode._ Demodulation baudrates, bps. `[1200, 2400, 4800, 9600]` by default |
| deviation_factor | Number | _Required only for **FSK**, **GFSK**, **GMSK**, **QUAD2FSK** mode._ Deviation frequency factor (baudrate / factor), `5` by default |
| fsk_baudrate | Integer | _Optional. Required for **QUAD2FSK** mode._ |
| proto_mode | String | _Optional. Required for **QUAD2FSK** mode._ |
| grs_file | String | _Optional. Only for **SATS** decoder._ See [gr-satellites](#gr-satellites) for details |
| grs_name | String | _Optional. Only for **SATS** decoder._ See [gr-satellites](#gr-satellites) for details |
| grs_norad | Integer | _Optional. Only for **SATS** decoder._ See [gr-satellites](#gr-satellites) for details |
| grs_tlm_decode | Boolean | _Optional. Only for **SATS** decoder._ Save decoded telemetry. `true` by default |
| qpsk_baudrate | Number | _Required only for **(O)QPSK** mode._ (O)QPSK Baudrate, bps |
| qpsk_excess_bw | Number | _Optional. Only for **(O)QPSK** mode._ (O)QPSK Excess bandwidth. `0.35` by default |
| qpsk_ntaps | Integer | _Optional. Only for **(O)QPSK** mode._ (O)QPSK number of taps. `33` by default |
| qpsk_costas_bw | Number | _Optional. Only for **(O)QPSK** mode._ (O)QPSK Costas bandwidth. `0.005` by default |
| sstv_wsr | Number | _Optional. Only for **SSTV** decoder._ SSTV work samplerate. `16000` by default |
| sstv_sync | Number | _Optional. Only for **SSTV** decoder._ SSTV syncing. `true` by default |
| sstv_live_exec | Number | _Optional. Only for **SSTV** decoder._ SSTV live executing. `false` by default |
| ccc_frame_size | Number | _Optional. Only for **CCSDSCC** decoder._ Frame size, bytes. `892` by default |
| ccc_pre_deint | Boolean | _Optional. Only for **CCSDSCC** decoder._ Pre-Deinterleaving. `false` by default |
| ccc_diff | Boolean | _Optional. Only for **CCSDSCC** decoder._ Differential Decoding. `true` by default |
| ccc_rs_dualbasis | Boolean | _Optional. Only for **CCSDSCC** decoder._ Reed-Solomon Dualbasis. `false` by default |
| ccc_rs_interleaving | Number | _Optional. Only for **CCSDSCC** decoder._ Reed-Solomon Interleaving. `4` by default |
| ccc_derandomize | Boolean | _Optional. Only for **CCSDSCC** decoder._ Descrambling. `true` by default |
| quad_gain | Number | _Optional. Only for **QUAD**, **SSTV_QUAD**, **QUAD2FSK** modes._ Quadrature demodulation gain. `1.0` by default |
| raw_out_format | String | _Optional. Only for **RAW** decoder._ WAV output format. `WAV` by default |
| raw_out_subformat | String | _Optional. Only for **RAW** decoder._ WAV output subformat. `FLOAT` by default |
| proto_deframer | String | _Optional. Only for **PROTO** decoder._ Name of the gr-satellites deframer. See [proto](#proto) for detail. |
| proto_options | String | _Optional. Only for **PROTO** decoder._ Deframer options. See [proto](#proto) for detail. |
| ssb_bandwidth | Number | _Optional. Only for **SSB**-family mode._ SSB Bandwidth, Hz. `4600` for DSB nd `2800` foa another by default |
| ssb_out_sr | Number | _Optional. Only for **SSB**-family mode._ SSB out sample rate, Hz. `8000` by default |

* `iq_waterfall` Create waterfall. Mapping with options (might be empty):
* `fft_size` FFT size (int) `4096` by default
Expand All @@ -223,6 +225,7 @@ Each frequency object contain:
* `WFM`
* `WFM_STEREO`
* `QUAD`
* `QUAD2FSK`
* `SSTV_QUAD`
* `QPSK`
* `OQPSK`
Expand Down Expand Up @@ -259,6 +262,7 @@ Each frequency object contain:
* Scottie (S1, S2, S3, S4)
* `SATS` See [gr-satellites](#gr-satellites) for details
* `PROTO` Satellite deframer based decoder. KISS file on output. See [proto](#proto) for detail. _Only for *FSK mode._
* `PROTO_RAW`
* ~~`LRPT`~~ Not implemented yet

##### gr-satellites
Expand Down
39 changes: 32 additions & 7 deletions sats_receiver/gr_modules/decoders.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,15 +746,15 @@ class ProtoDecoder(Decoder):

def __init__(self,
recorder: 'SatRecorder',
channles: List[Union[int, float]]):
channels: List[Union[int, float]]):

self.deftype = recorder.proto_deframer
name = self.deftype.name + ' Decoder'

chn = len(channles)
chn = len(channels)
super(ProtoDecoder, self).__init__(
recorder,
max(channles),
max(channels),
name,
utils.Decode.PROTO,
[
Expand All @@ -765,7 +765,7 @@ def __init__(self,
],
)

self.base_kw['channles'] = channles
self.base_kw['channels'] = channels
self.base_kw['deftype'] = self.deftype

self.deframers = []
Expand All @@ -774,7 +774,7 @@ def __init__(self,

defr = self.deframer[self.deftype]
opts = recorder.proto_options
for i, baud in enumerate(channles):
for i, baud in enumerate(channels):
df = defr(**opts)
self.deframers.append(df)
self.connect((self, i), df)
Expand Down Expand Up @@ -802,14 +802,39 @@ def _proto_finalize(log: logging.Logger,
log.debug('finalizing...')

st = tmp_file.stat()
d = dt.datetime.fromtimestamp(st.st_mtime, dateutil.tz.tzutc())
d = kw.get('end_time')
if d:
d = dt.datetime.fromisoformat(d)
else:
d = dt.datetime.fromtimestamp(st.st_mtime, dateutil.tz.tzutc())
res_fn = tmp_file.rename(out_dir / d.strftime(f'{sat_name}_%Y-%m-%d_%H-%M-%S,%f_{deftype.name}{subname}.kss'))
log.info('finish: %s (%s)', res_fn, utils.numbi_disp(st.st_size))
if not st.st_size:
res_fn.unlink(True)
return utils.Decode.NONE,

return dtype, deftype, sat_name, observation_key, res_fn, dt.datetime.fromtimestamp(st.st_mtime, dateutil.tz.tzutc())
return dtype, deftype, sat_name, observation_key, res_fn, d


class ProtoRawDecoder(RawDecoder):
def __init__(self,
recorder: 'SatRecorder',
samp_rate: Union[int, float],
force_nosend_iq=False,
iq_in=True):
super().__init__(recorder, samp_rate, force_nosend_iq, iq_in)

self.base_kw['channels'] = recorder.channels
self.base_kw['deftype'] = recorder.proto_deframer
self.base_kw['proto_mode'] = recorder.proto_mode
self.base_kw['proto_options'] = recorder.proto_options

@staticmethod
def _raw_finalize(**kw):
dtype, *x = RawDecoder._raw_finalize(**kw)
if dtype == utils.Decode.NONE:
return dtype,
return dtype, kw['proto_mode'], kw['proto_options'], kw['deftype'], kw['channels'], *x


# needed for typehints
Expand Down
49 changes: 45 additions & 4 deletions sats_receiver/gr_modules/demodulators.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ class FskDemod(gr.gr.hier_block2):
def __init__(self,
samp_rate: Union[int, float],
channels: List[Union[int, float]] = None,
deviation_factor: Union[int, float] = 5):
deviation_factor: Union[int, float] = 5,
iq=True):
self.prefix = self.__class__.__name__
self.log = logging.getLogger(self.prefix)

Expand All @@ -157,7 +158,9 @@ def __init__(self,
chans = len(channels)
super(FskDemod, self).__init__(
self.prefix.partition('Demod')[0] + ' Demodulator',
gr.gr.io_signature(1, 1, gr.gr.sizeof_gr_complex),
gr.gr.io_signature(1, 1, gr.gr.sizeof_gr_complex)
if iq
else gr.gr.io_signature(1, 1, gr.gr.sizeof_float),
gr.gr.io_signature(1, 1, gr.gr.sizeof_float)
if chans == 1
else gr.gr.io_signature.makev(chans, chans, [gr.gr.sizeof_float] * chans)
Expand All @@ -166,7 +169,7 @@ def __init__(self,
self.channel_demod = {}
for i, baud in enumerate(channels):
deviation = baud / deviation_factor
demod = grs_demodulators.fsk_demodulator(baud, samp_rate, 1, deviation, dc_block=0)
demod = grs_demodulators.fsk_demodulator(baud, samp_rate, iq, deviation, dc_block=0)
self.channel_demod[baud] = demod
self.connect(self, demod, (self, i))

Expand All @@ -184,7 +187,6 @@ class GmskDemod(FskDemod):


class SsbDemod(gr.gr.hier_block2):

def __init__(self,
samp_rate: Union[int, float],
mode: utils.SsbMode,
Expand Down Expand Up @@ -252,3 +254,42 @@ def __init__(self,
self,
)
self.connect((self.ctf, 1), (self.add, 1))


class Quad2FskDemod(gr.gr.hier_block2):
def __init__(self,
samp_rate: Union[int, float],
baudrate: int,
deviation_factor: Union[int, float] = 5,
quad_gain: Union[int, float] = 1.0):
super(Quad2FskDemod, self).__init__(
'Quad for FSK Demodulator',
gr.gr.io_signature(1, 1, gr.gr.sizeof_gr_complex),
gr.gr.io_signature(1, 1, gr.gr.sizeof_float)
)

fsk_deviation_hz = baudrate / deviation_factor
carson_cutoff = abs(fsk_deviation_hz) + baudrate / 2
decim = int(samp_rate // (2 * (carson_cutoff + carson_cutoff * 0.1)))

self.channels = [samp_rate // decim]
self.flow = [self]

if decim > 1:
self.flow.append(
gr.filter.fir_filter_ccf(
decim,
gr.filter.firdes.low_pass(
gain=1,
sampling_freq=samp_rate,
cutoff_freq=carson_cutoff,
transition_width=(carson_cutoff * 0.1)
)
)
)

self.demod = gr.analog.quadrature_demod_cf(quad_gain)
self.flow.append(self.demod)
self.flow.append(self)

self.connect(*self.flow)
Loading

0 comments on commit 1ba014f

Please sign in to comment.