diff --git a/simulations/lib/__init__.py b/simulations/lib/__init__.py index f255874..69d5f6e 100644 --- a/simulations/lib/__init__.py +++ b/simulations/lib/__init__.py @@ -1,5 +1,6 @@ from . import signals from . import location +from . import sampling from .util import * diff --git a/simulations/lib/sampling/__init__.py b/simulations/lib/sampling/__init__.py new file mode 100644 index 0000000..1e38591 --- /dev/null +++ b/simulations/lib/sampling/__init__.py @@ -0,0 +1,3 @@ +from .sampling import * +from .sampler import * +from .digitizer import * diff --git a/simulations/lib/sampling/digitizer.py b/simulations/lib/sampling/digitizer.py new file mode 100644 index 0000000..3052073 --- /dev/null +++ b/simulations/lib/sampling/digitizer.py @@ -0,0 +1,36 @@ +import numpy as np + +from . import sampling as smp +from .sampler import Sampler + +class Digitizer(Sampler): + """ + Digitizer that takes in a signal and resamples and quantises the signal. + """ + + def __init__(self, resolution=0.1, sampling_frequency=None): + """ + + Parameters + ########## + resolution - float + Resolution of the digitizer + sampling_frequency - float + Frequency this digitizer will sample a signal + """ + super().__init__(sampling_frequency) + + self.resolution = resolution + + def digitise(self, signal, signal_sample_frequency=None): + """ + Digitize signal according to the specs of this digitizer. + + Effectively resamples signal + """ + signal = np.asarray(signal) + + return smp.quantise( + self.sample(signal, signal_sample_frequency), + self.resolution + ) diff --git a/simulations/lib/sampling/sampler.py b/simulations/lib/sampling/sampler.py new file mode 100644 index 0000000..09c2f76 --- /dev/null +++ b/simulations/lib/sampling/sampler.py @@ -0,0 +1,29 @@ + +import numpy as np + +from . import sampling as smp + +class Sampler(): + """ + A mechanism to sample signals. + """ + + def __init__(self, sampling_frequency=None): + """ + Parameters + ########## + sampling_frequency - float + Frequency the signals will be sampled at + """ + + self.sampling_frequency = sampling_frequency + + def sample(self, signal, signal_fs=None): + """ + Sample signal + """ + # Null operation + if signal_fs is None or self.sampling_frequency is None: + return signal + + return smp.resample(signal, signal_fs, self.sampling_frequency) diff --git a/simulations/lib/sampling/sampling.py b/simulations/lib/sampling/sampling.py new file mode 100644 index 0000000..a3d33fb --- /dev/null +++ b/simulations/lib/sampling/sampling.py @@ -0,0 +1,55 @@ +""" +Sampling related stuff + +Such as a Sampler and Digitizer +""" + +import numpy as np + +def quantise(signal, resolution, bias=0): + """ + Quantise the signal with resolution + + Parameters + ########## + signal - arraylike + The signal to be quantised + resolution - float + Resolution for quantising the signal + bias - optional,float + Optional bias applied before quantising + """ + + return np.round(signal / resolution - bias) * resolution + +def resample(signal, signal_fs, sample_frequency = 1, periodic=True): + """ + Resample signal (sampled at signal_fs) to sample_frequency + + Parameters + ########## + signal - arraylike + The signal to be resampled + signal_fs - float + Sampling frequency of signal + sample_frequency - float + Wanted sampling frequency for the resampled signal + """ + + scale = sample_frequency / signal_fs + + return _resample(signal, scale) + +def _resample(signal, scale): + """ + Quick resampling algorithm + + From: https://github.com/nwhitehead/swmixer/blob/master/swmixer.py + """ + n = round( len(signal) * scale ) + + return np.interp( + np.linspace(0, 1, n, endpoint=False), # where to interpret + np.linspace(0, 1, len(signal), endpoint=False), # known positions + signal, # known data points + )