TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
tinymodem::MFSKDecoder Class Reference

Multi-tone FSK demodulator: PCM audio data is written to the decoder and the decoded bytes are written to the output. The input can be 8, 16 or 32 bit signed samples with any number of channels (only MFSKConfig::channel is evaluated). More...

#include <MFSKDecoder.h>

Inheritance diagram for tinymodem::MFSKDecoder:
Collaboration diagram for tinymodem::MFSKDecoder:

Public Member Functions

 MFSKDecoder ()=default
 MFSKDecoder (Print &out)
MFSKConfig defaultConfig ()
 Provides a default configuration: mfsk16.
void setAudioInfo (audio_tools::AudioInfo info) override
 Defines the format of the input audio data.
audio_tools::AudioInfo audioInfo () override
bool begin (MFSKConfig config)
 Starts the processing with the indicated configuration.
bool begin () override
void end () override
 Processes the remaining samples and reports the end of the carrier.
void flush () override
 Processes all buffered samples (e.g. at the end of the input).
size_t write (const uint8_t *data, size_t len) override
 Provide PCM data to the decoder.
bool isCarrier () override
 true while a transmission is received
bool isFinished () override
 true if the decoding was stopped (rx_one)
MFSKConfig & config ()
 The configuration which was provided in begin().
 operator bool () override
Public Member Functions inherited from tinymodem::ModemDecoder
void setStatusOutput (Print &out)
 Defines the output for the ### CARRIER / ### NOCARRIER messages.
void setQuiet (bool quiet)
 Suppresses the status messages.
const char * mime () override

Protected Types

enum class  State { SEARCH , PREAMBLE , DATA }

Protected Member Functions

void tune (float new_scale)
void setupDetector (audio_tools::GoertzelDetector &det, float freq)
void startSearch ()
 Back to the search for the next preamble.
void resetState ()
float noise ()
 uniform random value in the range -0.5 to 0.5
void addSample (float sample, bool add_noise)
void discard (size_t n)
 Removes the processed samples at the start of the buffer.
float magnitude (int tone, int start)
 Magnitude (amplitude) of the tone in the window starting at start.
float magnitude (audio_tools::GoertzelDetector &det, int start)
 Magnitude (amplitude) of the detector's frequency in the window.
float windowAmplitude (int start)
 Amplitude of a sine with the same energy as the window.
bool step ()
 One processing step: returns false if more data is needed.
bool searchStep ()
 Searches for the preamble at the start of the buffer.
bool hasHighTone (float clock_error, float low)
bool acquire (float coarse_error)
int findTiming ()
bool estimateClock (int offset)
bool symbolStep ()
 Analyzes the next symbol.
void preambleSymbol (int symbol, float amplitude, bool strong)
void dataSymbol (int symbol, float amplitude, float second, bool strong, float symbol_nsamples)
void outputSymbol (int symbol)
void startOfCarrier ()
void endOfCarrier ()
Protected Member Functions inherited from tinymodem::ModemDecoder
void status (const char *fmt,...)

Protected Attributes

MFSKConfig cfg
bool is_active = false
bool is_finished = false
PcmInput input
audio_tools::Vector< audio_tools::GoertzelDetector > detectors
audio_tools::Vector< audio_tools::GoertzelDetector > search_detectors
audio_tools::Vector< float > magnitudes
audio_tools::Vector< float > samples
size_t nvalid = 0
size_t needed = 0
int ntones = 16
int bits_per_symbol = 4
float nsamples = 0
int window = 0
int delta = 1
int acquire_step = 1
int hop = 1
uint32_t noise_seed = 1
float scale = 1.0f
 frequency scale which results from the different sample rates
float drift = 0.0f
 learned timing drift in samples per symbol
bool estimate_clock = true
 true if the clock of the sender is determined from the tones
State state = State::SEARCH
float pos = 0
float track_amplitude = 0
int preamble_count = 0
int sync_stage = 0
bool has_pending = false
int pending_symbol = 0
uint32_t bit_buffer = 0
int bit_count = 0
unsigned ndata = 0
unsigned nsymbols = 0
float confidence_total = 0
float amplitude_total = 0
double data_nsamples = 0
Protected Attributes inherited from tinymodem::ModemDecoder
Print * p_status = nullptr
bool is_quiet = false

Static Protected Attributes

static constexpr int ACQUIRE_SYMBOLS = 4
 number of preamble symbols which are used for the timing acquisition
static constexpr int MAX_PREAMBLE = 64
 max number of preamble symbols before we give up
static constexpr float MAX_CLOCK_ERROR = 0.03f
 max difference of the sample rates of sender and receiver
static constexpr float CLOCK_ERROR_STEP = 0.001f
static constexpr float MIN_CLOCK_GAIN = 1.2f
 a different clock must provide this much more energy
static constexpr float TIMING_GAIN = 0.25f
 gains of the timing loop
static constexpr float DRIFT_GAIN = 0.05f
static constexpr float LOST_LEVEL = 0.4f
 a symbol below this part of the tracked amplitude is lost
static constexpr float NEW_SIGNAL_LEVEL = 4.0f
static constexpr float CLEAR_RATIO = 1.5f
static constexpr float HIGH_TONE_LEVEL = 0.25f
static constexpr float MAX_CONFIDENCE = 100.0f
 the confidence of a symbol is limited to this value
static constexpr int SEARCH_STEPS = 3
 the search checks the clock errors -3% to +3% in steps of 1%
static constexpr float SEARCH_STEP = 0.01f

Detailed Description

Multi-tone FSK demodulator: PCM audio data is written to the decoder and the decoded bytes are written to the output. The input can be 8, 16 or 32 bit signed samples with any number of channels (only MFSKConfig::channel is evaluated).

The decoder searches for the preamble, determines the symbol timing from the alternating preamble tones and waits for the sync symbols. Then each symbol is analyzed with one Goertzel filter per tone. The timing is tracked with an early/late gate, so small differences of the sample rates are corrected. The end of a transmission is detected when the signal is lost.

Status messages (### CARRIER and ### NOCARRIER) are written to the status output.

Member Enumeration Documentation

◆ State

enum class tinymodem::MFSKDecoder::State
strongprotected
Enumerator
SEARCH 
PREAMBLE 
DATA 

Constructor & Destructor Documentation

◆ MFSKDecoder() [1/2]

tinymodem::MFSKDecoder::MFSKDecoder ( )
default

◆ MFSKDecoder() [2/2]

tinymodem::MFSKDecoder::MFSKDecoder ( Print & out)
inline

Member Function Documentation

◆ acquire()

bool tinymodem::MFSKDecoder::acquire ( float coarse_error)
inlineprotected

Determines the symbol timing and the clock of the sender from the alternating preamble tones: the coarse clock error is known from the search

◆ addSample()

void tinymodem::MFSKDecoder::addSample ( float sample,
bool add_noise )
inlineprotected

◆ audioInfo()

audio_tools::AudioInfo tinymodem::MFSKDecoder::audioInfo ( )
inlineoverride

◆ begin() [1/2]

bool tinymodem::MFSKDecoder::begin ( )
inlineoverride

◆ begin() [2/2]

bool tinymodem::MFSKDecoder::begin ( MFSKConfig config)
inline

Starts the processing with the indicated configuration.

◆ config()

MFSKConfig & tinymodem::MFSKDecoder::config ( )
inline

The configuration which was provided in begin().

◆ dataSymbol()

void tinymodem::MFSKDecoder::dataSymbol ( int symbol,
float amplitude,
float second,
bool strong,
float symbol_nsamples )
inlineprotected

◆ defaultConfig()

MFSKConfig tinymodem::MFSKDecoder::defaultConfig ( )
inline

Provides a default configuration: mfsk16.

◆ discard()

void tinymodem::MFSKDecoder::discard ( size_t n)
inlineprotected

Removes the processed samples at the start of the buffer.

◆ end()

void tinymodem::MFSKDecoder::end ( )
inlineoverride

Processes the remaining samples and reports the end of the carrier.

◆ endOfCarrier()

void tinymodem::MFSKDecoder::endOfCarrier ( )
inlineprotected

◆ estimateClock()

bool tinymodem::MFSKDecoder::estimateClock ( int offset)
inlineprotected

Determines the exact frequency scale from the highest preamble tone and adapts the receiver to it: returns true if the receiver was retuned

◆ findTiming()

int tinymodem::MFSKDecoder::findTiming ( )
inlineprotected

Finds the offset where the preamble tones are best separated: returns -1 if there is no signal

◆ flush()

void tinymodem::MFSKDecoder::flush ( )
inlineoverridevirtual

Processes all buffered samples (e.g. at the end of the input).

Implements tinymodem::ModemDecoder.

◆ hasHighTone()

bool tinymodem::MFSKDecoder::hasHighTone ( float clock_error,
float low )
inlineprotected

Quick check before the (expensive) acquisition: the preamble alternates the lowest and the highest tone, so the highest tone must be present in one of the next symbols. This rejects a steady tone (e.g. a carrier at the lowest tone), which would otherwise start an acquisition at each step.

◆ isCarrier()

bool tinymodem::MFSKDecoder::isCarrier ( )
inlineoverridevirtual

true while a transmission is received

Implements tinymodem::ModemDecoder.

◆ isFinished()

bool tinymodem::MFSKDecoder::isFinished ( )
inlineoverridevirtual

true if the decoding was stopped (rx_one)

Implements tinymodem::ModemDecoder.

◆ magnitude() [1/2]

float tinymodem::MFSKDecoder::magnitude ( audio_tools::GoertzelDetector & det,
int start )
inlineprotected

Magnitude (amplitude) of the detector's frequency in the window.

◆ magnitude() [2/2]

float tinymodem::MFSKDecoder::magnitude ( int tone,
int start )
inlineprotected

Magnitude (amplitude) of the tone in the window starting at start.

◆ noise()

float tinymodem::MFSKDecoder::noise ( )
inlineprotected

uniform random value in the range -0.5 to 0.5

◆ operator bool()

tinymodem::MFSKDecoder::operator bool ( )
inlineoverride

◆ outputSymbol()

void tinymodem::MFSKDecoder::outputSymbol ( int symbol)
inlineprotected

◆ preambleSymbol()

void tinymodem::MFSKDecoder::preambleSymbol ( int symbol,
float amplitude,
bool strong )
inlineprotected

◆ resetState()

void tinymodem::MFSKDecoder::resetState ( )
inlineprotected

◆ searchStep()

bool tinymodem::MFSKDecoder::searchStep ( )
inlineprotected

Searches for the preamble at the start of the buffer.

◆ setAudioInfo()

void tinymodem::MFSKDecoder::setAudioInfo ( audio_tools::AudioInfo info)
inlineoverride

Defines the format of the input audio data.

◆ setupDetector()

void tinymodem::MFSKDecoder::setupDetector ( audio_tools::GoertzelDetector & det,
float freq )
inlineprotected

◆ startOfCarrier()

void tinymodem::MFSKDecoder::startOfCarrier ( )
inlineprotected

◆ startSearch()

void tinymodem::MFSKDecoder::startSearch ( )
inlineprotected

Back to the search for the next preamble.

◆ step()

bool tinymodem::MFSKDecoder::step ( )
inlineprotected

One processing step: returns false if more data is needed.

◆ symbolStep()

bool tinymodem::MFSKDecoder::symbolStep ( )
inlineprotected

Analyzes the next symbol.

◆ tune()

void tinymodem::MFSKDecoder::tune ( float new_scale)
inlineprotected

Adapts the tones and the symbol length to the clock of the sender: a sender with a faster sample rate results in lower frequencies (scale < 1.0) and longer symbols.

◆ windowAmplitude()

float tinymodem::MFSKDecoder::windowAmplitude ( int start)
inlineprotected

Amplitude of a sine with the same energy as the window.

◆ write()

size_t tinymodem::MFSKDecoder::write ( const uint8_t * data,
size_t len )
inlineoverride

Provide PCM data to the decoder.

Member Data Documentation

◆ acquire_step

int tinymodem::MFSKDecoder::acquire_step = 1
protected

◆ ACQUIRE_SYMBOLS

int tinymodem::MFSKDecoder::ACQUIRE_SYMBOLS = 4
staticconstexprprotected

number of preamble symbols which are used for the timing acquisition

◆ amplitude_total

float tinymodem::MFSKDecoder::amplitude_total = 0
protected

◆ bit_buffer

uint32_t tinymodem::MFSKDecoder::bit_buffer = 0
protected

◆ bit_count

int tinymodem::MFSKDecoder::bit_count = 0
protected

◆ bits_per_symbol

int tinymodem::MFSKDecoder::bits_per_symbol = 4
protected

◆ cfg

MFSKConfig tinymodem::MFSKDecoder::cfg
protected

◆ CLEAR_RATIO

float tinymodem::MFSKDecoder::CLEAR_RATIO = 1.5f
staticconstexprprotected

the tone of a preamble or sync symbol must be this much stronger than any other tone

◆ CLOCK_ERROR_STEP

float tinymodem::MFSKDecoder::CLOCK_ERROR_STEP = 0.001f
staticconstexprprotected

◆ confidence_total

float tinymodem::MFSKDecoder::confidence_total = 0
protected

◆ data_nsamples

double tinymodem::MFSKDecoder::data_nsamples = 0
protected

◆ delta

int tinymodem::MFSKDecoder::delta = 1
protected

◆ detectors

audio_tools::Vector<audio_tools::GoertzelDetector> tinymodem::MFSKDecoder::detectors
protected

◆ drift

float tinymodem::MFSKDecoder::drift = 0.0f
protected

learned timing drift in samples per symbol

◆ DRIFT_GAIN

float tinymodem::MFSKDecoder::DRIFT_GAIN = 0.05f
staticconstexprprotected

◆ estimate_clock

bool tinymodem::MFSKDecoder::estimate_clock = true
protected

true if the clock of the sender is determined from the tones

◆ has_pending

bool tinymodem::MFSKDecoder::has_pending = false
protected

◆ HIGH_TONE_LEVEL

float tinymodem::MFSKDecoder::HIGH_TONE_LEVEL = 0.25f
staticconstexprprotected

the highest preamble tone must have this part of the lowest tone's amplitude (a window may only partly overlap a symbol)

◆ hop

int tinymodem::MFSKDecoder::hop = 1
protected

◆ input

PcmInput tinymodem::MFSKDecoder::input
protected

◆ is_active

bool tinymodem::MFSKDecoder::is_active = false
protected

◆ is_finished

bool tinymodem::MFSKDecoder::is_finished = false
protected

◆ LOST_LEVEL

float tinymodem::MFSKDecoder::LOST_LEVEL = 0.4f
staticconstexprprotected

a symbol below this part of the tracked amplitude is lost

◆ magnitudes

audio_tools::Vector<float> tinymodem::MFSKDecoder::magnitudes
protected

◆ MAX_CLOCK_ERROR

float tinymodem::MFSKDecoder::MAX_CLOCK_ERROR = 0.03f
staticconstexprprotected

max difference of the sample rates of sender and receiver

◆ MAX_CONFIDENCE

float tinymodem::MFSKDecoder::MAX_CONFIDENCE = 100.0f
staticconstexprprotected

the confidence of a symbol is limited to this value

◆ MAX_PREAMBLE

int tinymodem::MFSKDecoder::MAX_PREAMBLE = 64
staticconstexprprotected

max number of preamble symbols before we give up

◆ MIN_CLOCK_GAIN

float tinymodem::MFSKDecoder::MIN_CLOCK_GAIN = 1.2f
staticconstexprprotected

a different clock must provide this much more energy

◆ ndata

unsigned tinymodem::MFSKDecoder::ndata = 0
protected

◆ needed

size_t tinymodem::MFSKDecoder::needed = 0
protected

◆ NEW_SIGNAL_LEVEL

float tinymodem::MFSKDecoder::NEW_SIGNAL_LEVEL = 4.0f
staticconstexprprotected

a preamble symbol above this multiple of the tracked amplitude starts a new search

◆ noise_seed

uint32_t tinymodem::MFSKDecoder::noise_seed = 1
protected

◆ nsamples

float tinymodem::MFSKDecoder::nsamples = 0
protected

◆ nsymbols

unsigned tinymodem::MFSKDecoder::nsymbols = 0
protected

◆ ntones

int tinymodem::MFSKDecoder::ntones = 16
protected

◆ nvalid

size_t tinymodem::MFSKDecoder::nvalid = 0
protected

◆ pending_symbol

int tinymodem::MFSKDecoder::pending_symbol = 0
protected

◆ pos

float tinymodem::MFSKDecoder::pos = 0
protected

◆ preamble_count

int tinymodem::MFSKDecoder::preamble_count = 0
protected

◆ samples

audio_tools::Vector<float> tinymodem::MFSKDecoder::samples
protected

◆ scale

float tinymodem::MFSKDecoder::scale = 1.0f
protected

frequency scale which results from the different sample rates

◆ search_detectors

audio_tools::Vector<audio_tools::GoertzelDetector> tinymodem::MFSKDecoder::search_detectors
protected

◆ SEARCH_STEP

float tinymodem::MFSKDecoder::SEARCH_STEP = 0.01f
staticconstexprprotected

◆ SEARCH_STEPS

int tinymodem::MFSKDecoder::SEARCH_STEPS = 3
staticconstexprprotected

the search checks the clock errors -3% to +3% in steps of 1%

◆ state

State tinymodem::MFSKDecoder::state = State::SEARCH
protected

◆ sync_stage

int tinymodem::MFSKDecoder::sync_stage = 0
protected

◆ TIMING_GAIN

float tinymodem::MFSKDecoder::TIMING_GAIN = 0.25f
staticconstexprprotected

gains of the timing loop

◆ track_amplitude

float tinymodem::MFSKDecoder::track_amplitude = 0
protected

◆ window

int tinymodem::MFSKDecoder::window = 0
protected

The documentation for this class was generated from the following file: