restore PSK decoding
This commit is contained in:
@ -1,21 +1,8 @@
|
||||
from csdr.chain import Chain
|
||||
from abc import ABC, abstractmethod
|
||||
from abc import ABC, ABCMeta, abstractmethod
|
||||
from pycsdr.modules import Writer
|
||||
|
||||
|
||||
class BaseDemodulatorChain(Chain):
|
||||
def supportsSquelch(self) -> bool:
|
||||
return True
|
||||
|
||||
def setSampleRate(self, sampleRate: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class SecondaryDemodulator(Chain):
|
||||
def supportsSquelch(self) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class FixedAudioRateChain(ABC):
|
||||
@abstractmethod
|
||||
def getFixedAudioRate(self) -> int:
|
||||
@ -49,3 +36,28 @@ class SlotFilterChain(ABC):
|
||||
@abstractmethod
|
||||
def setSlotFilter(self, filter: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class SecondarySelectorChain(ABC):
|
||||
def getBandwidth(self) -> float:
|
||||
pass
|
||||
|
||||
|
||||
class BaseDemodulatorChain(Chain):
|
||||
def supportsSquelch(self) -> bool:
|
||||
return True
|
||||
|
||||
def setSampleRate(self, sampleRate: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class SecondaryDemodulator(Chain):
|
||||
def supportsSquelch(self) -> bool:
|
||||
return True
|
||||
|
||||
def setSampleRate(self, sampleRate: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class ServiceDemodulator(SecondaryDemodulator, FixedAudioRateChain, metaclass=ABCMeta):
|
||||
pass
|
||||
|
@ -1,15 +1,15 @@
|
||||
from csdr.chain.demodulator import SecondaryDemodulator, FixedAudioRateChain, DialFrequencyReceiver
|
||||
from csdr.chain.demodulator import ServiceDemodulator, SecondaryDemodulator, DialFrequencyReceiver, SecondarySelectorChain
|
||||
from owrx.audio.chopper import AudioChopper
|
||||
from owrx.aprs.kiss import KissDeframer
|
||||
from owrx.aprs import Ax25Parser, AprsParser
|
||||
from pycsdr.modules import Convert, FmDemod
|
||||
from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder
|
||||
from pycsdr.types import Format
|
||||
from owrx.aprs.module import DirewolfModule
|
||||
from digiham.modules import FskDemodulator, PocsagDecoder
|
||||
from owrx.pocsag import PocsagParser
|
||||
|
||||
|
||||
class AudioChopperDemodulator(SecondaryDemodulator, FixedAudioRateChain, DialFrequencyReceiver):
|
||||
class AudioChopperDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
# TODO parser typing
|
||||
def __init__(self, mode: str, parser):
|
||||
self.chopper = AudioChopper(mode, parser)
|
||||
@ -23,7 +23,7 @@ class AudioChopperDemodulator(SecondaryDemodulator, FixedAudioRateChain, DialFre
|
||||
self.chopper.setDialFrequency(frequency)
|
||||
|
||||
|
||||
class PacketDemodulator(SecondaryDemodulator, FixedAudioRateChain, DialFrequencyReceiver):
|
||||
class PacketDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
def __init__(self, service: bool = False):
|
||||
self.parser = AprsParser()
|
||||
workers = [
|
||||
@ -46,7 +46,7 @@ class PacketDemodulator(SecondaryDemodulator, FixedAudioRateChain, DialFrequency
|
||||
self.parser.setDialFrequency(frequency)
|
||||
|
||||
|
||||
class PocsagDemodulator(SecondaryDemodulator, FixedAudioRateChain):
|
||||
class PocsagDemodulator(ServiceDemodulator):
|
||||
def __init__(self):
|
||||
workers = [
|
||||
FmDemod(),
|
||||
@ -61,3 +61,28 @@ class PocsagDemodulator(SecondaryDemodulator, FixedAudioRateChain):
|
||||
|
||||
def getFixedAudioRate(self) -> int:
|
||||
return 48000
|
||||
|
||||
|
||||
class PskDemodulator(SecondaryDemodulator, SecondarySelectorChain):
|
||||
def __init__(self, baudRate: float):
|
||||
self.baudRate = baudRate
|
||||
# this is an assumption, we will adjust in setSampleRate
|
||||
self.sampleRate = 12000
|
||||
secondary_samples_per_bits = int(round(self.sampleRate / self.baudRate)) & ~3
|
||||
workers = [
|
||||
Agc(Format.COMPLEX_FLOAT),
|
||||
TimingRecovery(secondary_samples_per_bits, 0.5, 2, useQ=True),
|
||||
DBPskDecoder(),
|
||||
VaricodeDecoder(),
|
||||
]
|
||||
super().__init__(workers)
|
||||
|
||||
def getBandwidth(self):
|
||||
return self.baudRate
|
||||
|
||||
def setSampleRate(self, sampleRate: int) -> None:
|
||||
if sampleRate == self.sampleRate:
|
||||
return
|
||||
self.sampleRate = sampleRate
|
||||
secondary_samples_per_bits = int(round(self.sampleRate / self.baudRate)) & ~3
|
||||
self.replace(1, TimingRecovery(secondary_samples_per_bits, 0.5, 2, useQ=True))
|
||||
|
@ -62,10 +62,12 @@ class Decimator(Chain):
|
||||
|
||||
|
||||
class Selector(Chain):
|
||||
def __init__(self, inputRate: int, outputRate: int, shiftRate: float, withSquelch: bool = True):
|
||||
def __init__(self, inputRate: int, outputRate: int, withSquelch: bool = True):
|
||||
self.inputRate = inputRate
|
||||
self.outputRate = outputRate
|
||||
self.frequencyOffset = 0
|
||||
|
||||
self.shift = Shift(shiftRate)
|
||||
self.shift = Shift(0.0)
|
||||
|
||||
self.decimation = Decimator(inputRate, outputRate)
|
||||
|
||||
@ -88,8 +90,15 @@ class Selector(Chain):
|
||||
bp_transition = 320.0 / self.outputRate
|
||||
return Bandpass(transition=bp_transition, use_fft=True)
|
||||
|
||||
def setShiftRate(self, rate: float) -> None:
|
||||
self.shift.setRate(rate)
|
||||
def setFrequencyOffset(self, offset: int) -> None:
|
||||
if offset == self.frequencyOffset:
|
||||
return
|
||||
self.frequencyOffset = offset
|
||||
self._updateShift()
|
||||
|
||||
def _updateShift(self):
|
||||
shift = -self.frequencyOffset / self.inputRate
|
||||
self.shift.setRate(shift)
|
||||
|
||||
def _convertToLinear(self, db: float) -> float:
|
||||
return float(math.pow(10, db / 10))
|
||||
@ -125,4 +134,27 @@ class Selector(Chain):
|
||||
self.replace(2, self.bandpass)
|
||||
|
||||
def setInputRate(self, inputRate: int) -> None:
|
||||
if inputRate == self.inputRate:
|
||||
return
|
||||
self.inputRate = inputRate
|
||||
self.decimation.setInputRate(inputRate)
|
||||
self._updateShift()
|
||||
|
||||
|
||||
class SecondarySelector(Chain):
|
||||
def __init__(self, sampleRate: int, bandwidth: float):
|
||||
self.sampleRate = sampleRate
|
||||
self.frequencyOffset = 0
|
||||
self.shift = Shift(0.0)
|
||||
cutoffRate = bandwidth / sampleRate
|
||||
self.bandpass = Bandpass(-cutoffRate, cutoffRate, cutoffRate, use_fft=True)
|
||||
workers = [self.shift, self.bandpass]
|
||||
super().__init__(workers)
|
||||
|
||||
def setFrequencyOffset(self, offset: int) -> None:
|
||||
if offset == self.frequencyOffset:
|
||||
return
|
||||
self.frequencyOffset = offset
|
||||
if self.frequencyOffset is None:
|
||||
return
|
||||
self.shift.setRate(-offset / self.sampleRate)
|
||||
|
Reference in New Issue
Block a user