new do1_noise_subtract logic
This commit is contained in:
80
main.cpp
80
main.cpp
@ -512,11 +512,11 @@ void print_help(const char* exe_name) {
|
|||||||
<< " DO1 outputs 00110011... continuously (toggle every 2 ADC ticks)\n"
|
<< " DO1 outputs 00110011... continuously (toggle every 2 ADC ticks)\n"
|
||||||
<< " without per-tick DOUT updates from PC\n"
|
<< " without per-tick DOUT updates from PC\n"
|
||||||
<< " do1_noise_subtract -> with tty + do1_toggle_per_frame, use DI1 state from synchronous DIN\n"
|
<< " do1_noise_subtract -> with tty + do1_toggle_per_frame, use DI1 state from synchronous DIN\n"
|
||||||
<< " (expected DO1->DI1 loopback) to average recent noise steps and subtract it\n"
|
<< " (expected DO1->DI1 loopback) to take previous DI1=HIGH step as baseline and subtract it\n"
|
||||||
<< " from useful steps before tty output\n"
|
<< " from useful steps before tty output\n"
|
||||||
<< " (only corrected DO1=LOW steps are sent to tty)\n"
|
<< " (only corrected DO1=LOW steps are sent to tty)\n"
|
||||||
<< " noise_avg_steps:N -> number of recent DO1=HIGH noise steps per channel used as subtraction baseline\n"
|
<< " noise_avg_steps:N -> kept for compatibility in do1_noise_subtract mode (current baseline is previous HIGH step)\n"
|
||||||
<< " (required when do1_noise_subtract is enabled)\n"
|
<< " (still required when do1_noise_subtract is enabled)\n"
|
||||||
<< " tty fast stream-only modes -> di1_group_avg or do1_noise_subtract; skip CSV/SVG/live outputs\n"
|
<< " tty fast stream-only modes -> di1_group_avg or do1_noise_subtract; skip CSV/SVG/live outputs\n"
|
||||||
<< " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\n"
|
<< " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
@ -545,7 +545,7 @@ void print_help(const char* exe_name) {
|
|||||||
<< "For tty output, use di1_group_avg together with di1:trace to emit one averaged 4-word step\n"
|
<< "For tty output, use di1_group_avg together with di1:trace to emit one averaged 4-word step\n"
|
||||||
<< "per constant DI1 run while keeping the current ring-buffered binary frame format.\n"
|
<< "per constant DI1 run while keeping the current ring-buffered binary frame format.\n"
|
||||||
<< "For DO1 subtraction with loopback, use do1_toggle_per_frame + do1_noise_subtract + noise_avg_steps:N;\n"
|
<< "For DO1 subtraction with loopback, use do1_toggle_per_frame + do1_noise_subtract + noise_avg_steps:N;\n"
|
||||||
<< "DI1 from synchronous DIN is used as the actual DO1 state marker.\n"
|
<< "DI1 from synchronous DIN is used as the actual DO1 state marker, and each LOW step subtracts previous HIGH step.\n"
|
||||||
<< "Amplitude mode keeps the raw AD8317 voltage as captured on X1; no inversion is applied.\n"
|
<< "Amplitude mode keeps the raw AD8317 voltage as captured on X1; no inversion is applied.\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "Phase profile example:\n"
|
<< "Phase profile example:\n"
|
||||||
@ -1232,22 +1232,16 @@ struct TtyGroupAverageState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Do1NoiseSubtractState {
|
struct Do1NoiseSubtractState {
|
||||||
uint32_t noise_avg_steps = 0;
|
|
||||||
std::array<std::vector<double>, 2> noise_ring;
|
|
||||||
std::array<std::size_t, 2> noise_ring_head {};
|
|
||||||
std::array<std::size_t, 2> noise_ring_size {};
|
|
||||||
std::array<double, 2> noise_ring_sum {};
|
|
||||||
std::array<double, 2> step_sum {};
|
std::array<double, 2> step_sum {};
|
||||||
std::array<uint32_t, 2> step_count {};
|
std::array<uint32_t, 2> step_count {};
|
||||||
|
std::array<double, 2> last_high_avg {};
|
||||||
|
std::array<bool, 2> last_high_valid {};
|
||||||
bool step_level_initialized = false;
|
bool step_level_initialized = false;
|
||||||
bool step_di1_high = false;
|
bool step_di1_high = false;
|
||||||
uint16_t next_index = 1;
|
uint16_t next_index = 1;
|
||||||
|
|
||||||
void configure(uint32_t history_steps) {
|
void configure(uint32_t history_steps) {
|
||||||
noise_avg_steps = history_steps;
|
(void) history_steps;
|
||||||
for (auto& ring : noise_ring) {
|
|
||||||
ring.assign(noise_avg_steps, 0.0);
|
|
||||||
}
|
|
||||||
reset_packet();
|
reset_packet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,12 +1252,11 @@ struct Do1NoiseSubtractState {
|
|||||||
|
|
||||||
void reset_packet() {
|
void reset_packet() {
|
||||||
clear_step();
|
clear_step();
|
||||||
|
last_high_avg = {};
|
||||||
|
last_high_valid = {};
|
||||||
step_level_initialized = false;
|
step_level_initialized = false;
|
||||||
step_di1_high = false;
|
step_di1_high = false;
|
||||||
next_index = 1;
|
next_index = 1;
|
||||||
noise_ring_head = {};
|
|
||||||
noise_ring_size = {};
|
|
||||||
noise_ring_sum = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_new_step(bool di1_high) {
|
void start_new_step(bool di1_high) {
|
||||||
@ -1291,38 +1284,26 @@ struct Do1NoiseSubtractState {
|
|||||||
return step_sum[lch] / static_cast<double>(step_count[lch]);
|
return step_sum[lch] / static_cast<double>(step_count[lch]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_noise_average(uint32_t lch, double avg_value) {
|
void update_last_high(uint32_t lch, double avg_value) {
|
||||||
if ((noise_avg_steps == 0U) || (lch >= noise_ring.size())) {
|
if (lch >= last_high_avg.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
last_high_avg[lch] = avg_value;
|
||||||
auto& ring = noise_ring[lch];
|
last_high_valid[lch] = true;
|
||||||
auto& head = noise_ring_head[lch];
|
|
||||||
auto& size = noise_ring_size[lch];
|
|
||||||
auto& sum = noise_ring_sum[lch];
|
|
||||||
|
|
||||||
if (size < noise_avg_steps) {
|
|
||||||
ring[size] = avg_value;
|
|
||||||
sum += avg_value;
|
|
||||||
++size;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum -= ring[head];
|
|
||||||
ring[head] = avg_value;
|
|
||||||
sum += avg_value;
|
|
||||||
head = (head + 1U) % noise_avg_steps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double noise_baseline(uint32_t lch) const {
|
bool has_last_high(uint32_t lch) const {
|
||||||
if (lch >= noise_ring_size.size()) {
|
if (lch >= last_high_valid.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return last_high_valid[lch];
|
||||||
|
}
|
||||||
|
|
||||||
|
double last_high(uint32_t lch) const {
|
||||||
|
if (lch >= last_high_avg.size()) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
const std::size_t size = noise_ring_size[lch];
|
return last_high_avg[lch];
|
||||||
if (size == 0U) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
return noise_ring_sum[lch] / static_cast<double>(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish_step() { clear_step(); }
|
void finish_step() { clear_step(); }
|
||||||
@ -1885,21 +1866,28 @@ int run(const Config& cfg) {
|
|||||||
const double ch2_avg = (cfg.channel_count <= 1U) ? 0.0 : tty_do1_noise_state.step_average(1U);
|
const double ch2_avg = (cfg.channel_count <= 1U) ? 0.0 : tty_do1_noise_state.step_average(1U);
|
||||||
|
|
||||||
if (tty_do1_noise_state.step_di1_high) {
|
if (tty_do1_noise_state.step_di1_high) {
|
||||||
tty_do1_noise_state.push_noise_average(0U, ch1_avg);
|
tty_do1_noise_state.update_last_high(0U, ch1_avg);
|
||||||
if (cfg.channel_count > 1U) {
|
if (cfg.channel_count > 1U) {
|
||||||
tty_do1_noise_state.push_noise_average(1U, ch2_avg);
|
tty_do1_noise_state.update_last_high(1U, ch2_avg);
|
||||||
}
|
}
|
||||||
tty_do1_noise_state.finish_step();
|
tty_do1_noise_state.finish_step();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tty_do1_noise_state.has_last_high(0U) ||
|
||||||
|
((cfg.channel_count > 1U) && !tty_do1_noise_state.has_last_high(1U))) {
|
||||||
|
// Skip LOW output until the previous HIGH step baseline is available.
|
||||||
|
tty_do1_noise_state.finish_step();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (tty_do1_noise_state.next_index >= 0xFFFFU) {
|
if (tty_do1_noise_state.next_index >= 0xFFFFU) {
|
||||||
fail("TTY protocol step index overflow within packet");
|
fail("TTY protocol step index overflow within packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
const double ch1_corrected = ch1_avg - tty_do1_noise_state.noise_baseline(0U);
|
const double ch1_corrected = ch1_avg - tty_do1_noise_state.last_high(0U);
|
||||||
const double ch2_corrected =
|
const double ch2_corrected =
|
||||||
(cfg.channel_count <= 1U) ? 0.0 : (ch2_avg - tty_do1_noise_state.noise_baseline(1U));
|
(cfg.channel_count <= 1U) ? 0.0 : (ch2_avg - tty_do1_noise_state.last_high(1U));
|
||||||
|
|
||||||
append_tty_frame((cfg.profile == CaptureProfile::Amplitude) ? 0x001AU : 0x000AU,
|
append_tty_frame((cfg.profile == CaptureProfile::Amplitude) ? 0x001AU : 0x000AU,
|
||||||
tty_do1_noise_state.next_index,
|
tty_do1_noise_state.next_index,
|
||||||
|
|||||||
Reference in New Issue
Block a user