From 3adc36a7e5adce575688582dab6f2d89cfea3216 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Mon, 6 Feb 2023 20:48:35 -0500 Subject: [PATCH 1/2] Adding SSTV decoder. --- csdr/chain/digimodes.py | 26 ++++++++++++++++++++++++-- owrx/dsp.py | 3 +++ owrx/modes.py | 1 + 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/csdr/chain/digimodes.py b/csdr/chain/digimodes.py index ae2a5b12..a51e538e 100644 --- a/csdr/chain/digimodes.py +++ b/csdr/chain/digimodes.py @@ -2,7 +2,7 @@ from csdr.chain.demodulator import ServiceDemodulator, SecondaryDemodulator, Dia 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, CwDecoder, RttyDecoder, Shift +from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder, CwDecoder, RttyDecoder, SstvDecoder, Shift from pycsdr.types import Format from owrx.aprs.module import DirewolfModule @@ -90,7 +90,6 @@ class CwDemodulator(SecondaryDemodulator, SecondarySelectorChain): self.replace(2, CwDecoder(sampleRate, 800, int(self.baudRate))) - class RttyDemodulator(SecondaryDemodulator, SecondarySelectorChain): def __init__(self, targetWidth: float, baudRate: float, reverse: bool): self.sampleRate = 12000 @@ -113,3 +112,26 @@ class RttyDemodulator(SecondaryDemodulator, SecondarySelectorChain): self.sampleRate = sampleRate self.replace(0, Shift((self.targetWidth/2 + 550) / sampleRate)) self.replace(2, RttyDecoder(sampleRate, 550, int(self.targetWidth), self.baudRate, self.reverse)) + + +class SstvDemodulator(SecondaryDemodulator, SecondarySelectorChain): + def __init__(self, targetWidth: float): + self.sampleRate = 12000 + self.targetWidth = targetWidth + workers = [ + Shift((self.targetWidth/2) / self.sampleRate), + Agc(Format.COMPLEX_FLOAT), + SstvDecoder(self.sampleRate, int(self.targetWidth)), + ] + super().__init__(workers) + + def getBandwidth(self): + return self.targetWidth + + def setSampleRate(self, sampleRate: int) -> None: + if sampleRate == self.sampleRate: + return + self.sampleRate = sampleRate + self.replace(0, Shift((self.targetWidth/2) / sampleRate)) + self.replace(2, SstvDecoder(sampleRate, int(self.targetWidth))) + diff --git a/owrx/dsp.py b/owrx/dsp.py index e5210a10..fbab7d42 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -622,6 +622,9 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) elif mod == "rtty450": from csdr.chain.digimodes import RttyDemodulator return RttyDemodulator(450.0, 50.0, reverse = True) + elif mod == "sstv": + from csdr.chain.digimodes import SstvDemodulator + return SstvDemodulator(3000.0) def setSecondaryDemodulator(self, mod): demodulator = self._getSecondaryDemodulator(mod) diff --git a/owrx/modes.py b/owrx/modes.py index e7de647b..2afa2ecd 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -141,6 +141,7 @@ class Modes(object): DigitalMode("cwdecoder", "CWDecoder", underlying=["usb"]), DigitalMode("rtty170", "RTTY-170", underlying=["usb"]), DigitalMode("rtty450", "RTTY-450", underlying=["usb"]), + DigitalMode("sstv", "SSTV", underlying=["usb"]), ] @staticmethod From ba7aa19d2ac0ed4449a15f1c5a932006bf060299 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Fri, 10 Feb 2023 20:09:20 -0500 Subject: [PATCH 2/2] Cleanup. --- csdr/chain/digimodes.py | 13 ++++++------- owrx/dsp.py | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/csdr/chain/digimodes.py b/csdr/chain/digimodes.py index a51e538e..9e3a6e94 100644 --- a/csdr/chain/digimodes.py +++ b/csdr/chain/digimodes.py @@ -115,23 +115,22 @@ class RttyDemodulator(SecondaryDemodulator, SecondarySelectorChain): class SstvDemodulator(SecondaryDemodulator, SecondarySelectorChain): - def __init__(self, targetWidth: float): + def __init__(self): self.sampleRate = 12000 - self.targetWidth = targetWidth workers = [ - Shift((self.targetWidth/2) / self.sampleRate), + Shift(1500.0 / self.sampleRate), Agc(Format.COMPLEX_FLOAT), - SstvDecoder(self.sampleRate, int(self.targetWidth)), + SstvDecoder(self.sampleRate), ] super().__init__(workers) def getBandwidth(self): - return self.targetWidth + return 3000.0 def setSampleRate(self, sampleRate: int) -> None: if sampleRate == self.sampleRate: return self.sampleRate = sampleRate - self.replace(0, Shift((self.targetWidth/2) / sampleRate)) - self.replace(2, SstvDecoder(sampleRate, int(self.targetWidth))) + self.replace(0, Shift(1500.0 / sampleRate)) + self.replace(2, SstvDecoder(sampleRate)) diff --git a/owrx/dsp.py b/owrx/dsp.py index fbab7d42..adef6a25 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -624,7 +624,7 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) return RttyDemodulator(450.0, 50.0, reverse = True) elif mod == "sstv": from csdr.chain.digimodes import SstvDemodulator - return SstvDemodulator(3000.0) + return SstvDemodulator() def setSecondaryDemodulator(self, mod): demodulator = self._getSecondaryDemodulator(mod)