From 37ee7796dbce35ff24d85a9798f8be371bda3987 Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Fri, 25 Aug 2023 21:12:13 +0200 Subject: [PATCH] added option to run demodulator without bandpass --- csdr/chain/__init__.py | 15 ++++++++++----- csdr/chain/selector.py | 30 ++++++++++++++++++++++++++---- htdocs/lib/Demodulator.js | 15 +++++++++++++-- htdocs/lib/DemodulatorPanel.js | 2 ++ owrx/dsp.py | 8 +++++++- owrx/modes.py | 2 +- owrx/service/__init__.py | 7 +++++-- 7 files changed, 64 insertions(+), 15 deletions(-) diff --git a/csdr/chain/__init__.py b/csdr/chain/__init__.py index b9af86a9..02bb5951 100644 --- a/csdr/chain/__init__.py +++ b/csdr/chain/__init__.py @@ -94,19 +94,24 @@ class Chain(Module): if self.writer is not None: newWorker.setWriter(self.writer) - def insert(self, newWorker): + def insert(self, newWorker, index=0): nextWorker = None - if self.workers: - nextWorker = self.workers[0] + previousWorker = None + if index < len(self.workers): + nextWorker = self.workers[index] + if index > 0: + previousWorker = self.workers[index - 1] - self.workers.insert(0, newWorker) + self.workers.insert(index, newWorker) if nextWorker: self._connect(newWorker, nextWorker) elif self.writer is not None: newWorker.setWriter(self.writer) - if self.reader is not None: + if previousWorker: + self._connect(previousWorker, newWorker) + elif self.reader is not None: newWorker.setReader(self.reader) def remove(self, index): diff --git a/csdr/chain/selector.py b/csdr/chain/selector.py index 8b009fb0..2f272bbc 100644 --- a/csdr/chain/selector.py +++ b/csdr/chain/selector.py @@ -1,6 +1,7 @@ from csdr.chain import Chain from pycsdr.modules import Shift, FirDecimate, Bandpass, Squelch, FractionalDecimator, Writer from pycsdr.types import Format +from owrx.property import PropertyDeleted import math @@ -80,7 +81,6 @@ class Selector(Chain): self.bandpass = self._buildBandpass() self.bandpassCutoffs = None - self.setBandpass(-4000, 4000) workers = [self.shift, self.decimation, self.bandpass] @@ -93,6 +93,8 @@ class Selector(Chain): super().__init__(workers) + self.setBandpass(-4000, 4000) + def _buildBandpass(self) -> Bandpass: bp_transition = 320.0 / self.outputRate return Bandpass(transition=bp_transition, use_fft=True) @@ -113,16 +115,34 @@ class Selector(Chain): def setSquelchLevel(self, level: float) -> None: self.squelch.setSquelchLevel(self._convertToLinear(level)) + def _enableBandpass(self): + index = self.indexOf(lambda x: isinstance(x, Bandpass)) + if index < 0: + self.insert(self.bandpass, 2) + + def _disableBandpass(self): + index = self.indexOf(lambda x: isinstance(x, Bandpass)) + if index >= 0: + self.remove(index) + def setBandpass(self, lowCut: float, highCut: float) -> None: self.bandpassCutoffs = [lowCut, highCut] - scaled = [x / self.outputRate for x in self.bandpassCutoffs] - self.bandpass.setBandpass(*scaled) + if None in self.bandpassCutoffs: + self._disableBandpass() + else: + self._enableBandpass() + scaled = [x / self.outputRate for x in self.bandpassCutoffs] + self.bandpass.setBandpass(*scaled) def setLowCut(self, lowCut: float) -> None: + if lowCut is PropertyDeleted: + lowCut = None self.bandpassCutoffs[0] = lowCut self.setBandpass(*self.bandpassCutoffs) def setHighCut(self, highCut: float) -> None: + if highCut is PropertyDeleted: + highCut = None self.bandpassCutoffs[1] = highCut self.setBandpass(*self.bandpassCutoffs) @@ -136,9 +156,11 @@ class Selector(Chain): self.decimation.setOutputRate(outputRate) self.squelch.setReportInterval(int(outputRate / (self.readings_per_second * 1024))) + index = self.indexOf(lambda x: isinstance(x, Bandpass)) self.bandpass = self._buildBandpass() self.setBandpass(*self.bandpassCutoffs) - self.replace(2, self.bandpass) + if index >= 0: + self.replace(index, self.bandpass) def setInputRate(self, inputRate: int) -> None: if inputRate == self.inputRate: diff --git a/htdocs/lib/Demodulator.js b/htdocs/lib/Demodulator.js index 79282b61..6dadac9d 100644 --- a/htdocs/lib/Demodulator.js +++ b/htdocs/lib/Demodulator.js @@ -83,9 +83,13 @@ Envelope.prototype.draw = function(visible_range){ scale_ctx.stroke(); scale_ctx.lineWidth = 1; scale_ctx.textAlign = "left"; - scale_ctx.fillText(this.demodulator.high_cut.toString(), to_px + env_att_w, env_h2); + if (this.demodulator.high_cut) { + scale_ctx.fillText(this.demodulator.high_cut.toString(), to_px + env_att_w, env_h2); + } scale_ctx.textAlign = "right"; - scale_ctx.fillText(this.demodulator.low_cut.toString(), from_px - env_att_w, env_h2); + if (this.demodulator.low_cut) { + scale_ctx.fillText(this.demodulator.low_cut.toString(), from_px - env_att_w, env_h2); + } scale_ctx.lineWidth = 3; } if (typeof line !== "undefined") // out of screen? @@ -332,6 +336,13 @@ Demodulator.prototype.setBandpass = function(bandpass) { this.set(); }; +Demodulator.prototype.disableBandpass = function() { + delete this.bandpass; + this.low_cut = null; + this.high_cut = null; + this.set() +} + Demodulator.prototype.setLowCut = function(low_cut) { this.low_cut = low_cut; this.set(); diff --git a/htdocs/lib/DemodulatorPanel.js b/htdocs/lib/DemodulatorPanel.js index 042e4fe8..995f53a1 100644 --- a/htdocs/lib/DemodulatorPanel.js +++ b/htdocs/lib/DemodulatorPanel.js @@ -137,6 +137,8 @@ DemodulatorPanel.prototype.setMode = function(requestedModulation, underlyingMod this.demodulator.set_secondary_demod(mode.modulation); if (mode.bandpass) { this.demodulator.setBandpass(mode.bandpass); + } else { + this.demodulator.disableBandpass(); } } else { this.demodulator.set_secondary_demod(false); diff --git a/owrx/dsp.py b/owrx/dsp.py index 864d5ea0..641d9488 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -462,6 +462,8 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) if mode.bandpass: bpf = [mode.bandpass.low_cut, mode.bandpass.high_cut] self.chain.setBandpass(*bpf) + else: + self.chain.setBandpass(None, None) else: # TODO modes should be mandatory self.setDemodulator(self.props["start_mod"]) @@ -714,7 +716,11 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) self.setProperty(k, v) def setProperty(self, prop, value): - self.localProps[prop] = value + if value is None: + if prop in self.localProps: + del self.localProps[prop] + else: + self.localProps[prop] = value def getClientClass(self) -> SdrClientClass: return SdrClientClass.USER diff --git a/owrx/modes.py b/owrx/modes.py index 31b6b8d8..582bf70a 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -168,7 +168,7 @@ class Modes(object): "adsb", "ADS-B", underlying=["empty"], - bandpass=Bandpass(-1e6, 1e6), + bandpass=None, requirements=["dump1090"], service=True, squelch=False, diff --git a/owrx/service/__init__.py b/owrx/service/__init__.py index f705c672..3662391e 100644 --- a/owrx/service/__init__.py +++ b/owrx/service/__init__.py @@ -266,12 +266,15 @@ class ServiceHandler(SdrSourceEventClient): secondaryDemod = self._getSecondaryDemodulator(modeObject.modulation) center_freq = source.getProps()["center_freq"] sampleRate = source.getProps()["samp_rate"] - bandpass = modeObject.get_bandpass() if isinstance(secondaryDemod, DialFrequencyReceiver): secondaryDemod.setDialFrequency(dial["frequency"]) chain = ServiceDemodulatorChain(demod, secondaryDemod, sampleRate, dial["frequency"] - center_freq) - chain.setBandPass(bandpass.low_cut, bandpass.high_cut) + bandpass = modeObject.get_bandpass() + if bandpass: + chain.setBandPass(bandpass.low_cut, bandpass.high_cut) + else: + chain.setBandPass(None, None) chain.setReader(source.getBuffer().getReader()) # dummy buffer, we don't use the output right now