first working nfm chain using pycsdr

This commit is contained in:
Jakob Ketterl
2021-07-19 19:04:14 +02:00
parent bb77d2ce0a
commit 5bb14a8997
5 changed files with 139 additions and 25 deletions

View File

@ -13,43 +13,57 @@ class Chain:
self._connect(self.workers[i - 1], self.workers[i])
def _connect(self, w1, w2):
buffer = Buffer(w1.getOutputFormat())
w1.setOutput(buffer)
if isinstance(w1, Chain):
buffer = w1.getOutput()
else:
buffer = Buffer(w1.getOutputFormat())
w1.setOutput(buffer)
w2.setInput(buffer)
def stop(self):
for w in self.workers:
w.stop()
self.setInput(None)
self.setOutput(None)
if self.output is not None:
self.output.stop()
def setInput(self, buffer):
if self.input == buffer:
return
self.input = buffer
self.workers[0].setInput(buffer)
if self.workers:
self.workers[0].setInput(buffer)
else:
self.output = self.input
def setOutput(self, buffer):
if self.output == buffer:
return
if self.output is not None:
self.output.stop()
self.output = buffer
self.workers[-1].setOutput(buffer)
def getOutput(self):
if self.output is None:
if self.workers:
lastWorker = self.workers[-1]
if isinstance(lastWorker, Chain):
self.output = lastWorker.getOutput()
else:
self.output = Buffer(self.getOutputFormat())
self.workers[-1].setOutput(self.output)
else:
self.output = self.input
return self.output
def getOutputFormat(self):
return self.workers[-1].getOutputFormat()
if self.workers:
return self.workers[-1].getOutputFormat()
else:
return self.input.getOutputFormat()
def pump(self, write):
if self.output is None:
self.setOutput(Buffer(self.getOutputFormat()))
output = self.getOutput()
def copy():
run = True
while run:
data = None
try:
data = self.output.read()
data = output.read()
except ValueError:
pass
if data is None or (isinstance(data, bytes) and len(data) == 0):

56
csdr/chain/demodulator.py Normal file
View File

@ -0,0 +1,56 @@
from csdr.chain import Chain
from pycsdr.modules import Shift, FirDecimate, Bandpass, Squelch, FractionalDecimator
from abc import ABCMeta, abstractmethod
class Demodulator(Chain, metaclass=ABCMeta):
@abstractmethod
def setLastDecimation(self, decimation: Chain):
pass
class DemodulatorChain(Chain):
def __init__(self, samp_rate: int, audioRate: int, shiftRate: float, demodulator: Demodulator):
self.shift = Shift(shiftRate)
decimation, fraction = self._getDecimation(samp_rate, audioRate)
if_samp_rate = samp_rate / decimation
transition = 0.15 * (if_samp_rate / float(samp_rate))
self.decimation = FirDecimate(decimation, transition)
bp_transition = 320.0 / if_samp_rate
self.bandpass = Bandpass(bp_transition, use_fft=True)
self.squelch = Squelch(5)
if fraction != 1.0:
demodulator.setLastDecimation(Chain(FractionalDecimator(fraction)))
workers = [
self.shift,
self.decimation,
self.bandpass,
self.squelch,
demodulator
]
super().__init__(*workers)
def setShiftRate(self, rate: float):
self.shift.setRate(rate)
def setSquelchLevel(self, level: float):
self.squelch.setSquelchLevel(level)
def setBandpass(self, low_cut: float, high_cut: float):
self.bandpass.setBandpass(low_cut, high_cut)
def _getDecimation(self, input_rate, output_rate):
if output_rate <= 0:
raise ValueError("invalid output rate: {rate}".format(rate=output_rate))
decimation = 1
target_rate = output_rate
while input_rate / (decimation + 1) >= target_rate:
decimation += 1
fraction = float(input_rate / decimation) / output_rate
return decimation, fraction

22
csdr/chain/fm.py Normal file
View File

@ -0,0 +1,22 @@
from csdr.chain.demodulator import Demodulator, Chain
from pycsdr.modules import FmDemod, Limit, NfmDeemphasis, Agc, Convert
from pycsdr.types import Format
class Fm(Demodulator):
def __init__(self, sampleRate: int):
workers = [
FmDemod(),
Limit(),
# empty chain as placeholder for the "last decimation"
Chain(),
NfmDeemphasis(sampleRate),
Agc(Format.FLOAT),
Convert(Format.FLOAT, Format.SHORT),
]
super().__init__(*workers)
def setLastDecimation(self, decimation: Chain):
# TODO: build api to replace workers
# TODO: replace placeholder
pass