mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Extend REC low bit rate bandwith options in Capture App till 75khz (#1380)
* working_x32_Capture_till_75Khz * format issues * apply better accurate comments * auto format issues
This commit is contained in:
parent
e1cc0b1ad0
commit
12dbf957b3
@ -78,6 +78,7 @@ options_t freqman_bandwidths[4] = {
|
|||||||
{"16k", 16000},
|
{"16k", 16000},
|
||||||
{"25k", 25000},
|
{"25k", 25000},
|
||||||
{"50k", 50000},
|
{"50k", 50000},
|
||||||
|
{"75k", 75000},
|
||||||
{"100k", 100000},
|
{"100k", 100000},
|
||||||
{"150k", 150000},
|
{"150k", 150000},
|
||||||
{"250k", 250000},
|
{"250k", 250000},
|
||||||
|
@ -383,7 +383,7 @@ void WaterfallView::on_audio_spectrum() {
|
|||||||
// TODO: Comments below refer to a fixed oversample rate (8x), cleanup.
|
// TODO: Comments below refer to a fixed oversample rate (8x), cleanup.
|
||||||
uint32_t filter_bandwidth_for_sampling_rate(int32_t sampling_rate) {
|
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.
|
switch (sampling_rate) { // Use the var fs (sampling_rate) to set up BPF aprox < fs_max / 2 by Nyquist theorem.
|
||||||
case 0 ... 3'000'000: // BW Captured range (0 <= 250kHz max) fs = 8 x 250 kHz., 16 x 150 khz, 32 x 75 khz, , 64 x 40 khz
|
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)
|
||||||
return 1'750'000; // Minimum BPF MAX2837 for all those lower BW options.
|
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 ... 6'000'000: // BW capture range (500k...750kHz max) fs_max = 8 x 750kHz = 6Mhz
|
||||||
|
@ -145,11 +145,11 @@ OversampleRate RecordView::get_oversample_rate(uint32_t sample_rate) {
|
|||||||
|
|
||||||
auto rate = ::get_oversample_rate(sample_rate);
|
auto rate = ::get_oversample_rate(sample_rate);
|
||||||
|
|
||||||
// Currently proc_capture only supports x8 and x16 for decimation.
|
// Currently proc_capture only supports x8, x16, x32 for decimation.
|
||||||
if (rate < OversampleRate::x8)
|
if (rate < OversampleRate::x8) // clipping while x4 is not implemented yet.
|
||||||
rate = OversampleRate::x8;
|
rate = OversampleRate::x8;
|
||||||
else if (rate > OversampleRate::x16)
|
else if (rate > OversampleRate::x32) // clipping while x64 is not implemented yet .
|
||||||
rate = OversampleRate::x16;
|
rate = OversampleRate::x32;
|
||||||
|
|
||||||
return rate;
|
return rate;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@ CaptureProcessor::CaptureProcessor() {
|
|||||||
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.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_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.configure(taps_200k_decim_1.taps, 131072);
|
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);
|
channel_spectrum.set_decimation_factor(1);
|
||||||
baseband_thread.start();
|
baseband_thread.start();
|
||||||
@ -39,11 +40,16 @@ CaptureProcessor::CaptureProcessor() {
|
|||||||
|
|
||||||
void CaptureProcessor::execute(const buffer_c8_t& buffer) {
|
void CaptureProcessor::execute(const buffer_c8_t& buffer) {
|
||||||
/* 2.4576MHz, 2048 samples */
|
/* 2.4576MHz, 2048 samples */
|
||||||
const auto decim_0_out = decim_0_execute(buffer, dst_buffer); // selectable 3 possible decim_0, (/4. /8 200k soft transition filter , /8 180k sharp )
|
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
|
const auto decim_1_out = baseband_fs < 4800'000
|
||||||
? decim_1.execute(decim_0_out, dst_buffer) // < 600khz double decim. stage , means 500khz and lower bit rates.
|
? decim_1_2.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.
|
// ? 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& decimator_out = decim_1_out;
|
||||||
const auto& channel = decimator_out;
|
const auto& channel = decimator_out;
|
||||||
@ -91,13 +97,44 @@ void CaptureProcessor::sample_rate_config(const SampleRateConfigMessage& message
|
|||||||
|
|
||||||
baseband_thread.set_sampling_rate(baseband_fs);
|
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
|
auto decim_0_factor = oversample_rate == OversampleRate::x8
|
||||||
? decim_0_4.decimation_factor
|
? decim_0_4.decimation_factor
|
||||||
: decim_0_8.decimation_factor;
|
: decim_0_8.decimation_factor;
|
||||||
size_t decim_0_output_fs = baseband_fs / decim_0_factor;
|
|
||||||
|
|
||||||
|
size_t decim_0_output_fs = baseband_fs / decim_0_factor;
|
||||||
size_t decim_1_input_fs = decim_0_output_fs;
|
size_t decim_1_input_fs = decim_0_output_fs;
|
||||||
size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
|
|
||||||
|
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
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
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 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OversampleRate::x32:
|
||||||
|
decim_1_factor = 2 * decim_1_8.decimation_factor; // /x32 = /4x8 (we applied additional *2 correction to speed up waterfall, no effect to scale spectrum)
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
decim_1_factor = 2; // just default initial value to remove compile warning.
|
||||||
|
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_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_high_f = taps_200k_decim_1.high_frequency_normalized * decim_1_input_fs;
|
||||||
@ -117,15 +154,39 @@ void CaptureProcessor::capture_config(const CaptureConfigMessage& message) {
|
|||||||
|
|
||||||
buffer_c16_t CaptureProcessor::decim_0_execute(const buffer_c8_t& src, const buffer_c16_t& dst) {
|
buffer_c16_t CaptureProcessor::decim_0_execute(const buffer_c8_t& src, const buffer_c16_t& dst) {
|
||||||
switch (oversample_rate) {
|
switch (oversample_rate) {
|
||||||
case OversampleRate::x8: // we can get /8 by two means , decim0 (:4) + decim1 (:2) . or just decim0 (;8)
|
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)
|
if (baseband_fs < 4800'000) { // 600khz (600k x 8)
|
||||||
return decim_0_4.execute(src, dst); // decim_0 /4 with double decim stage
|
return decim_0_4.execute(src, dst); // decim_0 , /4 with double decim stage
|
||||||
} else {
|
} else {
|
||||||
return decim_0_8_180k.execute(src, dst); // decim_0 /8 with single decim stage
|
return decim_0_8_180k.execute(src, dst); // decim_0 /8 with single decim stage
|
||||||
}
|
}
|
||||||
|
|
||||||
case OversampleRate::x16:
|
case OversampleRate::x16:
|
||||||
return decim_0_8.execute(src, dst);
|
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
|
||||||
|
|
||||||
|
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 150khz
|
||||||
|
|
||||||
|
case OversampleRate::x32:
|
||||||
|
return decim_1_8.execute(src, dst); // total decim /32 = /4x8, appled to <= 100khz , 75k with margin ,(50k, 25k, 12k5 now also) ...
|
||||||
|
|
||||||
default:
|
default:
|
||||||
chDbgPanic("Unhandled OversampleRate");
|
chDbgPanic("Unhandled OversampleRate");
|
||||||
|
@ -57,7 +57,8 @@ class CaptureProcessor : public BasebandProcessor {
|
|||||||
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0_4{};
|
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0_4{};
|
||||||
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_8{};
|
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_8{};
|
||||||
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_8_180k{};
|
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_8_180k{};
|
||||||
dsp::decimate::FIRC16xR16x16Decim2 decim_1{};
|
dsp::decimate::FIRC16xR16x16Decim2 decim_1_2{};
|
||||||
|
dsp::decimate::FIRC16xR16x32Decim8 decim_1_8{};
|
||||||
|
|
||||||
int32_t channel_filter_low_f = 0;
|
int32_t channel_filter_low_f = 0;
|
||||||
int32_t channel_filter_high_f = 0;
|
int32_t channel_filter_high_f = 0;
|
||||||
@ -80,6 +81,9 @@ class CaptureProcessor : public BasebandProcessor {
|
|||||||
|
|
||||||
/* Dispatch to the correct decim_0 based on oversample rate. */
|
/* 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);
|
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__*/
|
#endif /*__PROC_CAPTURE_HPP__*/
|
||||||
|
@ -40,17 +40,29 @@
|
|||||||
* The baseband needs to know how to correctly decimate (or interpolate) so
|
* The baseband needs to know how to correctly decimate (or interpolate) so
|
||||||
* the set of allowed scalars is fixed (See OversampleRate enum).
|
* the set of allowed scalars is fixed (See OversampleRate enum).
|
||||||
* In testing, a minimum rate of 400kHz seems to the functional minimum.
|
* 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" .
|
||||||
|
*
|
||||||
|
* (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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Gets the oversample rate for a given sample rate.
|
/* Gets the oversample rate for a given sample rate.
|
||||||
* The oversample rate is used to increase the sample rate to improve SNR and quality.
|
* 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. */
|
* This is also used as the interpolation rate when replaying captures. */
|
||||||
inline OversampleRate get_oversample_rate(uint32_t sample_rate) {
|
inline OversampleRate get_oversample_rate(uint32_t sample_rate) {
|
||||||
if (sample_rate < 50'000) return OversampleRate::x128; // 25kk..12k5, prepared for future, OVS ok, but decim. :128 still not implemented.
|
if (sample_rate < 50'000) return OversampleRate::x128; // 25k..12k5, prepared for future, OVS ok, but decim. x128 still not implemented.
|
||||||
if (sample_rate < 100'000) return OversampleRate::x64; // 50k, prepared for future, OVS ok, but decim. :64 still not implemented.
|
if (sample_rate < 100'000) return OversampleRate::x64; // 50k, prepared for future, OVS ok, but decim. x64 still not implemented.
|
||||||
if (sample_rate < 250'000) return OversampleRate::x16; // Now tentatively applied to 150k..100k - but as soon as we got decim :32, (150k x16, and 100k x32)
|
if (sample_rate < 150'000) return OversampleRate::x32; // 100k needs x32
|
||||||
|
if (sample_rate < 250'000) return OversampleRate::x16; // 150k needs x16
|
||||||
|
|
||||||
return OversampleRate::x8; // 250k .. 1Mhz, that decim :8 , is already applied.(OVS and decim OK)
|
return OversampleRate::x8; // 250k .. 1Mhz, that decim x8 , is already applied.(OVerSampling and decim OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets the actual sample rate for a given sample rate.
|
/* Gets the actual sample rate for a given sample rate.
|
||||||
|
Loading…
Reference in New Issue
Block a user