From 0a115261d5971a8b32ae4ff0c1907d1a71236663 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 2126b1c1..70f253ee 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 b7d01f90..d8fb1e54 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"),