mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-13 10:09:30 +00:00
Isolate filtered spectrum collection from WFM
This commit is contained in:
@@ -124,6 +124,7 @@ set(CPPSRC
|
|||||||
dsp_goertzel.cpp
|
dsp_goertzel.cpp
|
||||||
matched_filter.cpp
|
matched_filter.cpp
|
||||||
spectrum_collector.cpp
|
spectrum_collector.cpp
|
||||||
|
filtered_spectrum_collector.cpp
|
||||||
tv_collector.cpp
|
tv_collector.cpp
|
||||||
stream_input.cpp
|
stream_input.cpp
|
||||||
stream_output.cpp
|
stream_output.cpp
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "filtered_spectrum_collector.hpp"
|
||||||
|
|
||||||
|
#include "dsp_fir_taps.hpp"
|
||||||
|
#include "event_m4.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
void FilteredSpectrumCollector::on_message(const Message* const message) {
|
||||||
|
if (message->id == Message::ID::UpdateSpectrum) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
SpectrumCollector::on_message(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilteredSpectrumCollector::start_capture(
|
||||||
|
const size_t decimation_factor) {
|
||||||
|
capture_decimation_ = decimation_factor;
|
||||||
|
capture_count_ = 0;
|
||||||
|
capture_ready_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilteredSpectrumCollector::feed(
|
||||||
|
const buffer_c16_t& channel,
|
||||||
|
const int32_t filter_low_frequency,
|
||||||
|
const int32_t filter_high_frequency,
|
||||||
|
const int32_t filter_transition) {
|
||||||
|
set_filter(
|
||||||
|
filter_low_frequency,
|
||||||
|
filter_high_frequency,
|
||||||
|
filter_transition);
|
||||||
|
|
||||||
|
const size_t required_samples = 256 * capture_decimation_;
|
||||||
|
const size_t copy_count = std::min(
|
||||||
|
channel.count, required_samples - capture_count_);
|
||||||
|
std::copy_n(
|
||||||
|
channel.p,
|
||||||
|
copy_count,
|
||||||
|
capture_.begin() + capture_count_);
|
||||||
|
capture_count_ += copy_count;
|
||||||
|
|
||||||
|
if (capture_count_ == required_samples) {
|
||||||
|
sampling_rate_ = channel.sampling_rate / capture_decimation_;
|
||||||
|
capture_ready_ = true;
|
||||||
|
EventDispatcher::events_flag(EVT_MASK_SPECTRUM);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilteredSpectrumCollector::update() {
|
||||||
|
if (!capture_ready_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decim_0_.configure(taps_audio_spectrum_halfband.taps);
|
||||||
|
const buffer_c16_t capture{
|
||||||
|
capture_.data(),
|
||||||
|
256 * capture_decimation_,
|
||||||
|
sampling_rate_ * capture_decimation_};
|
||||||
|
const buffer_c16_t stage_0{
|
||||||
|
stage_0_.data(),
|
||||||
|
stage_0_.size()};
|
||||||
|
const auto filtered = decim_0_.execute(capture, stage_0);
|
||||||
|
|
||||||
|
if (capture_decimation_ == 4) {
|
||||||
|
decim_1_.configure(taps_audio_spectrum_halfband.taps);
|
||||||
|
const buffer_c16_t stage_1{
|
||||||
|
stage_1_.data(),
|
||||||
|
stage_1_.size()};
|
||||||
|
post_message(decim_1_.execute(filtered, stage_1));
|
||||||
|
} else {
|
||||||
|
post_message(filtered);
|
||||||
|
}
|
||||||
|
capture_ready_ = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FILTERED_SPECTRUM_COLLECTOR_H__
|
||||||
|
#define __FILTERED_SPECTRUM_COLLECTOR_H__
|
||||||
|
|
||||||
|
#include "dsp_decimate.hpp"
|
||||||
|
#include "spectrum_collector.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
class FilteredSpectrumCollector : public SpectrumCollector {
|
||||||
|
public:
|
||||||
|
void on_message(const Message* const message);
|
||||||
|
|
||||||
|
void start_capture(const size_t decimation_factor);
|
||||||
|
bool feed(
|
||||||
|
const buffer_c16_t& channel,
|
||||||
|
const int32_t filter_low_frequency,
|
||||||
|
const int32_t filter_high_frequency,
|
||||||
|
const int32_t filter_transition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<complex16_t, 1024> capture_{};
|
||||||
|
std::array<complex16_t, 512> stage_0_{};
|
||||||
|
std::array<complex16_t, 256> stage_1_{};
|
||||||
|
dsp::decimate::FIRC16xR16x63HalfbandDecim2 decim_0_{};
|
||||||
|
dsp::decimate::FIRC16xR16x63HalfbandDecim2 decim_1_{};
|
||||||
|
size_t capture_count_{0};
|
||||||
|
size_t capture_decimation_{1};
|
||||||
|
uint32_t sampling_rate_{0};
|
||||||
|
bool capture_ready_{false};
|
||||||
|
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*__FILTERED_SPECTRUM_COLLECTOR_H__*/
|
||||||
@@ -51,12 +51,12 @@ void NarrowbandAMAudio::execute(const buffer_c8_t& buffer) {
|
|||||||
if (!spectrum_capture_active &&
|
if (!spectrum_capture_active &&
|
||||||
spectrum_samples >= spectrum_interval_samples) {
|
spectrum_samples >= spectrum_interval_samples) {
|
||||||
spectrum_samples -= spectrum_interval_samples;
|
spectrum_samples -= spectrum_interval_samples;
|
||||||
channel_spectrum.start_filtered_capture(spectrum_zoom_x2 ? 4 : 2);
|
channel_spectrum.start_capture(spectrum_zoom_x2 ? 4 : 2);
|
||||||
spectrum_capture_active = true;
|
spectrum_capture_active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spectrum_capture_active &&
|
if (spectrum_capture_active &&
|
||||||
channel_spectrum.feed_filtered(
|
channel_spectrum.feed(
|
||||||
audio_decim_0_out,
|
audio_decim_0_out,
|
||||||
channel_filter_low_f,
|
channel_filter_low_f,
|
||||||
channel_filter_high_f,
|
channel_filter_high_f,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
#include "audio_compressor.hpp"
|
#include "audio_compressor.hpp"
|
||||||
|
|
||||||
#include "audio_output.hpp"
|
#include "audio_output.hpp"
|
||||||
#include "spectrum_collector.hpp"
|
#include "filtered_spectrum_collector.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class NarrowbandAMAudio : public BasebandProcessor {
|
|||||||
FeedForwardCompressor audio_compressor{};
|
FeedForwardCompressor audio_compressor{};
|
||||||
AudioOutput audio_output{};
|
AudioOutput audio_output{};
|
||||||
|
|
||||||
SpectrumCollector channel_spectrum{};
|
FilteredSpectrumCollector channel_spectrum{};
|
||||||
|
|
||||||
/* NB: Threads should be the last members in the class definition. */
|
/* NB: Threads should be the last members in the class definition. */
|
||||||
#ifdef PRALINE
|
#ifdef PRALINE
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
|
|||||||
if (!spectrum_capture_active &&
|
if (!spectrum_capture_active &&
|
||||||
spectrum_samples >= spectrum_interval_samples) {
|
spectrum_samples >= spectrum_interval_samples) {
|
||||||
spectrum_samples -= spectrum_interval_samples;
|
spectrum_samples -= spectrum_interval_samples;
|
||||||
channel_spectrum.start_filtered_capture(2);
|
channel_spectrum.start_capture(2);
|
||||||
spectrum_capture_active = true;
|
spectrum_capture_active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spectrum_capture_active &&
|
if (spectrum_capture_active &&
|
||||||
channel_spectrum.feed_filtered(
|
channel_spectrum.feed(
|
||||||
audio_decim_0_out,
|
audio_decim_0_out,
|
||||||
channel_filter_low_f,
|
channel_filter_low_f,
|
||||||
channel_filter_high_f,
|
channel_filter_high_f,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "dsp_iir.hpp"
|
#include "dsp_iir.hpp"
|
||||||
|
|
||||||
#include "audio_output.hpp"
|
#include "audio_output.hpp"
|
||||||
#include "spectrum_collector.hpp"
|
#include "filtered_spectrum_collector.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ class NarrowbandFMAudio : public BasebandProcessor {
|
|||||||
|
|
||||||
AudioOutput audio_output{};
|
AudioOutput audio_output{};
|
||||||
|
|
||||||
SpectrumCollector channel_spectrum{};
|
FilteredSpectrumCollector channel_spectrum{};
|
||||||
size_t spectrum_interval_samples{0};
|
size_t spectrum_interval_samples{0};
|
||||||
size_t spectrum_samples{0};
|
size_t spectrum_samples{0};
|
||||||
bool spectrum_capture_active{false};
|
bool spectrum_capture_active{false};
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "spectrum_collector.hpp"
|
#include "spectrum_collector.hpp"
|
||||||
|
|
||||||
#include "dsp_fft.hpp"
|
#include "dsp_fft.hpp"
|
||||||
#include "dsp_fir_taps.hpp"
|
|
||||||
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "event_m4.hpp"
|
#include "event_m4.hpp"
|
||||||
@@ -80,9 +79,10 @@ bool SpectrumCollector::feed(
|
|||||||
const int32_t filter_high_frequency,
|
const int32_t filter_high_frequency,
|
||||||
const int32_t filter_transition) {
|
const int32_t filter_transition) {
|
||||||
// Called from baseband processing thread.
|
// Called from baseband processing thread.
|
||||||
channel_filter_low_frequency = filter_low_frequency;
|
set_filter(
|
||||||
channel_filter_high_frequency = filter_high_frequency;
|
filter_low_frequency,
|
||||||
channel_filter_transition = filter_transition;
|
filter_high_frequency,
|
||||||
|
filter_transition);
|
||||||
|
|
||||||
bool block_completed = false;
|
bool block_completed = false;
|
||||||
channel_spectrum_decimator.feed(
|
channel_spectrum_decimator.feed(
|
||||||
@@ -94,40 +94,13 @@ bool SpectrumCollector::feed(
|
|||||||
return block_completed;
|
return block_completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumCollector::start_filtered_capture(
|
void SpectrumCollector::set_filter(
|
||||||
const size_t decimation_factor) {
|
|
||||||
filtered_capture_decimation_ = decimation_factor;
|
|
||||||
filtered_capture_count_ = 0;
|
|
||||||
filtered_capture_ready_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpectrumCollector::feed_filtered(
|
|
||||||
const buffer_c16_t& channel,
|
|
||||||
const int32_t filter_low_frequency,
|
const int32_t filter_low_frequency,
|
||||||
const int32_t filter_high_frequency,
|
const int32_t filter_high_frequency,
|
||||||
const int32_t filter_transition) {
|
const int32_t filter_transition) {
|
||||||
channel_filter_low_frequency = filter_low_frequency;
|
channel_filter_low_frequency = filter_low_frequency;
|
||||||
channel_filter_high_frequency = filter_high_frequency;
|
channel_filter_high_frequency = filter_high_frequency;
|
||||||
channel_filter_transition = filter_transition;
|
channel_filter_transition = filter_transition;
|
||||||
|
|
||||||
const size_t required_samples = 256 * filtered_capture_decimation_;
|
|
||||||
const size_t copy_count = std::min(
|
|
||||||
channel.count, required_samples - filtered_capture_count_);
|
|
||||||
std::copy_n(
|
|
||||||
channel.p,
|
|
||||||
copy_count,
|
|
||||||
filtered_capture_.begin() + filtered_capture_count_);
|
|
||||||
filtered_capture_count_ += copy_count;
|
|
||||||
|
|
||||||
if (filtered_capture_count_ == required_samples) {
|
|
||||||
channel_spectrum_sampling_rate =
|
|
||||||
channel.sampling_rate / filtered_capture_decimation_;
|
|
||||||
filtered_capture_ready_ = true;
|
|
||||||
channel_spectrum_request_update = true;
|
|
||||||
EventDispatcher::events_flag(EVT_MASK_SPECTRUM);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumCollector::post_message(const buffer_c16_t& data) {
|
void SpectrumCollector::post_message(const buffer_c16_t& data) {
|
||||||
@@ -171,31 +144,6 @@ static typename T::value_type spectrum_window_blackman_3(const T& s, const size_
|
|||||||
void SpectrumCollector::update() {
|
void SpectrumCollector::update() {
|
||||||
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
|
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
|
||||||
if (streaming && channel_spectrum_request_update) {
|
if (streaming && channel_spectrum_request_update) {
|
||||||
if (filtered_capture_ready_) {
|
|
||||||
filtered_decim_0_.configure(taps_audio_spectrum_halfband.taps);
|
|
||||||
const buffer_c16_t capture{
|
|
||||||
filtered_capture_.data(),
|
|
||||||
256 * filtered_capture_decimation_,
|
|
||||||
channel_spectrum_sampling_rate * filtered_capture_decimation_};
|
|
||||||
const buffer_c16_t stage_0{
|
|
||||||
filtered_stage_0_.data(),
|
|
||||||
filtered_stage_0_.size()};
|
|
||||||
const auto filtered = filtered_decim_0_.execute(capture, stage_0);
|
|
||||||
|
|
||||||
if (filtered_capture_decimation_ == 4) {
|
|
||||||
filtered_decim_1_.configure(taps_audio_spectrum_halfband.taps);
|
|
||||||
const buffer_c16_t stage_1{
|
|
||||||
filtered_stage_1_.data(),
|
|
||||||
filtered_stage_1_.size()};
|
|
||||||
const auto zoom_filtered =
|
|
||||||
filtered_decim_1_.execute(filtered, stage_1);
|
|
||||||
fft_swap(zoom_filtered, channel_spectrum);
|
|
||||||
} else {
|
|
||||||
fft_swap(filtered, channel_spectrum);
|
|
||||||
}
|
|
||||||
filtered_capture_ready_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decimated buffer is full. Compute spectrum. */
|
/* Decimated buffer is full. Compute spectrum. */
|
||||||
fft_c_preswapped(channel_spectrum, 0, 8);
|
fft_c_preswapped(channel_spectrum, 0, 8);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include "complex.hpp"
|
#include "complex.hpp"
|
||||||
|
|
||||||
#include "block_decimator.hpp"
|
#include "block_decimator.hpp"
|
||||||
#include "dsp_decimate.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -51,12 +50,12 @@ class SpectrumCollector {
|
|||||||
const int32_t filter_high_frequency,
|
const int32_t filter_high_frequency,
|
||||||
const int32_t filter_transition);
|
const int32_t filter_transition);
|
||||||
|
|
||||||
void start_filtered_capture(const size_t decimation_factor);
|
protected:
|
||||||
bool feed_filtered(
|
void set_filter(
|
||||||
const buffer_c16_t& channel,
|
|
||||||
const int32_t filter_low_frequency,
|
const int32_t filter_low_frequency,
|
||||||
const int32_t filter_high_frequency,
|
const int32_t filter_high_frequency,
|
||||||
const int32_t filter_transition);
|
const int32_t filter_transition);
|
||||||
|
void post_message(const buffer_c16_t& data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BlockDecimator<complex16_t, 256> channel_spectrum_decimator{1};
|
BlockDecimator<complex16_t, 256> channel_spectrum_decimator{1};
|
||||||
@@ -66,22 +65,12 @@ class SpectrumCollector {
|
|||||||
volatile bool channel_spectrum_request_update{false};
|
volatile bool channel_spectrum_request_update{false};
|
||||||
bool streaming{false};
|
bool streaming{false};
|
||||||
std::array<std::complex<float>, 256> channel_spectrum{};
|
std::array<std::complex<float>, 256> channel_spectrum{};
|
||||||
std::array<complex16_t, 1024> filtered_capture_{};
|
|
||||||
std::array<complex16_t, 512> filtered_stage_0_{};
|
|
||||||
std::array<complex16_t, 256> filtered_stage_1_{};
|
|
||||||
dsp::decimate::FIRC16xR16x63HalfbandDecim2 filtered_decim_0_{};
|
|
||||||
dsp::decimate::FIRC16xR16x63HalfbandDecim2 filtered_decim_1_{};
|
|
||||||
size_t filtered_capture_count_{0};
|
|
||||||
size_t filtered_capture_decimation_{1};
|
|
||||||
bool filtered_capture_ready_{false};
|
|
||||||
uint32_t channel_spectrum_sampling_rate{0};
|
uint32_t channel_spectrum_sampling_rate{0};
|
||||||
int32_t channel_filter_low_frequency{0};
|
int32_t channel_filter_low_frequency{0};
|
||||||
int32_t channel_filter_high_frequency{0};
|
int32_t channel_filter_high_frequency{0};
|
||||||
int32_t channel_filter_transition{0};
|
int32_t channel_filter_transition{0};
|
||||||
int32_t channel_filter_offset{0};
|
int32_t channel_filter_offset{0};
|
||||||
|
|
||||||
void post_message(const buffer_c16_t& data);
|
|
||||||
|
|
||||||
void set_state(const SpectrumStreamingConfigMessage& message);
|
void set_state(const SpectrumStreamingConfigMessage& message);
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
|||||||
Reference in New Issue
Block a user