From c19b648cb601ff92b0f0caaeae9db6813dc6fead Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Wed, 6 Dec 2023 23:52:34 -0500 Subject: [PATCH] Adding initial DSC support. --- csdr/chain/digimodes.py | 36 +++++++++++++++++++++++++++++++++++- owrx/dsp.py | 3 +++ owrx/modes.py | 1 + 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/csdr/chain/digimodes.py b/csdr/chain/digimodes.py index ce4b3d5d..53b17ce0 100644 --- a/csdr/chain/digimodes.py +++ b/csdr/chain/digimodes.py @@ -3,7 +3,7 @@ from csdr.module.msk144 import Msk144Module, ParserAdapter from owrx.audio.chopper import AudioChopper, AudioChopperParser from owrx.aprs.kiss import KissDeframer from owrx.aprs import Ax25Parser, AprsParser -from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder, RttyDecoder, BaudotDecoder, Lowpass, MFRttyDecoder, CwDecoder, SstvDecoder, FaxDecoder, SitorDecoder, Ccir476Decoder, Shift +from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder, RttyDecoder, BaudotDecoder, Lowpass, MFRttyDecoder, CwDecoder, SstvDecoder, FaxDecoder, SitorDecoder, Ccir476Decoder, DscDecoder, Ccir493Decoder, Shift from pycsdr.types import Format from owrx.aprs.direwolf import DirewolfModule from owrx.sstv import SstvParser @@ -250,3 +250,37 @@ class SitorBDemodulator(SecondaryDemodulator, SecondarySelectorChain): loop_gain = self.sampleRate / self.getBandwidth() / 5 self.replace(2, Lowpass(Format.FLOAT, cutoff)) self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10)) + + +class DscDemodulator(SecondaryDemodulator, SecondarySelectorChain): + def __init__(self, baudRate, bandWidth, invert=False): + self.baudRate = baudRate + self.bandWidth = bandWidth + self.invert = invert + # this is an assumption, we will adjust in setSampleRate + self.sampleRate = 12000 + secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate)) + cutoff = self.baudRate / self.sampleRate + loop_gain = self.sampleRate / self.getBandwidth() / 5 + workers = [ + Agc(Format.COMPLEX_FLOAT), + FmDemod(), + Lowpass(Format.FLOAT, cutoff), + TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10), + Ccir493Decoder(fec=True, invert=invert), + DscDecoder(), + ] + super().__init__(workers) + + def getBandwidth(self) -> float: + return self.bandWidth + + def setSampleRate(self, sampleRate: int) -> None: + if sampleRate == self.sampleRate: + return + self.sampleRate = sampleRate + secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate)) + cutoff = self.baudRate / self.sampleRate + loop_gain = self.sampleRate / self.getBandwidth() / 5 + self.replace(2, Lowpass(Format.FLOAT, cutoff)) + self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10)) diff --git a/owrx/dsp.py b/owrx/dsp.py index 41e4c6a6..2b508eea 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -670,6 +670,9 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) elif mod == "sitorb": from csdr.chain.digimodes import SitorBDemodulator return SitorBDemodulator(100, 170) + elif mod == "dsc": + from csdr.chain.digimodes import DscDemodulator + return DscDemodulator(100, 170) elif mod == "cwdecoder": from csdr.chain.digimodes import CwDemodulator return CwDemodulator(75.0) diff --git a/owrx/modes.py b/owrx/modes.py index 0ea84112..7cbff904 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -139,6 +139,7 @@ class Modes(object): DigitalMode("rtty450", "RTTY-450 (50N)", underlying=["usb", "lsb"]), DigitalMode("rtty85", "RTTY-85 (50N)", underlying=["usb", "lsb"]), DigitalMode("sitorb", "SITOR-B", underlying=["usb"]), + DigitalMode("dsc", "DSC", underlying=["usb"]), WsjtMode("ft8", "FT8"), WsjtMode("ft4", "FT4"), WsjtMode("jt65", "JT65"),