Merged remote-tracking branch 'upstream/master'

This commit is contained in:
furrtek
2015-11-18 22:01:48 +01:00
135 changed files with 8512 additions and 7734 deletions

View File

@@ -125,13 +125,23 @@ CSRC = $(PORTSRC) \
CPPSRC = main.cpp \
message_queue.cpp \
event_m4.cpp \
irq_ipc_m4.cpp \
gpdma.cpp \
baseband_dma.cpp \
portapack_shared_memory.cpp \
baseband_processor.cpp \
channel_decimator.cpp \
dsp_decimate.cpp \
dsp_demodulate.cpp \
matched_filter.cpp \
proc_am_audio.cpp \
proc_nfm_audio.cpp \
proc_wfm_audio.cpp \
proc_ais.cpp \
proc_wideband_spectrum.cpp \
proc_tpms.cpp \
dsp_squelch.cpp \
clock_recovery.cpp \
access_code_correlator.cpp \
packet_builder.cpp \
dsp_fft.cpp \
dsp_fir_taps.cpp \
@@ -142,6 +152,7 @@ CPPSRC = main.cpp \
audio_dma.cpp \
touch_dma.cpp \
../common/utility.cpp \
../common/chibios_cpp.cpp \
../common/debug.cpp \
../common/gcc.cpp
@@ -222,7 +233,8 @@ CPPWARN = -Wall -Wextra
# TODO: Switch -DCRT0_INIT_DATA depending on load from RAM or SPIFI?
# NOTE: _RANDOM_TCC to kill a GCC 4.9.3 error with std::max argument types
DDEFS = -DLPC43XX -DLPC43XX_M4 -D__NEWLIB__ -DHACKRF_ONE \
-DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0
-DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 \
-DGIT_REVISION=\"$(GIT_REVISION)\"
# List all default ASM defines here, like -D_DEBUG=1
DADEFS =

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "baseband_processor.hpp"
#include "portapack_shared_memory.hpp"
#include "dsp_fft.hpp"
#include "audio_dma.hpp"
#include "message.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
#include <cstddef>
#include <algorithm>
void BasebandProcessor::update_spectrum() {
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
if( channel_spectrum_request_update ) {
/* Decimated buffer is full. Compute spectrum. */
channel_spectrum_request_update = false;
fft_c_preswapped(channel_spectrum);
ChannelSpectrumMessage spectrum_message;
for(size_t i=0; i<spectrum_message.spectrum.db.size(); i++) {
const auto mag2 = magnitude_squared(channel_spectrum[i]);
const float db = complex16_mag_squared_to_dbv_norm(mag2);
constexpr float mag_scale = 5.0f;
const unsigned int v = (db * mag_scale) + 255.0f;
spectrum_message.spectrum.db[i] = std::max(0U, std::min(255U, v));
}
/* TODO: Rename .db -> .magnitude, or something more (less!) accurate. */
spectrum_message.spectrum.db_count = spectrum_message.spectrum.db.size();
spectrum_message.spectrum.sampling_rate = channel_spectrum_sampling_rate;
spectrum_message.spectrum.channel_filter_pass_frequency = channel_filter_pass_frequency;
spectrum_message.spectrum.channel_filter_stop_frequency = channel_filter_stop_frequency;
shared_memory.application_queue.push(spectrum_message);
}
}
void BasebandProcessor::feed_channel_stats(const buffer_c16_t channel) {
channel_stats.feed(
channel,
[this](const ChannelStatistics statistics) {
this->post_channel_stats_message(statistics);
}
);
}
void BasebandProcessor::feed_channel_spectrum(
const buffer_c16_t channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
) {
channel_filter_pass_frequency = filter_pass_frequency;
channel_filter_stop_frequency = filter_stop_frequency;
channel_spectrum_decimator.feed(
channel,
[this](const buffer_c16_t data) {
this->post_channel_spectrum_message(data);
}
);
}
void BasebandProcessor::fill_audio_buffer(const buffer_s16_t audio) {
auto audio_buffer = audio::dma::tx_empty_buffer();;
for(size_t i=0; i<audio_buffer.count; i++) {
audio_buffer.p[i].left = audio_buffer.p[i].right = audio.p[i];
}
i2s::i2s0::tx_unmute();
feed_audio_stats(audio);
}
void BasebandProcessor::post_channel_stats_message(const ChannelStatistics statistics) {
channel_stats_message.statistics = statistics;
shared_memory.application_queue.push(channel_stats_message);
}
void BasebandProcessor::post_channel_spectrum_message(const buffer_c16_t data) {
if( !channel_spectrum_request_update ) {
fft_swap(data, channel_spectrum);
channel_spectrum_sampling_rate = data.sampling_rate;
channel_spectrum_request_update = true;
events_flag(EVT_MASK_SPECTRUM);
}
}
void BasebandProcessor::feed_audio_stats(const buffer_s16_t audio) {
audio_stats.feed(
audio,
[this](const AudioStatistics statistics) {
this->post_audio_stats_message(statistics);
}
);
}
void BasebandProcessor::post_audio_stats_message(const AudioStatistics statistics) {
audio_stats_message.statistics = statistics;
shared_memory.application_queue.push(audio_stats_message);
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BASEBAND_PROCESSOR_H__
#define __BASEBAND_PROCESSOR_H__
#include "dsp_types.hpp"
#include "complex.hpp"
#include "block_decimator.hpp"
#include "channel_stats_collector.hpp"
#include "audio_stats_collector.hpp"
#include <array>
#include <cstdint>
#include <complex>
class BasebandProcessor {
public:
virtual ~BasebandProcessor() = default;
virtual void execute(buffer_c8_t buffer) = 0;
void update_spectrum();
protected:
void feed_channel_stats(const buffer_c16_t channel);
void feed_channel_spectrum(
const buffer_c16_t channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
);
void fill_audio_buffer(const buffer_s16_t audio);
volatile bool channel_spectrum_request_update { false };
std::array<std::complex<float>, 256> channel_spectrum;
uint32_t channel_spectrum_sampling_rate { 0 };
uint32_t channel_filter_pass_frequency { 0 };
uint32_t channel_filter_stop_frequency { 0 };
private:
BlockDecimator<256> channel_spectrum_decimator { 4 };
ChannelStatsCollector channel_stats;
ChannelStatisticsMessage channel_stats_message;
AudioStatsCollector audio_stats;
AudioStatisticsMessage audio_stats_message;
void post_channel_stats_message(const ChannelStatistics statistics);
void post_channel_spectrum_message(const buffer_c16_t data);
void feed_audio_stats(const buffer_s16_t audio);
void post_audio_stats_message(const AudioStatistics statistics);
};
#endif/*__BASEBAND_PROCESSOR_H__*/

View File

@@ -26,13 +26,25 @@
#include "dsp_types.hpp"
#include "message.hpp"
#include "utility.hpp"
#include "utility_m4.hpp"
#include <cstdint>
#include <cstddef>
class BasebandStatsCollector {
public:
BasebandStatsCollector(
const Thread* const thread_idle,
const Thread* const thread_main,
const Thread* const thread_rssi,
const Thread* const thread_baseband
) : thread_idle { thread_idle },
thread_main { thread_main },
thread_rssi { thread_rssi },
thread_baseband { thread_baseband }
{
}
template<typename Callback>
void process(buffer_c8_t buffer, Callback callback) {
samples += buffer.count;
@@ -40,11 +52,21 @@ public:
const size_t report_samples = buffer.sampling_rate * report_interval;
const auto report_delta = samples - samples_last_report;
if( report_delta >= report_samples ) {
const auto idle_ticks = chSysGetIdleThread()->total_ticks;
BasebandStatistics statistics;
const auto idle_ticks = thread_idle->total_ticks;
statistics.idle_ticks = (idle_ticks - last_idle_ticks);
last_idle_ticks = idle_ticks;
const auto baseband_ticks = chThdSelf()->total_ticks;
const auto main_ticks = thread_main->total_ticks;
statistics.main_ticks = (main_ticks - last_main_ticks);
last_main_ticks = main_ticks;
const auto rssi_ticks = thread_rssi->total_ticks;
statistics.rssi_ticks = (rssi_ticks - last_rssi_ticks);
last_rssi_ticks = rssi_ticks;
const auto baseband_ticks = thread_baseband->total_ticks;
statistics.baseband_ticks = (baseband_ticks - last_baseband_ticks);
last_baseband_ticks = baseband_ticks;
@@ -59,10 +81,15 @@ public:
private:
static constexpr float report_interval { 1.0f };
BasebandStatistics statistics;
size_t samples { 0 };
size_t samples_last_report { 0 };
const Thread* const thread_idle;
uint32_t last_idle_ticks { 0 };
const Thread* const thread_main;
uint32_t last_main_ticks { 0 };
const Thread* const thread_rssi;
uint32_t last_rssi_ticks { 0 };
const Thread* const thread_baseband;
uint32_t last_baseband_ticks { 0 };
};

View File

@@ -24,7 +24,9 @@
#include <cstdint>
#include <cstddef>
#include <array>
#include "dsp_types.hpp"
#include "complex.hpp"
template<size_t N>

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "channel_decimator.hpp"
buffer_c16_t ChannelDecimator::execute_decimation(buffer_c8_t buffer) {
const buffer_c16_t work_baseband_buffer {
work_baseband.data(),
work_baseband.size()
};
const buffer_s16_t work_audio_buffer {
(int16_t*)work_baseband.data(),
sizeof(work_baseband) / sizeof(int16_t)
};
/* 3.072MHz complex<int8_t>[2048], [-128, 127]
* -> Shift by -fs/4
* -> 3rd order CIC: -0.1dB @ 0.028fs, -1dB @ 0.088fs, -60dB @ 0.468fs
* -0.1dB @ 86kHz, -1dB @ 270kHz, -60dB @ 1.44MHz
* -> gain of 256
* -> decimation by 2
* -> 1.544MHz complex<int16_t>[1024], [-32768, 32512] */
const auto stage_0_out = translate.execute(buffer, work_baseband_buffer);
//if( fs_over_4_downconvert ) {
// // TODO:
//} else {
// Won't work until cic_0 will accept input type of buffer_c8_t.
// stage_0_out = cic_0.execute(buffer, work_baseband_buffer);
//}
/* 1.536MHz complex<int16_t>[1024], [-32768, 32512]
* -> 3rd order CIC: -0.1dB @ 0.028fs, -1dB @ 0.088fs, -60dB @ 0.468fs
* -0.1dB @ 43kHz, -1dB @ 136kHz, -60dB @ 723kHz
* -> gain of 8
* -> decimation by 2
* -> 768kHz complex<int16_t>[512], [-8192, 8128] */
auto cic_1_out = cic_1.execute(stage_0_out, work_baseband_buffer);
if( decimation_factor == DecimationFactor::By4 ) {
return cic_1_out;
}
/* 768kHz complex<int16_t>[512], [-32768, 32512]
* -> 3rd order CIC decimation by 2, gain of 1
* -> 384kHz complex<int16_t>[256], [-32768, 32512] */
auto cic_2_out = cic_2.execute(cic_1_out, work_baseband_buffer);
if( decimation_factor == DecimationFactor::By8 ) {
return cic_2_out;
}
/* 384kHz complex<int16_t>[256], [-32768, 32512]
* -> 3rd order CIC decimation by 2, gain of 1
* -> 192kHz complex<int16_t>[128], [-32768, 32512] */
auto cic_3_out = cic_3.execute(cic_2_out, work_baseband_buffer);
if( decimation_factor == DecimationFactor::By16 ) {
return cic_3_out;
}
/* 192kHz complex<int16_t>[128], [-32768, 32512]
* -> 3rd order CIC decimation by 2, gain of 1
* -> 96kHz complex<int16_t>[64], [-32768, 32512] */
auto cic_4_out = cic_4.execute(cic_3_out, work_baseband_buffer);
return cic_4_out;
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CHANNEL_DECIMATOR_H__
#define __CHANNEL_DECIMATOR_H__
#include "buffer.hpp"
#include "complex.hpp"
#include "dsp_decimate.hpp"
#include <array>
class ChannelDecimator {
public:
enum class DecimationFactor {
By4,
By8,
By16,
By32,
};
constexpr ChannelDecimator(
) : decimation_factor { DecimationFactor::By32 }
{
}
constexpr ChannelDecimator(
const DecimationFactor decimation_factor
) : decimation_factor { decimation_factor }
{
}
void set_decimation_factor(const DecimationFactor f) {
decimation_factor = f;
}
buffer_c16_t execute(buffer_c8_t buffer) {
auto decimated = execute_decimation(buffer);
return decimated;
}
private:
std::array<complex16_t, 1024> work_baseband;
//const bool fs_over_4_downconvert = true;
dsp::decimate::TranslateByFSOver4AndDecimateBy2CIC3 translate;
//dsp::decimate::DecimateBy2CIC3 cic_0;
dsp::decimate::DecimateBy2CIC3 cic_1;
dsp::decimate::DecimateBy2CIC3 cic_2;
dsp::decimate::DecimateBy2CIC3 cic_3;
dsp::decimate::DecimateBy2CIC3 cic_4;
DecimationFactor decimation_factor;
buffer_c16_t execute_decimation(buffer_c8_t buffer);
};
#endif/*__CHANNEL_DECIMATOR_H__*/

View File

@@ -29,6 +29,8 @@
#include <cstdint>
#include <cstddef>
#include <hal.h>
class ChannelStatsCollector {
public:
template<typename Callback>
@@ -47,13 +49,8 @@ public:
if( count >= samples_per_update ) {
const float max_squared_f = max_squared;
const float max_db_f = complex16_mag_squared_to_dbv_norm(max_squared_f);
const int32_t max_db = max_db_f;
const ChannelStatistics statistics {
.max_db = max_db,
.count = count,
};
callback(statistics);
const int32_t max_db = complex16_mag_squared_to_dbv_norm(max_squared_f);
callback({ max_db, count });
max_squared = 0;
count = 0;

View File

@@ -20,12 +20,3 @@
*/
#include "clock_recovery.hpp"
void ClockRecovery::configure(
const uint32_t symbol_rate,
const uint32_t sampling_rate
) {
phase_increment = phase_increment_u32(
fractional_symbol_rate(symbol_rate, sampling_rate)
);
}

View File

@@ -22,65 +22,157 @@
#ifndef __CLOCK_RECOVERY_H__
#define __CLOCK_RECOVERY_H__
#include <cstdint>
#include <cstddef>
#include <array>
#include <functional>
class ClockRecovery {
#include "linear_resampler.hpp"
namespace clock_recovery {
class GardnerTimingErrorDetector {
public:
void configure(
const uint32_t symbol_rate,
const uint32_t sampling_rate
);
static constexpr size_t samples_per_symbol { 2 };
/*
Expects retimed samples at a rate of twice the expected symbol rate.
Calculates timing error, sends symbol and error to handler.
*/
template<typename SymbolHandler>
void execute(
void operator()(
const float in,
SymbolHandler symbol_handler
) {
const bool phase_0 = (phase_last >> 31) & (!(phase >> 31));
const bool phase_180 = (!(phase_last >> 31)) & (phase >> 31);
phase_last = phase;
phase += phase_increment + phase_adjustment;
/* NOTE: Algorithm is sensitive to input magnitude. Timing error value
* will scale proportionally. Best practice is to use error sign only.
*/
t[2] = t[1];
t[1] = t[0];
t[0] = in;
if( phase_0 || phase_180 ) {
t2 = t1;
t1 = t0;
t0 = in;
if( symbol_phase == 0 ) {
const auto symbol = t[0];
const float lateness = (t[0] - t[2]) * t[1];
symbol_handler(symbol, lateness);
}
if( phase_0 ) {
symbol_handler(t0);
const float error = (t0 - t2) * t1;
// + error == late == decrease/slow phase
// - error == early == increase/fast phase
error_filtered = 0.75f * error_filtered + 0.25f * error;
// Correct phase (don't change frequency!)
phase_adjustment = -phase_increment * error_filtered / 200.0f;
}
symbol_phase = (symbol_phase + 1) % samples_per_symbol;
}
private:
uint32_t phase { 0 };
uint32_t phase_last { 0 };
uint32_t phase_adjustment { 0 };
uint32_t phase_increment { 0 };
float t0 { 0 };
float t1 { 0 };
float t2 { 0 };
float error_filtered { 0 };
std::array<float, 3> t { { 0.0f, 0.0f, 0.0f } };
size_t symbol_phase { 0 };
};
static constexpr float fractional_symbol_rate(
const uint32_t symbol_rate,
const uint32_t sampling_rate
) {
return float(symbol_rate) / float(sampling_rate);
class LinearErrorFilter {
public:
LinearErrorFilter(
const float filter_alpha = 0.95f,
const float error_weight = -1.0f
) : filter_alpha { filter_alpha },
error_weight { error_weight }
{
}
static constexpr uint32_t phase_increment_u32(const float fractional_symbol_rate) {
return 4294967296.0f * fractional_symbol_rate;
float operator()(
const float error
) {
error_filtered = filter_alpha * error_filtered + (1.0f - filter_alpha) * error;
return error_filtered * error_weight;
}
private:
const float filter_alpha;
const float error_weight;
float error_filtered { 0.0f };
};
class FixedErrorFilter {
public:
FixedErrorFilter(
) {
}
FixedErrorFilter(
const float weight
) : weight_ { weight }
{
}
float operator()(
const float lateness
) const {
return (lateness < 0.0f) ? weight() : -weight();
}
float weight() const {
return weight_;
}
private:
float weight_ { 1.0f / 16.0f };
};
template<typename ErrorFilter>
class ClockRecovery {
public:
ClockRecovery(
const float sampling_rate,
const float symbol_rate,
ErrorFilter error_filter,
std::function<void(const float)> symbol_handler
) : symbol_handler { symbol_handler }
{
configure(sampling_rate, symbol_rate, error_filter);
}
ClockRecovery(
std::function<void(const float)> symbol_handler
) : symbol_handler { symbol_handler }
{
}
void configure(
const float sampling_rate,
const float symbol_rate,
ErrorFilter error_filter
) {
resampler.configure(sampling_rate, symbol_rate * timing_error_detector.samples_per_symbol);
error_filter = error_filter;
}
void operator()(
const float baseband_sample
) {
resampler(baseband_sample,
[this](const float interpolated_sample) {
this->resampler_callback(interpolated_sample);
}
);
}
private:
dsp::interpolation::LinearResampler resampler;
GardnerTimingErrorDetector timing_error_detector;
ErrorFilter error_filter;
std::function<void(const float)> symbol_handler;
void resampler_callback(const float interpolated_sample) {
timing_error_detector(interpolated_sample,
[this](const float symbol, const float lateness) {
this->symbol_callback(symbol, lateness);
}
);
}
void symbol_callback(const float symbol, const float lateness) {
symbol_handler(symbol);
const float adjustment = error_filter(lateness);
resampler.advance(adjustment);
}
};
} /* namespace clock_recovery */
#endif/*__CLOCK_RECOVERY_H__*/

View File

@@ -196,120 +196,38 @@ buffer_s16_t FIR64AndDecimateBy2Real::execute(
return { dst.p, src.count / 2, src.sampling_rate / 2 };
}
#if 0
size_t fir_and_decimate_by_2_complex(
const complex16_t* const src_start,
const size_t src_count,
complex16_t* const dst_start,
complex16_t* const z,
const complex16_t* const taps,
const size_t taps_count
buffer_c16_t FIRAndDecimateComplex::execute(
buffer_c16_t src,
buffer_c16_t dst
) {
/* int16_t input (sample count "n" must be multiple of 4)
* -> int16_t output, decimated by 2.
/* int16_t input (sample count "n" must be multiple of decimation_factor)
* -> int16_t output, decimated by decimation_factor.
* taps are normalized to 1 << 16 == 1.0.
*/
auto src_p = src_start;
const auto src_end = &src_start[src_count];
auto dst_p = dst_start;
const auto output_sampling_rate = src.sampling_rate / decimation_factor_;
const size_t output_samples = src.count / decimation_factor_;
sample_t* dst_p = dst.p;
const buffer_c16_t result { dst.p, output_samples, output_sampling_rate };
auto z_p = &z[0];
const sample_t* src_p = src.p;
size_t outer_count = output_samples;
while(outer_count > 0) {
/* Put new samples into delay buffer */
auto z_new_p = &samples_[taps_count_ - decimation_factor_];
for(size_t i=0; i<decimation_factor_; i++) {
*__SIMD32(z_new_p)++ = *__SIMD32(src_p)++;
}
while(src_p < src_end) {
/* Put two new samples into delay buffer */
*__SIMD32(z_p)++ = *__SIMD32(src_p)++;
*__SIMD32(z_p)++ = *__SIMD32(src_p)++;
size_t loop_count = taps_count_ / 8;
auto t_p = &taps_reversed_[0];
auto z_p = &samples_[0];
int64_t t_real = 0;
int64_t t_imag = 0;
auto t_p = &taps[0];
const auto z_end = &z[taps_count];
while(z_p < z_end) {
const auto tap0 = *__SIMD32(t_p)++;
const auto sample0 = *__SIMD32(z_p)++;
t_real = __SMLSLD(sample0, tap0, t_real);
t_imag = __SMLALDX(sample0, tap0, t_imag);
const auto tap1 = *__SIMD32(t_p)++;
const auto sample1 = *__SIMD32(z_p)++;
t_real = __SMLSLD(sample1, tap1, t_real);
t_imag = __SMLALDX(sample1, tap1, t_imag);
}
z_p = &z[0];
const auto t_end = &taps[taps_count];
while(t_p < t_end) {
const auto tap0 = *__SIMD32(t_p)++;
const auto sample0 = *__SIMD32(z_p)++;
t_real = __SMLSLD(sample0, tap0, t_real);
t_imag = __SMLALDX(sample0, tap0, t_imag);
const auto tap1 = *__SIMD32(t_p)++;
const auto sample1 = *__SIMD32(z_p)++;
t_real = __SMLSLD(sample1, tap1, t_real);
t_imag = __SMLALDX(sample1, tap1, t_imag);
}
if( z_p == z_end ) {
z_p = &z[0];
}
/* TODO: No rounding taking place here, so might be adding a bit of
* noise. Enough to be significant?
*/
*__SIMD32(dst_p)++ = __PKHBT(
t_real / 131072,
t_imag / 131072,
16
);
/*
*__SIMD32(dst_p)++ = __PKHBT(
__SSAT((t_real / 131072), 16),
__SSAT((t_imag / 131072), 16),
16
);
*/
}
return src_count / 2;
}
#endif
size_t fir_and_decimate_by_2_complex_fast(
const complex16_t* const src_start,
const size_t src_count,
complex16_t* const dst_start,
complex16_t* const z,
const complex16_t* const taps,
const size_t taps_count
) {
/* int16_t input (sample count "n" must be multiple of 4)
* -> int16_t output, decimated by 2.
* taps are normalized to 1 << 16 == 1.0.
*/
auto src_p = src_start;
auto dst_p = dst_start;
auto z_new_p = &z[0];
auto t_p = &taps[taps_count * 2];
while(src_p < &src_start[src_count]) {
/* Put two new samples into delay buffer */
*__SIMD32(z_new_p)++ = *__SIMD32(src_p)++;
*__SIMD32(z_new_p)++ = *__SIMD32(src_p)++;
t_p -= (taps_count + 2);
if( z_new_p == &z[taps_count] ) {
z_new_p = &z[0];
t_p = &taps[taps_count];
}
int64_t t_real = 0;
int64_t t_imag = 0;
auto z_p = &z[0];
while(z_p < &z[taps_count]) {
while(loop_count > 0) {
const auto tap0 = *__SIMD32(t_p)++;
const auto sample0 = *__SIMD32(z_p)++;
const auto tap1 = *__SIMD32(t_p)++;
@@ -345,6 +263,8 @@ size_t fir_and_decimate_by_2_complex_fast(
t_imag = __SMLALDX(sample6, tap6, t_imag);
t_real = __SMLSLD(sample7, tap7, t_real);
t_imag = __SMLALDX(sample7, tap7, t_imag);
loop_count--;
}
/* TODO: Re-evaluate whether saturation is performed, normalization,
@@ -359,9 +279,32 @@ size_t fir_and_decimate_by_2_complex_fast(
i_sat,
16
);
/* Shift sample buffer left/down by decimation factor. */
const size_t unroll_factor = 4;
size_t shift_count = (taps_count_ - decimation_factor_) / unroll_factor;
sample_t* t = &samples_[0];
const sample_t* s = &samples_[decimation_factor_];
while(shift_count > 0) {
*__SIMD32(t)++ = *__SIMD32(s)++;
*__SIMD32(t)++ = *__SIMD32(s)++;
*__SIMD32(t)++ = *__SIMD32(s)++;
*__SIMD32(t)++ = *__SIMD32(s)++;
shift_count--;
}
shift_count = (taps_count_ - decimation_factor_) % unroll_factor;
while(shift_count > 0) {
*(t++) = *(s++);
shift_count--;
}
outer_count--;
}
return src_count / 2;
return result;
}
buffer_s16_t DecimateBy2CIC4Real::execute(

View File

@@ -24,6 +24,10 @@
#include <cstdint>
#include <array>
#include <memory>
#include <algorithm>
#include "utility.hpp"
#include "dsp_types.hpp"
@@ -74,50 +78,46 @@ private:
const std::array<int16_t, taps_count>& taps;
};
size_t fir_and_decimate_by_2_complex(
const complex16_t* const src_start,
const size_t src_count,
complex16_t* const dst_start,
complex16_t* const z,
const complex16_t* const taps,
const size_t taps_count
);
size_t fir_and_decimate_by_2_complex_fast(
const complex16_t* const src_start,
const size_t src_count,
complex16_t* const dst_start,
complex16_t* const z,
const complex16_t* const taps,
const size_t taps_count
);
template<size_t taps_count>
class FIRAndDecimateBy2Complex {
class FIRAndDecimateComplex {
public:
using sample_t = complex16_t;
using tap_t = complex16_t;
using taps_t = tap_t[];
/* NOTE! Current code makes an assumption that block of samples to be
* processed will be a multiple of the taps_count.
*/
FIRAndDecimateBy2Complex(
const std::array<int16_t, taps_count>& real_taps
FIRAndDecimateComplex(
) : taps_count_ { 0 },
decimation_factor_ { 1 }
{
}
template<typename T>
void configure(
const T& taps,
const size_t decimation_factor
) {
for(size_t i=0; i<taps_count; i++) {
taps[ i] = real_taps[i];
taps[taps_count + i] = real_taps[i];
}
samples_ = std::make_unique<samples_t>(taps.size());
taps_reversed_ = std::make_unique<taps_t>(taps.size());
taps_count_ = taps.size();
decimation_factor_ = decimation_factor;
std::reverse_copy(taps.cbegin(), taps.cend(), &taps_reversed_[0]);
}
buffer_c16_t execute(
buffer_c16_t src,
buffer_c16_t dst
) {
const auto dst_count = fir_and_decimate_by_2_complex_fast(src.p, src.count, dst.p, z.data(), taps.data(), taps_count);
return { dst.p, dst_count, src.sampling_rate / 2 };
}
);
private:
std::array<complex16_t, taps_count * 2> taps;
std::array<complex16_t, taps_count> z;
using samples_t = sample_t[];
std::unique_ptr<samples_t> samples_;
std::unique_ptr<taps_t> taps_reversed_;
size_t taps_count_;
size_t decimation_factor_;
};
class DecimateBy2CIC4Real {

View File

@@ -23,6 +23,7 @@
#include "complex.hpp"
#include "fxpt_atan2.hpp"
#include "utility_m4.hpp"
#include <hal.h>

View File

@@ -55,9 +55,13 @@ public:
buffer_s16_t dst
);
void configure(const float sampling_rate, const float deviation_hz) {
k = static_cast<float>(32767.0f / (2.0 * pi * deviation_hz / sampling_rate));
}
private:
complex16_t::rep_type z_;
const float k;
float k;
};
} /* namespace demodulate */

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_IIR_CONFIG_H__
#define __DSP_IIR_CONFIG_H__
#include "dsp_iir.hpp"
constexpr iir_biquad_config_t audio_hpf_config {
{ 0.93346032f, -1.86687724f, 0.93346032f },
{ 1.0f , -1.97730264f, 0.97773668f }
};
constexpr iir_biquad_config_t non_audio_hpf_config {
{ 0.51891061f, -0.95714180f, 0.51891061f },
{ 1.0f , -0.79878302f, 0.43960231f }
};
#endif/*__DSP_IIR_CONFIG_H__*/

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_squelch.hpp"
#include <cstdint>
#include <array>
bool FMSquelch::execute(buffer_s16_t audio) {
// TODO: No hard-coded array size.
std::array<int16_t, N> squelch_energy_buffer;
const buffer_s16_t squelch_energy {
squelch_energy_buffer.data(),
squelch_energy_buffer.size()
};
non_audio_hpf.execute(audio, squelch_energy);
uint64_t max_squared = 0;
for(const auto sample : squelch_energy_buffer) {
const uint64_t sample_squared = sample * sample;
if( sample_squared > max_squared ) {
max_squared = sample_squared;
}
}
return (max_squared < (threshold * threshold));
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_SQUELCH_H__
#define __DSP_SQUELCH_H__
#include "buffer.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
#include <cstdint>
#include <cstddef>
class FMSquelch {
public:
bool execute(buffer_s16_t audio);
private:
static constexpr size_t N = 32;
static constexpr int16_t threshold = 3072;
// nyquist = 48000 / 2.0
// scipy.signal.iirdesign(wp=8000 / nyquist, ws= 4000 / nyquist, gpass=1, gstop=18, ftype='ellip')
IIRBiquadFilter non_audio_hpf { non_audio_hpf_config };
};
#endif/*__DSP_SQUELCH_H__*/

View File

@@ -19,31 +19,36 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __ACCESS_CODE_CORRELATOR_H__
#define __ACCESS_CODE_CORRELATOR_H__
#include "irq_ipc_m4.hpp"
#include <cstdint>
#include <cstddef>
#include "ch.h"
#include "hal.h"
class AccessCodeCorrelator {
public:
void configure(
const uint32_t new_code,
const size_t new_code_length,
const size_t new_maximum_hamming_distance
);
#include "event_m4.hpp"
bool execute(const uint_fast8_t in);
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
private:
uint32_t code { 0 };
uint32_t mask { 0 };
uint32_t history { 0 };
size_t maximum_hamming_distance { 0 };
void m0apptxevent_interrupt_enable() {
nvicEnableVector(M0CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M0APPTXEVENT_IRQ_PRIORITY));
}
static constexpr uint32_t mask_value(const size_t n) {
return static_cast<uint32_t>((1ULL << n) - 1ULL);
}
};
void m0apptxevent_interrupt_disable() {
nvicDisableVector(M0CORE_IRQn);
}
#endif/*__ACCESS_CODE_CORRELATOR_H__*/
extern "C" {
CH_IRQ_HANDLER(MAPP_IRQHandler) {
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
events_flag_isr(EVT_MASK_BASEBAND);
chSysUnlockFromIsr();
creg::m0apptxevent::clear();
CH_IRQ_EPILOGUE();
}
}

View File

@@ -19,26 +19,10 @@
* Boston, MA 02110-1301, USA.
*/
#include "access_code_correlator.hpp"
#ifndef __IRQ_IPC_M4_H__
#define __IRQ_IPC_M4_H__
void AccessCodeCorrelator::configure(
const uint32_t new_code,
const size_t new_code_length,
const size_t new_maximum_hamming_distance
) {
if( new_code_length <= 32 ) {
code = new_code;
mask = mask_value(new_code_length);
maximum_hamming_distance = new_maximum_hamming_distance;
}
}
void m0apptxevent_interrupt_enable();
void m0apptxevent_interrupt_disable();
bool AccessCodeCorrelator::execute(
const uint_fast8_t in
) {
history = (history << 1) | (in & 1);
const auto delta_bits = (history ^ code) & mask;
//const size_t count = __builtin_popcountll(delta_bits);
const size_t count = __builtin_popcountl(delta_bits);
return (count <= maximum_hamming_distance);
}
#endif/*__IRQ_IPC_M4_H__*/

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __LINEAR_RESAMPLER_H__
#define __LINEAR_RESAMPLER_H__
namespace dsp {
namespace interpolation {
class LinearResampler {
public:
void configure(
const float input_rate,
const float output_rate
) {
phase_increment = calculate_increment(input_rate, output_rate);
}
template<typename InterpolatedSampleHandler>
void operator()(
const float sample,
InterpolatedSampleHandler interpolated_sample_handler
) {
const float sample_delta = sample - last_sample;
while( phase < 1.0f ) {
const float interpolated_value = last_sample + phase * sample_delta;
interpolated_sample_handler(interpolated_value);
phase += phase_increment;
}
last_sample = sample;
phase -= 1.0f;
}
void advance(const float fraction) {
phase += (fraction * phase_increment);
}
private:
float last_sample { 0.0f };
float phase { 0.0f };
float phase_increment { 0.0f };
static constexpr float calculate_increment(const float input_rate, const float output_rate) {
return input_rate / output_rate;
}
};
} /* namespace interpolation */
} /* namespace dsp */
#endif/*__LINEAR_RESAMPLER_H__*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "matched_filter.hpp"
namespace dsp {
namespace matched_filter {
bool MatchedFilter::execute_once(
const sample_t input
) {
samples_[taps_count_ - decimation_factor_ + decimation_phase] = input;
advance_decimation_phase();
if( is_new_decimation_cycle() ) {
float sr_tr = 0.0f;
float si_tr = 0.0f;
float si_ti = 0.0f;
float sr_ti = 0.0f;
for(size_t n=0; n<taps_count_; n++) {
const auto sample = samples_[n];
const auto tap = taps_reversed_[n];
sr_tr += sample.real() * tap.real();
si_ti += sample.imag() * tap.imag();
si_tr += sample.imag() * tap.real();
sr_ti += sample.real() * tap.imag();
}
// N: complex multiple of samples and taps (conjugate, tap.i negated).
// P: complex multiply of samples and taps.
const auto r_n = sr_tr + si_ti;
const auto r_p = sr_tr - si_ti;
const auto i_n = si_tr - sr_ti;
const auto i_p = si_tr + sr_ti;
const auto mag_n = std::sqrt(r_n * r_n + i_n * i_n);
const auto mag_p = std::sqrt(r_p * r_p + i_p * i_p);
const auto diff = mag_p - mag_n;
output = diff;
shift_by_decimation_factor();
return true;
} else {
return false;
}
}
void MatchedFilter::shift_by_decimation_factor() {
const sample_t* s = &samples_[decimation_factor_];
sample_t* t = &samples_[0];
const size_t unroll_factor = 4;
size_t shift_count = (taps_count_ - decimation_factor_) / unroll_factor;
while(shift_count > 0) {
*t++ = *s++;
*t++ = *s++;
*t++ = *s++;
*t++ = *s++;
shift_count--;
}
shift_count = (taps_count_ - decimation_factor_) % unroll_factor;
while(shift_count > 0) {
*t++ = *s++;
shift_count--;
}
}
} /* namespace matched_filter */
} /* namespace dsp */

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MATCHED_FILTER_H__
#define __MATCHED_FILTER_H__
#include "utility.hpp"
#include <cstddef>
#include <complex>
#include <array>
#include <memory>
#include <algorithm>
#include <numeric>
namespace dsp {
namespace matched_filter {
// This filter contains "magic" (optimizations) that expect the taps to
// combine a low-pass filter with a complex sinusoid that performs shifting of
// the input signal to 0Hz/DC. This also means that the taps length must be
// a multiple of the complex sinusoid period.
class MatchedFilter {
public:
using sample_t = std::complex<float>;
using tap_t = std::complex<float>;
using taps_t = tap_t[];
template<class T>
MatchedFilter(
const T& taps,
size_t decimation_factor = 1
) {
configure(taps, decimation_factor);
}
template<class T>
void configure(
const T& taps,
size_t decimation_factor
) {
samples_ = std::make_unique<samples_t>(taps.size());
taps_reversed_ = std::make_unique<taps_t>(taps.size());
taps_count_ = taps.size();
decimation_factor_ = decimation_factor;
std::reverse_copy(taps.cbegin(), taps.cend(), &taps_reversed_[0]);
}
bool execute_once(const sample_t input);
float get_output() const {
return output;
}
private:
using samples_t = sample_t[];
std::unique_ptr<samples_t> samples_;
std::unique_ptr<taps_t> taps_reversed_;
size_t taps_count_ { 0 };
size_t decimation_factor_ { 1 };
size_t decimation_phase { 0 };
float output;
void shift_by_decimation_factor();
void advance_decimation_phase() {
decimation_phase = (decimation_phase + 1) % decimation_factor_;
}
bool is_new_decimation_cycle() const {
return (decimation_phase == 0);
}
};
} /* namespace matched_filter */
} /* namespace dsp */
#endif/*__MATCHED_FILTER_H__*/

View File

@@ -41,3 +41,7 @@
//#define LPC_ADC1_IRQ_PRIORITY 4
#define LPC43XX_M0APPTXEVENT_IRQ_PRIORITY 4
/* M4 is initialized by M0, which has already started PLL1 */
#define LPC43XX_M4_CLK 200000000
#define LPC43XX_M4_CLK_SRC 0x09

View File

@@ -20,15 +20,3 @@
*/
#include "packet_builder.hpp"
void PacketBuilder::configure(size_t new_payload_length) {
if( new_payload_length <= payload.size() ) {
payload_length = new_payload_length;
reset_state();
}
}
void PacketBuilder::reset_state() {
bits_received = 0;
state = State::AccessCodeSearch;
}

View File

@@ -25,30 +25,62 @@
#include <cstdint>
#include <cstddef>
#include <bitset>
#include <functional>
#include "bit_pattern.hpp"
template<typename PreambleMatcher, typename UnstuffMatcher, typename EndMatcher>
class PacketBuilder {
public:
void configure(size_t new_payload_length);
using PayloadType = std::bitset<1024>;
using PayloadHandlerFunc = std::function<void(const PayloadType& payload, const size_t bits_received)>;
template<typename PayloadHandler>
void execute(
const uint_fast8_t symbol,
const bool access_code_found,
PayloadHandler payload_handler
PacketBuilder(
const PreambleMatcher preamble_matcher,
const UnstuffMatcher unstuff_matcher,
const EndMatcher end_matcher,
const PayloadHandlerFunc payload_handler
) : payload_handler { payload_handler },
preamble(preamble_matcher),
unstuff(unstuff_matcher),
end(end_matcher)
{
}
void configure(
const PreambleMatcher preamble_matcher,
const UnstuffMatcher unstuff_matcher
) {
preamble = preamble_matcher;
unstuff = unstuff_matcher;
reset_state();
}
void execute(
const uint_fast8_t symbol
) {
bit_history.add(symbol);
switch(state) {
case State::AccessCodeSearch:
if( access_code_found ) {
case State::Preamble:
if( preamble(bit_history, bits_received) ) {
state = State::Payload;
}
break;
case State::Payload:
if( bits_received < payload_length ) {
if( !unstuff(bit_history, bits_received) ) {
payload[bits_received++] = symbol;
} else {
}
if( end(bit_history, bits_received) ) {
payload_handler(payload, bits_received);
reset_state();
} else {
if( packet_truncated() ) {
reset_state();
}
}
break;
@@ -60,16 +92,29 @@ public:
private:
enum State {
AccessCodeSearch,
Preamble,
Payload,
};
size_t payload_length { 0 };
size_t bits_received { 0 };
State state { State::AccessCodeSearch };
std::bitset<256> payload;
bool packet_truncated() const {
return bits_received >= payload.size();
}
void reset_state();
const PayloadHandlerFunc payload_handler;
BitHistory bit_history;
PreambleMatcher preamble;
UnstuffMatcher unstuff;
EndMatcher end;
size_t bits_received { 0 };
State state { State::Preamble };
PayloadType payload;
void reset_state() {
bits_received = 0;
state = State::Preamble;
}
};
#endif/*__PACKET_BUILDER_H__*/

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_ais.hpp"
#include "portapack_shared_memory.hpp"
#include "i2s.hpp"
using namespace lpc43xx;
void AISProcessor::execute(buffer_c8_t buffer) {
/* 2.4576MHz, 2048 samples */
auto decimator_out = decimator.execute(buffer);
/* 76.8kHz, 64 samples */
feed_channel_stats(decimator_out);
/* No spectrum display while AIS decoding.
feed_channel_spectrum(
channel,
decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized,
decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized
);
*/
for(size_t i=0; i<decimator_out.count; i++) {
// TODO: No idea why implicit cast int16_t->float is not allowed.
const std::complex<float> sample {
static_cast<float>(decimator_out.p[i].real()),
static_cast<float>(decimator_out.p[i].imag())
};
if( mf.execute_once(sample) ) {
clock_recovery(mf.get_output());
}
}
i2s::i2s0::tx_mute();
}
void AISProcessor::consume_symbol(
const float raw_symbol
) {
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
const auto decoded_symbol = nrzi_decode(sliced_symbol);
packet_builder.execute(decoded_symbol);
}
void AISProcessor::payload_handler(
const std::bitset<1024>& payload,
const size_t bits_received
) {
AISPacketMessage message;
message.packet.payload = payload;
message.packet.bits_received = bits_received;
shared_memory.application_queue.push(message);
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_AIS_H__
#define __PROC_AIS_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "matched_filter.hpp"
#include "clock_recovery.hpp"
#include "symbol_coding.hpp"
#include "packet_builder.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
#include "ais_baseband.hpp"
class AISProcessor : public BasebandProcessor {
public:
using payload_t = std::bitset<1024>;
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator { ChannelDecimator::DecimationFactor::By32 };
dsp::matched_filter::MatchedFilter mf { baseband::ais::rrc_taps_76k8_4t_p, 4 };
clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
19200, 9600, { 0.0555f },
[this](const float symbol) { this->consume_symbol(symbol); }
};
symbol_coding::NRZIDecoder nrzi_decode;
PacketBuilder<BitPattern, BitPattern, BitPattern> packet_builder {
{ 0b0101010101111110, 16, 1 },
{ 0b111110, 6 },
{ 0b01111110, 8 },
[this](const payload_t& payload, const size_t bits_received) {
this->payload_handler(payload, bits_received);
}
};
void consume_symbol(const float symbol);
void payload_handler(const payload_t& payload, const size_t bits_received);
};
#endif/*__PROC_AIS_H__*/

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_am_audio.hpp"
#include <cstdint>
void NarrowbandAMAudio::execute(buffer_c8_t buffer) {
auto decimator_out = decimator.execute(buffer);
const buffer_c16_t work_baseband_buffer {
(complex16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 96kHz complex<int16_t>[64]
* -> FIR filter, <?kHz (0.???fs) pass, gain 1.0
* -> 48kHz int16_t[32] */
auto channel = channel_filter.execute(decimator_out, work_baseband_buffer);
// TODO: Feed channel_stats post-decimation data?
feed_channel_stats(channel);
feed_channel_spectrum(
channel,
decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized,
decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized
);
const buffer_s16_t work_audio_buffer {
(int16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 48kHz complex<int16_t>[32]
* -> AM demodulation
* -> 48kHz int16_t[32] */
auto audio = demod.execute(channel, work_audio_buffer);
audio_hpf.execute_in_place(audio);
fill_audio_buffer(audio);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_AM_AUDIO_H__
#define __PROC_AM_AUDIO_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
class NarrowbandAMAudio : public BasebandProcessor {
public:
NarrowbandAMAudio() {
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By32);
channel_filter.configure(channel_filter_taps.taps, 2);
}
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator;
const fir_taps_real<64>& channel_filter_taps = taps_64_lp_031_070_tfilter;
dsp::decimate::FIRAndDecimateComplex channel_filter;
dsp::demodulate::AM demod;
IIRBiquadFilter audio_hpf { audio_hpf_config };
};
#endif/*__PROC_AM_AUDIO_H__*/

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_nfm_audio.hpp"
#include <cstdint>
#include <cstddef>
void NarrowbandFMAudio::execute(buffer_c8_t buffer) {
/* Called every 2048/3072000 second -- 1500Hz. */
auto decimator_out = decimator.execute(buffer);
const buffer_c16_t work_baseband_buffer {
(complex16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 96kHz complex<int16_t>[64]
* -> FIR filter, <6kHz (0.063fs) pass, gain 1.0
* -> 48kHz int16_t[32] */
auto channel = channel_filter.execute(decimator_out, work_baseband_buffer);
// TODO: Feed channel_stats post-decimation data?
feed_channel_stats(channel);
feed_channel_spectrum(
channel,
decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized,
decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized
);
const buffer_s16_t work_audio_buffer {
(int16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 48kHz complex<int16_t>[32]
* -> FM demodulation
* -> 48kHz int16_t[32] */
auto audio = demod.execute(channel, work_audio_buffer);
static uint64_t audio_present_history = 0;
const auto audio_present_now = squelch.execute(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
const bool audio_present = (audio_present_history != 0);
if( !audio_present ) {
// Zero audio buffer.
for(size_t i=0; i<audio.count; i++) {
audio.p[i] = 0;
}
}
audio_hpf.execute_in_place(audio);
fill_audio_buffer(audio);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_NFM_AUDIO_H__
#define __PROC_NFM_AUDIO_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
#include "dsp_squelch.hpp"
class NarrowbandFMAudio : public BasebandProcessor {
public:
NarrowbandFMAudio() {
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By32);
channel_filter.configure(channel_filter_taps.taps, 2);
}
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator;
const fir_taps_real<64>& channel_filter_taps = taps_64_lp_042_078_tfilter;
dsp::decimate::FIRAndDecimateComplex channel_filter;
dsp::demodulate::FM demod { 48000, 7500 };
IIRBiquadFilter audio_hpf { audio_hpf_config };
FMSquelch squelch;
};
#endif/*__PROC_NFM_AUDIO_H__*/

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_tpms.hpp"
#include "portapack_shared_memory.hpp"
#include "i2s.hpp"
using namespace lpc43xx;
void TPMSProcessor::execute(buffer_c8_t buffer) {
/* 2.4576MHz, 2048 samples */
auto decimator_out = decimator.execute(buffer);
/* 76.8kHz, 64 samples */
feed_channel_stats(decimator_out);
/* No spectrum display while FSK decoding.
feed_channel_spectrum(
channel,
decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized,
decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized
);
*/
for(size_t i=0; i<decimator_out.count; i++) {
// TODO: No idea why implicit cast int16_t->float is not allowed.
const std::complex<float> sample {
static_cast<float>(decimator_out.p[i].real()),
static_cast<float>(decimator_out.p[i].imag())
};
if( mf.execute_once(sample) ) {
clock_recovery(mf.get_output());
}
}
i2s::i2s0::tx_mute();
}
void TPMSProcessor::consume_symbol(
const float raw_symbol
) {
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
packet_builder.execute(sliced_symbol);
}
void TPMSProcessor::payload_handler(
const std::bitset<1024>& payload,
const size_t bits_received
) {
TPMSPacketMessage message;
message.packet.payload = payload;
message.packet.bits_received = bits_received;
shared_memory.application_queue.push(message);
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_TPMS_H__
#define __PROC_TPMS_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "matched_filter.hpp"
#include "clock_recovery.hpp"
#include "symbol_coding.hpp"
#include "packet_builder.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
struct NeverMatch {
bool operator()(const BitHistory&, const size_t) const {
return false;
}
};
struct FixedLength {
bool operator()(const BitHistory&, const size_t symbols_received) const {
return symbols_received >= length;
}
const size_t length;
};
// Translate+rectangular filter
// sample=153.6k, deviation=38400, symbol=19200
// Length: 8 taps, 1 symbols, 2 cycles of sinusoid
constexpr std::array<std::complex<float>, 8> rect_taps_153k6_1t_p { {
{ 1.2500000000e-01f, 0.0000000000e+00f }, { 7.6540424947e-18f, 1.2500000000e-01f },
{ -1.2500000000e-01f, 1.5308084989e-17f }, { -2.2962127484e-17f, -1.2500000000e-01f },
{ 1.2500000000e-01f, -3.0616169979e-17f }, { 3.8270212473e-17f, 1.2500000000e-01f },
{ -1.2500000000e-01f, 4.5924254968e-17f }, { -5.3578297463e-17f, -1.2500000000e-01f },
} };
class TPMSProcessor : public BasebandProcessor {
public:
using payload_t = std::bitset<1024>;
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator { ChannelDecimator::DecimationFactor::By16 };
dsp::matched_filter::MatchedFilter mf { rect_taps_153k6_1t_p, 4 };
clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
38400, 19200, { 0.0555f },
[this](const float symbol) { this->consume_symbol(symbol); }
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder {
{ 0b010101010101010101010101010110, 30, 1 },
{ },
{ 256 },
[this](const payload_t& payload, const size_t bits_received) {
this->payload_handler(payload, bits_received);
}
};
void consume_symbol(const float symbol);
void payload_handler(const payload_t& payload, const size_t bits_received);
};
#endif/*__PROC_TPMS_H__*/

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_wfm_audio.hpp"
#include <cstdint>
void WidebandFMAudio::execute(buffer_c8_t buffer) {
auto decimator_out = decimator.execute(buffer);
const buffer_s16_t work_audio_buffer {
(int16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
auto channel = decimator_out;
// TODO: Feed channel_stats post-decimation data?
feed_channel_stats(channel);
//feed_channel_spectrum(channel);
/* 768kHz complex<int16_t>[512]
* -> FM demodulation
* -> 768kHz int16_t[512] */
/* TODO: To improve adjacent channel rejection, implement complex channel filter:
* pass < +/- 100kHz, stop > +/- 200kHz
*/
auto audio_oversampled = demod.execute(decimator_out, work_audio_buffer);
/* 768kHz int16_t[512]
* -> 4th order CIC decimation by 2, gain of 1
* -> 384kHz int16_t[256] */
auto audio_8fs = audio_dec_1.execute(audio_oversampled, work_audio_buffer);
/* 384kHz int16_t[256]
* -> 4th order CIC decimation by 2, gain of 1
* -> 192kHz int16_t[128] */
auto audio_4fs = audio_dec_2.execute(audio_8fs, work_audio_buffer);
/* 192kHz int16_t[128]
* -> 4th order CIC decimation by 2, gain of 1
* -> 96kHz int16_t[64] */
auto audio_2fs = audio_dec_3.execute(audio_4fs, work_audio_buffer);
/* 96kHz int16_t[64]
* -> FIR filter, <15kHz (0.156fs) pass, >19kHz (0.198fs) stop, gain of 1
* -> 48kHz int16_t[32] */
auto audio = audio_filter.execute(audio_2fs, work_audio_buffer);
/* -> 48kHz int16_t[32] */
audio_hpf.execute_in_place(audio);
fill_audio_buffer(audio);
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_WFM_AUDIO_H__
#define __PROC_WFM_AUDIO_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
class WidebandFMAudio : public BasebandProcessor {
public:
WidebandFMAudio() {
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By4);
}
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator;
dsp::demodulate::FM demod { 768000, 75000 };
dsp::decimate::DecimateBy2CIC4Real audio_dec_1;
dsp::decimate::DecimateBy2CIC4Real audio_dec_2;
dsp::decimate::DecimateBy2CIC4Real audio_dec_3;
const fir_taps_real<64>& audio_filter_taps = taps_64_lp_156_198;
dsp::decimate::FIR64AndDecimateBy2Real audio_filter { audio_filter_taps.taps };
IIRBiquadFilter audio_hpf { audio_hpf_config };
};
#endif/*__PROC_WFM_AUDIO_H__*/

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_wideband_spectrum.hpp"
#include "event_m4.hpp"
#include "i2s.hpp"
using namespace lpc43xx;
#include "dsp_fft.hpp"
#include <cstdint>
#include <cstddef>
#include <array>
void WidebandSpectrum::execute(buffer_c8_t buffer) {
// 2048 complex8_t samples per buffer.
// 102.4us per buffer. 20480 instruction cycles per buffer.
static int phase = 0;
if( phase == 0 ) {
std::fill(spectrum.begin(), spectrum.end(), 0);
}
if( (phase & 7) == 0 ) {
// TODO: Removed window-presum windowing, due to lack of available code RAM.
// TODO: Apply window to improve spectrum bin sidelobes.
for(size_t i=0; i<channel_spectrum.size(); i++) {
spectrum[i] += std::complex<float> { buffer.p[i].real(), buffer.p[i].imag() };
}
}
if( phase == 23 ) {
if( channel_spectrum_request_update == false ) {
fft_swap(spectrum, channel_spectrum);
channel_spectrum_sampling_rate = buffer.sampling_rate;
channel_filter_pass_frequency = 0;
channel_filter_stop_frequency = 0;
channel_spectrum_request_update = true;
events_flag(EVT_MASK_SPECTRUM);
phase = 0;
}
} else {
phase++;
}
i2s::i2s0::tx_mute();
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_WIDEBAND_SPECTRUM_H__
#define __PROC_WIDEBAND_SPECTRUM_H__
#include "baseband_processor.hpp"
#include <cstddef>
#include <array>
#include <complex>
class WidebandSpectrum : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
private:
size_t sample_count = 0;
std::array<std::complex<float>, 256> spectrum;
};
#endif/*__PROC_WIDEBAND_SPECTRUM_H__*/

View File

@@ -37,6 +37,12 @@ public:
return;
}
if( statistics.count == 0 ) {
const auto value_0 = *p;
statistics.min = value_0;
statistics.max = value_0;
}
const auto end = &p[buffer.count];
while(p < end) {
const uint32_t value = *(p++);
@@ -58,9 +64,6 @@ public:
callback(statistics);
statistics.accumulator = 0;
statistics.count = 0;
const auto value_0 = *p;
statistics.min = value_0;
statistics.max = value_0;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SYMBOL_CODING_H__
#define __SYMBOL_CODING_H__
#include <cstdint>
#include <cstddef>
namespace symbol_coding {
class NRZIDecoder {
public:
uint_fast8_t operator()(const uint_fast8_t symbol) {
const auto out = (~(symbol ^ last)) & 1;
last = symbol;
return out;
}
private:
uint_fast8_t last { 0 };
};
} /* namespace symbol_coding */
#endif/*__SYMBOL_CODING_H__*/