diff --git a/firmware/application/freqman_db.cpp b/firmware/application/freqman_db.cpp index e32599ac..b3ef011f 100644 --- a/firmware/application/freqman_db.cpp +++ b/firmware/application/freqman_db.cpp @@ -83,16 +83,22 @@ options_t freqman_bandwidths[4] = { {"100k", 100000}, {"150k", 150000}, {"250k", 250000}, - {"500k", 500000}, /* Previous Limit bandwith Option with perfect micro SD write .C16 format operaton.*/ - {"600k", 600000}, /* We doubled x2 previous REC BW limit , now extended BW from 600k to 1M with fast enough SD card in C16 or C8 format .*/ - {"650k", 650000}, + {"500k", 500000}, + {"600k", 600000}, {"750k", 750000}, - {"1000k", 1000000}, /* New limit bandwith option for recording in C16 (in fast SD card) or in C8 */ - {"1500k", 1500000}, /* From this BW onwards, the LCD is ok, but M4 CPU is having periodical sample rec dropps, (not real file size, accelerated replay) */ + {"1000k", 1000000}, // Max bandwith for recording in C16 (with fast SD card). + {"1250k", 1250000}, + {"1500k", 1500000}, {"1750k", 1750000}, {"2000k", 2000000}, - {"2500k", 2500000}, - {"2750k", 2750000}, // That is our max Capture option, to keep using later / 8 decimation (22Mhz sampling ADC) + {"2250k", 2250000}, // Max bandwith for recording in C8 (with fast SD card). + {"2500k", 2500000}, // Here and up, LCD is ok, but M4 CPU drops samples. + {"3000k", 3000000}, + {"3500k", 3500000}, + {"4000k", 4000000}, + {"4500k", 4500000}, + {"5000k", 5500000}, + {"5500k", 5500000}, // Max capture, needs /4 decimation, (22Mhz sampling ADC). }, }; diff --git a/firmware/application/ui/ui_spectrum.cpp b/firmware/application/ui/ui_spectrum.cpp index 319915b1..52c06839 100644 --- a/firmware/application/ui/ui_spectrum.cpp +++ b/firmware/application/ui/ui_spectrum.cpp @@ -383,33 +383,33 @@ void WaterfallView::on_audio_spectrum() { // TODO: Comments below refer to a fixed oversample rate (8x), cleanup. uint32_t filter_bandwidth_for_sampling_rate(int32_t sampling_rate) { switch (sampling_rate) { // Use the var fs (sampling_rate) to set up BPF aprox < fs_max / 2 by Nyquist theorem. - case 0 ... 3'500'000: // BW Captured range (0 <= 250kHz max) fs = 8x250 kHz =2000., 16x150 khz =2400, 32x100 khz =3200, (32x75k = 2400), (future 64x40 khz =2400) + case 0 ... 3'500'000: // BW Captured range (0 <= 250kHz max) fs = 8x250k = 2000, 16x150k = 2400, 32x100k = 3200, 32x75k = 2400, (future 64x40 khz = 2400) return 1'750'000; // Minimum BPF MAX2837 for all those lower BW options. - case 4'000'000 ... 6'000'000: // BW capture range (500k...750kHz max) fs_max = 8 x 750kHz = 6Mhz + case 4'000'000 ... 7'000'000: // OVS x8, BW capture range (500k...750kHz max) fs_max = 8 x 750k = 6Mhz // BW 500k...750kHz, ex. 500kHz (fs = 8 x BW = 4Mhz), BW 600kHz (fs = 4,8Mhz), BW 750 kHz (fs = 6Mhz). return 2'500'000; // In some IC, MAX2837 appears as 2250000, but both work similarly. - case 8'000'000: // BW capture 1Mhz fs = 8 x 1Mhz = 8Mhz. (1Mhz showed slightly higher noise background). - return 3'500'000; // some low SD cards, if not showing avg. writting speed >4MB/sec, they will produce sammples drop at REC with 1MB and C16 format. + case 7'000'001 ... 10'000'000: // OVS x8 and x4, BW capture 1Mhz fs = 8 x 1Mhz = 8Mhz. (1Mhz showed slightly higher noise background). + return 3'500'000; // some low SD cards, if not showing avg. writing speed >4MB/sec, they will produce sammples drop at REC with 1MB and C16 format. - case 12'000'000: // BW capture 1,5Mhz, fs = 8 x 1,5Mhz = 12Mhz - // Good BPF, good matching, we have some periodical M4 % samples drop. + case 12'000'000 ... 14'000'000: // OVS x4, BW capture 3Mhz, fs = 4 x 3Mhz = 12Mhz + // Good BPF, good matching, we have some periodical M4 % samples drop. return 5'000'000; - case 14'000'000: // BW capture 1,75Mhz, fs = 8 x 1,75Mhz = 14Mhz + case 16'000'000: // OVS x4, BW capture 4Mhz, fs = 4 x 4Mhz = 16Mhz // Good BPF, good matching, we have some periodical M4 % samples drop. - return 5'000'000; + return 5'500'000; - case 16'000'000: // BW capture 2Mhz, fs = 8 x 2Mhz = 16Mhz + case 18'000'000: // OVS x4, BW capture 4,5Mhz, fs = 4 x 4,5Mhz = 18Mhz // Good BPF, good matching, we have some periodical M4 % samples drop. return 6'000'000; - case 20'000'000: // BW capture 2,5Mhz, fs = 8 x 2,5 Mhz = 20Mhz + case 20'000'000: // OVS x4, BW capture 5Mhz, fs = 4 x 5Mhz = 20Mhz // Good BPF, good matching, we have some periodical M4 % samples drop. return 7'000'000; - default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz = 22Mhz max ADC sampling and others. + default: // BW capture 5,5Mhz, fs = 4 x 5,5Mhz = 22Mhz max ADC sampling and others. // We tested also 9Mhz FPB slightly too much noise floor, better at 8Mhz. return 8'000'000; } diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 3d1f143b..83b9e5f7 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -107,13 +107,9 @@ uint32_t RecordView::set_sampling_rate(uint32_t new_sampling_rate) { auto oversample_rate = get_oversample_rate(new_sampling_rate); auto actual_sampling_rate = new_sampling_rate * toUType(oversample_rate); - /* We are changing "REC" icon background to yellow in BW rec Options >1Mhz - * > 1Mhz BW options , we are NOT recording full IQ .C16 files (those files has some periodical missing dropped samples). - * Those recorded files, has not the full IQ samples information, looks like decimated in file size. - * They are ok as recorded spectrum indication, but they should not be used by Replay app. (the voice speed will be accelerated) - - * We keep original black background in all the correct IQ .C16 files BW's Options. */ - if (actual_sampling_rate > 8'000'000) { // yellow REC button means not ok for REC, BW >1Mhz (BW from 12k5 till 1Mhz OK for REC and Replay) + // Change the "REC" icon background to yellow when the selected rate exceeds hardware limits. + // Above this threshold, samples will be dropped resulting incomplete capture files. + if (new_sampling_rate > 1'250'000) { button_record.set_background(ui::Color::yellow()); } else { button_record.set_background(ui::Color::black()); @@ -142,15 +138,7 @@ OversampleRate RecordView::get_oversample_rate(uint32_t sample_rate) { if (file_type == FileType::WAV) return OversampleRate::None; - auto rate = ::get_oversample_rate(sample_rate); - - // Currently proc_capture only supports /8, /16, /32 for decimation. - if (rate < OversampleRate::x8) // clipping while /4 is not implemented yet (it will be used >1Mhz onwards when available) - rate = OversampleRate::x8; - else if (rate > OversampleRate::x64) // clipping while /128 is not implemented yet , (but it is not necessary for 12k5) - rate = OversampleRate::x64; - - return rate; + return ::get_oversample_rate(sample_rate); } // Setter for datetime and frequency filename diff --git a/firmware/baseband/block_decimator.hpp b/firmware/baseband/block_decimator.hpp index fb8dd4e9..366db78b 100644 --- a/firmware/baseband/block_decimator.hpp +++ b/firmware/baseband/block_decimator.hpp @@ -69,29 +69,22 @@ class BlockDecimator { set_input_sampling_rate(src.sampling_rate); - while (src_i < src.count) { + for (size_t src_i = 0; src_i < src.count; src_i += factor()) { buffer[dst_i++] = src.p[src_i]; if (dst_i == buffer.size()) { callback({buffer.data(), buffer.size(), output_sampling_rate()}); reset_state(); - dst_i = 0; } - - src_i += factor(); } - - src_i -= src.count; } private: std::array buffer{}; uint32_t input_sampling_rate_{0}; size_t factor_{1}; - size_t src_i{0}; size_t dst_i{0}; void reset_state() { - src_i = 0; dst_i = 0; } }; diff --git a/firmware/baseband/dsp_decimate.cpp b/firmware/baseband/dsp_decimate.cpp index f65881ff..7b0af12a 100644 --- a/firmware/baseband/dsp_decimate.cpp +++ b/firmware/baseband/dsp_decimate.cpp @@ -202,8 +202,8 @@ buffer_c16_t FIRC8xR16x24FS4Decim4::execute( uint32_t* const d = static_cast(__builtin_assume_aligned(dst.p, 4)); const auto k = output_scale; - const size_t count = src.count / decimation_factor; + for (size_t i = 0; i < count; i++) { const vec4_s8* const in = static_cast(__builtin_assume_aligned(&src.p[i * decimation_factor], 4)); diff --git a/firmware/baseband/proc_capture.cpp b/firmware/baseband/proc_capture.cpp index 72008094..ad53acbf 100644 --- a/firmware/baseband/proc_capture.cpp +++ b/firmware/baseband/proc_capture.cpp @@ -26,48 +26,32 @@ #include "event_m4.hpp" #include "utility.hpp" +using namespace dsp::decimate; + CaptureProcessor::CaptureProcessor() { - decim_0_4.configure(taps_200k_decim_0.taps, 33554432); // to be used with decim1 (/2), then total two stages decim (/8) - decim_0_8.configure(taps_200k_decim_0.taps, 33554432); // to be used with decim1 (/2), then total two stages decim (/16) - decim_0_8_180k.configure(taps_180k_wfm_decim_0.taps, 33554432); // to be used alone - no additional decim1 (/2), then total single stage decim (/8) - - decim_1_2.configure(taps_200k_decim_1.taps, 131072); - decim_1_8.configure(taps_16k0_decim_1.taps, 131072); // tentative decim1 /8 and taps, pending to be optimized. - channel_spectrum.set_decimation_factor(1); baseband_thread.start(); } void CaptureProcessor::execute(const buffer_c8_t& buffer) { - /* 2.4576MHz, 2048 samples */ - const auto decim_0_out = decim_0_execute(buffer, dst_buffer); // selectable 3 possible decim_0, (/4. /8 200k soft filter , /8 180k sharp ) - const auto decim_1_out = decim_1_execute(decim_0_out, dst_buffer); // selectable 3 possible decim_1, (/8. /2 200k or bypassed /1 ) - - /* this code was valid when we had only 2 decim1 cases. - const auto decim_1_out = baseband_fs < 4800'000 - ? decim_1_2.execute(decim_0_out, dst_buffer) // < 600khz double decim. stage , means 500khz and lower bit rates. - // ? decim_1_8.execute(decim_0_out, dst_buffer) // < 600khz double decim. stage , means 500khz and lower bit rates. - : decim_0_out; // >= 600khz single decim. stage , means 600khz and upper bit rates. - - } */ - - const auto& decimator_out = decim_1_out; - const auto& channel = decimator_out; + auto decim_0_out = decim_0.execute(buffer, dst_buffer); + auto out_buffer = decim_1.execute(decim_0_out, dst_buffer); if (stream) { - const size_t bytes_to_write = sizeof(*decimator_out.p) * decimator_out.count; - const size_t written = stream->write(decimator_out.p, bytes_to_write); + const size_t bytes_to_write = sizeof(*out_buffer.p) * out_buffer.count; + const size_t written = stream->write(out_buffer.p, bytes_to_write); if (written != bytes_to_write) { - // TODO eventually report error somewhere + // TODO: Send an error message to the app? } } - feed_channel_stats(channel); + feed_channel_stats(out_buffer); - spectrum_samples += channel.count; + spectrum_samples += out_buffer.count; if (spectrum_samples >= spectrum_interval_samples) { spectrum_samples -= spectrum_interval_samples; - channel_spectrum.feed(channel, channel_filter_low_f, channel_filter_high_f, channel_filter_transition); + channel_spectrum.feed(out_buffer, channel_filter_low_f, + channel_filter_high_f, channel_filter_transition); } } @@ -92,120 +76,88 @@ void CaptureProcessor::on_message(const Message* const message) { } void CaptureProcessor::sample_rate_config(const SampleRateConfigMessage& message) { - baseband_fs = message.sample_rate * toUType(message.oversample_rate); - oversample_rate = message.oversample_rate; + const auto sample_rate = message.sample_rate; + // The actual sample rate is the requested rate * the oversample rate. + // See oversample.hpp for more details on oversampling. + baseband_fs = sample_rate * toUType(message.oversample_rate); baseband_thread.set_sampling_rate(baseband_fs); - // Current fw , we are using only 2 decim_0 modes, /4 , /8 - auto decim_0_factor = oversample_rate == OversampleRate::x8 - ? decim_0_4.decimation_factor - : decim_0_8.decimation_factor; + // TODO: Do we need to use the taps that the decimators get configured with? + channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * sample_rate; + channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * sample_rate; + channel_filter_transition = taps_200k_decim_1.transition_normalized * sample_rate; - size_t decim_0_output_fs = baseband_fs / decim_0_factor; - size_t decim_1_input_fs = decim_0_output_fs; + // Compute the scalar that corrects the oversample_rate to be x8 when computing + // the spectrum update interval. The original implementation only supported x8. + // TODO: Why is this needed here but not in proc_replay? There must be some other + // assumption about x8 oversampling in some component that makes this necessary. + const auto oversample_correction = toUType(message.oversample_rate) / 8.0; + + // The spectrum update interval controls how often the waterfall is fed new samples. + spectrum_interval_samples = sample_rate / (spectrum_rate_hz * oversample_correction); + spectrum_samples = 0; + + // For high sample rates, the M4 is busy collecting samples so the + // waterfall runs slower. Reduce the update interval so it runs faster. + // NB: Trade off: looks nicer, but more frequent updates == more CPU. + if (sample_rate >= 1'500'000) + spectrum_interval_samples /= (sample_rate / 500'000); + + // Mystery scalars for decimator configuration. + // TODO: figure these out and add a real comment. + constexpr int decim_0_scale = 0x2000000; + constexpr int decim_1_scale = 0x20000; + + switch (message.oversample_rate) { + case OversampleRate::x4: + // M4 can't handle 2 decimation passes for sample rates needing x4. + decim_0.set().configure(taps_200k_decim_0.taps, decim_0_scale); + decim_1.set(); + break; - size_t decim_1_factor; - switch (oversample_rate) { // we are using 3 decim_1 modes, /1 , /2 , /8 case OversampleRate::x8: - if (baseband_fs < 4800'000) { - decim_1_factor = decim_1_2.decimation_factor; // /8 = /4x2 + // M4 can't handle 2 decimation passes for sample rates <= 600k. + if (message.sample_rate < 600'000) { + decim_0.set().configure(taps_200k_decim_0.taps, decim_0_scale); + decim_1.set().configure(taps_200k_decim_1.taps, decim_1_scale); } else { - decim_1_factor = 2 * 1; // 600khz and onwards, single decim /8 = /8x1 (we applied additional *2 correction to speed up waterfall, no effect to scale spectrum) + // Using 180k taps to provide better filtering with a single pass. + decim_0.set().configure(taps_180k_wfm_decim_0.taps, decim_0_scale); + decim_1.set(); } break; case OversampleRate::x16: - decim_1_factor = 2 * decim_1_2.decimation_factor; // /16 = /8x2 (we applied additional *2 correction to increase waterfall spped >=600k and smooth & avoid abnormal motion >1M5 ) + decim_0.set().configure(taps_200k_decim_0.taps, decim_0_scale); + decim_1.set().configure(taps_200k_decim_1.taps, decim_1_scale); break; case OversampleRate::x32: - decim_1_factor = 2 * decim_1_8.decimation_factor; // /32 = /4x8 (we applied additional *2 correction to speed up waterfall, no effect to scale spectrum) + decim_0.set().configure(taps_200k_decim_0.taps, decim_0_scale); + decim_1.set().configure(taps_16k0_decim_1.taps, decim_1_scale); break; case OversampleRate::x64: - decim_1_factor = 8 * decim_1_8.decimation_factor; // /64 = /8x8 (we applied additional *8 correction to speed up waterfall, no effect to scale spectrum) + decim_0.set().configure(taps_200k_decim_0.taps, decim_0_scale); + decim_1.set().configure(taps_16k0_decim_1.taps, decim_1_scale); break; default: - decim_1_factor = 2; // just default initial value to remove compile warning. + chDbgPanic("Unhandled OversampleRate"); break; } - - /* - auto decim_1_factor = oversample_rate == OversampleRate::x32 // that was ok, when we had only 2 oversampling x8 , x16 - ? decim_1_8.decimation_factor - : decim_1_2.decimation_factor; - - */ - size_t decim_1_output_fs = decim_1_input_fs / decim_1_factor; - - channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * decim_1_input_fs; - channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * decim_1_input_fs; - channel_filter_transition = taps_200k_decim_1.transition_normalized * decim_1_input_fs; - - spectrum_interval_samples = decim_1_output_fs / spectrum_rate_hz; - spectrum_samples = 0; } void CaptureProcessor::capture_config(const CaptureConfigMessage& message) { - if (message.config) { + if (message.config) stream = std::make_unique(message.config); - } else { + else stream.reset(); - } -} - -buffer_c16_t CaptureProcessor::decim_0_execute(const buffer_c8_t& src, const buffer_c16_t& dst) { - switch (oversample_rate) { - case OversampleRate::x8: // we can get /8 by two means , decim0 (/4) + decim1 (/2) . or just decim0 (/8) - if (baseband_fs < 4800'000) { // 600khz (600k x 8) - return decim_0_4.execute(src, dst); // decim_0 , /4 with double decim stage - } else { - return decim_0_8_180k.execute(src, dst); // decim_0 /8 with single decim stage - } - - case OversampleRate::x16: - return decim_0_8.execute(src, dst); // decim_0 , /8 with double decim stage - - case OversampleRate::x32: - return decim_0_4.execute(src, dst); // decim_0 , /4 with double decim stage - - case OversampleRate::x64: - return decim_0_8.execute(src, dst); // decim_0 , /8 with double decim stage - - default: - chDbgPanic("Unhandled OversampleRate"); - return {}; - } -} - -buffer_c16_t CaptureProcessor::decim_1_execute(const buffer_c16_t& src, const buffer_c16_t& dst) { - switch (oversample_rate) { - case OversampleRate::x8: // we can get /8 by two means , decim0 (/4) + decim1 (/2) . or just decim0 (/8) - if (baseband_fs < 4800'000) { // 600khz (600k x 8) - return decim_1_2.execute(src, dst); - } else { - return src; - } - - case OversampleRate::x16: - return decim_1_2.execute(src, dst); // total decim /16 = /8x2, applied to 100khz and 150khz - - case OversampleRate::x32: - return decim_1_8.execute(src, dst); // total decim /32 = /4x8, appled to 75k , 50k, 32k - - case OversampleRate::x64: - return decim_1_8.execute(src, dst); // total decim /64 = /8x8, appled to 16k and 12k5 - - default: - chDbgPanic("Unhandled OversampleRate"); - return {}; - } } int main() { EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; -} +} \ No newline at end of file diff --git a/firmware/baseband/proc_capture.hpp b/firmware/baseband/proc_capture.hpp index 38cf206d..de51e23c 100644 --- a/firmware/baseband/proc_capture.hpp +++ b/firmware/baseband/proc_capture.hpp @@ -33,6 +33,56 @@ #include #include +#include +#include + +/* A decimator that just returns the source buffer. */ +class NoopDecim { + public: + static constexpr int decimation_factor = 1; + + template + Buffer execute(const Buffer& src, const Buffer&) { + // TODO: should this copy to 'dst'? + return {src.p, src.count, src.sampling_rate}; + } +}; + +/* Decimator wrapper that can hold one of a set of decimators and dispatch at runtime. */ +template +class MultiDecimator { + public: + /* Dispatches to the underlying type's execute. */ + template + Destination execute( + const Source& src, + const Destination& dst) { + return std::visit( + [&src, &dst](auto&& arg) -> Destination { + return arg.execute(src, dst); + }, + decimator_); + } + + size_t decimation_factor() const { + return std::visit( + [](auto&& arg) -> size_t { + return arg.decimation_factor; + }, + decimator_); + } + + /* Sets this decimator to a new instance of the specified decimator type. + * NB: The instance is returned by-ref so 'configure' can easily be called. */ + template + Decimator& set() { + decimator_ = Decimator{}; + return std::get(decimator_); + } + + private: + std::variant decimator_{}; +}; class CaptureProcessor : public BasebandProcessor { public: @@ -50,15 +100,16 @@ class CaptureProcessor : public BasebandProcessor { dst.data(), dst.size()}; - /* NB: There are two decimation passes: 0 and 1. In pass 0, one of - * the following will be selected based on the oversample rate. - * use decim_0_4 for an overall decimation factor of 8. - * use decim_0_8 for an overall decimation factor of 16. */ - dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0_4{}; - dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_8{}; - dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_8_180k{}; - dsp::decimate::FIRC16xR16x16Decim2 decim_1_2{}; - dsp::decimate::FIRC16xR16x32Decim8 decim_1_8{}; + /* The actual type will be configured depending on the sample rate. */ + MultiDecimator< + dsp::decimate::FIRC8xR16x24FS4Decim4, + dsp::decimate::FIRC8xR16x24FS4Decim8> + decim_0{}; + MultiDecimator< + dsp::decimate::FIRC16xR16x16Decim2, + dsp::decimate::FIRC16xR16x32Decim8, + NoopDecim> + decim_1{}; int32_t channel_filter_low_f = 0; int32_t channel_filter_high_f = 0; @@ -69,7 +120,6 @@ class CaptureProcessor : public BasebandProcessor { SpectrumCollector channel_spectrum{}; size_t spectrum_interval_samples = 0; size_t spectrum_samples = 0; - OversampleRate oversample_rate{OversampleRate::x8}; /* NB: Threads should be the last members in the class definition. */ BasebandThread baseband_thread{ @@ -78,12 +128,6 @@ class CaptureProcessor : public BasebandProcessor { void sample_rate_config(const SampleRateConfigMessage& message); void capture_config(const CaptureConfigMessage& message); - - /* Dispatch to the correct decim_0 based on oversample rate. */ - buffer_c16_t decim_0_execute(const buffer_c8_t& src, const buffer_c16_t& dst); - - /* Dispatch to the correct decim_1 based on oversample rate. */ - buffer_c16_t decim_1_execute(const buffer_c16_t& src, const buffer_c16_t& dst); }; #endif /*__PROC_CAPTURE_HPP__*/ diff --git a/firmware/baseband/proc_replay.cpp b/firmware/baseband/proc_replay.cpp index 7df2cb47..e6e9d5a8 100644 --- a/firmware/baseband/proc_replay.cpp +++ b/firmware/baseband/proc_replay.cpp @@ -69,7 +69,7 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) { chDbgPanic("Output not div."); // Is the input smaple buffer big enough? - if (samples_to_read > iq_buffer.size()) + if (samples_to_read > iq_buffer.count) chDbgPanic("IQ buf ovf."); #endif diff --git a/firmware/baseband/proc_replay.hpp b/firmware/baseband/proc_replay.hpp index 885946dd..e2852c07 100644 --- a/firmware/baseband/proc_replay.hpp +++ b/firmware/baseband/proc_replay.hpp @@ -45,7 +45,7 @@ class ReplayProcessor : public BasebandProcessor { static constexpr auto spectrum_rate_hz = 50.0f; // Holds the read IQ data chunk from the file to send. - std::array iq{}; + std::array iq{}; int32_t channel_filter_low_f = 0; int32_t channel_filter_high_f = 0; diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index d80cb4f2..625747be 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -816,8 +816,8 @@ enum class OversampleRate : uint8_t { None = 1, x1 = None, - // 4x would make sense to have, but need to ensure it doesn't - // overrun the IQ read buffer in proc_replay. + /* Oversample rate of 4 times the sample rate. */ + x4 = 4, /* Oversample rate of 8 times the sample rate. */ x8 = 8, @@ -830,9 +830,6 @@ enum class OversampleRate : uint8_t { /* Oversample rate of 64 times the sample rate. */ x64 = 64, - - /* Oversample rate of 128 times the sample rate. */ - x128 = 128, }; class SampleRateConfigMessage : public Message { diff --git a/firmware/common/oversample.hpp b/firmware/common/oversample.hpp index 45186f72..586787d4 100644 --- a/firmware/common/oversample.hpp +++ b/firmware/common/oversample.hpp @@ -42,26 +42,27 @@ * In testing, a minimum rate of 400kHz seems to the functional minimum. * * There are several different concepts or terms related to Capture and Replay, - * (1) oversampling (x8, x16 ,...) / decimation (/8, /16...) - * In Capture App , when ADC can not handle directly a requiered low sample rates , - * we need to apply oversampling (x8. x16 ex) , getting more real samples than needed) by "x_number" , - * and later to write it to SD card with the proper needed real sample rate , we apply Decimation , "/ number" . + * (1) Oversampling (x8, x16, ...) and Decimation (/8, /16...) + * In Capture App, the ADC can not directly handle low sample rates. + * We need to apply oversampling (x8, x16, ...), collecting more "x number" additional real samples. + * To write it to SD card with the desired sample rate, we apply Decimation ("/ number"). * - * (2) up-sampling or re-escale or interpolation. (x8, x16, ...) - * In Replay-list App, when we got too low bit rate data for Hackrf , - * we need to upsampling or interpolate or resampling to increase those low bit rates - * to a proper sample rate higher than the min. to be able to be transmitted by Hackrf. + * (2) Up-sampling or re-scale or interpolation. (x8, x16, ...). + * In Replay-list App, when the bit rate data is too low for HackRF. + * We need to upsample or interpolate to increase those low bit rates + * to a rate higher than the hardware nminimum to be transmitted by Hackrf. */ /* Gets the oversample rate for a given sample rate. * The oversample rate is used to increase the sample rate to improve SNR and quality. * This is also used as the interpolation rate when replaying captures. */ inline OversampleRate get_oversample_rate(uint32_t sample_rate) { - if (sample_rate < 30'000) return OversampleRate::x64; // 25k, 16k, 12k5. - if (sample_rate < 80'000) return OversampleRate::x32; // 75k, 50k, 32k. - if (sample_rate < 250'000) return OversampleRate::x16; // 100k and 150k. + if (sample_rate < 30'000) return OversampleRate::x64; // 25k, 16k, 12k5. + if (sample_rate < 80'000) return OversampleRate::x32; // 75k, 50k, 32k. + if (sample_rate < 250'000) return OversampleRate::x16; // 100k, 150k. + if (sample_rate < 1'250'000) return OversampleRate::x8; // 250k, 500k, 600k, 650k, 750k, 1Mhz. - return OversampleRate::x8; // 250k .. 1Mhz, that decim x8 , is already applied.(OVerSampling and decim OK) + return OversampleRate::x4; // Top range (1.25Mhz ... 5.5Mhz). } /* Gets the actual sample rate for a given sample rate.