diff --git a/main.cpp b/main.cpp index 1b727b3..219ea10 100644 --- a/main.cpp +++ b/main.cpp @@ -512,11 +512,11 @@ void print_help(const char* exe_name) { << " DO1 outputs 00110011... continuously (toggle every 2 ADC ticks)\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" - << " (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" << " (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" - << " (required when do1_noise_subtract is enabled)\n" + << " noise_avg_steps:N -> kept for compatibility in do1_noise_subtract mode (current baseline is previous HIGH step)\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" << " If sample_clock_hz is omitted together with clock:internal, the maximum ADC speed is used\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" << "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" - << "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" << "\n" << "Phase profile example:\n" @@ -1232,22 +1232,16 @@ struct TtyGroupAverageState { }; struct Do1NoiseSubtractState { - uint32_t noise_avg_steps = 0; - std::array, 2> noise_ring; - std::array noise_ring_head {}; - std::array noise_ring_size {}; - std::array noise_ring_sum {}; std::array step_sum {}; std::array step_count {}; + std::array last_high_avg {}; + std::array last_high_valid {}; bool step_level_initialized = false; bool step_di1_high = false; uint16_t next_index = 1; void configure(uint32_t history_steps) { - noise_avg_steps = history_steps; - for (auto& ring : noise_ring) { - ring.assign(noise_avg_steps, 0.0); - } + (void) history_steps; reset_packet(); } @@ -1258,12 +1252,11 @@ struct Do1NoiseSubtractState { void reset_packet() { clear_step(); + last_high_avg = {}; + last_high_valid = {}; step_level_initialized = false; step_di1_high = false; next_index = 1; - noise_ring_head = {}; - noise_ring_size = {}; - noise_ring_sum = {}; } void start_new_step(bool di1_high) { @@ -1291,38 +1284,26 @@ struct Do1NoiseSubtractState { return step_sum[lch] / static_cast(step_count[lch]); } - void push_noise_average(uint32_t lch, double avg_value) { - if ((noise_avg_steps == 0U) || (lch >= noise_ring.size())) { + void update_last_high(uint32_t lch, double avg_value) { + if (lch >= last_high_avg.size()) { return; } - - auto& ring = noise_ring[lch]; - 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; + last_high_avg[lch] = avg_value; + last_high_valid[lch] = true; } - double noise_baseline(uint32_t lch) const { - if (lch >= noise_ring_size.size()) { + bool has_last_high(uint32_t lch) const { + 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; } - const std::size_t size = noise_ring_size[lch]; - if (size == 0U) { - return 0.0; - } - return noise_ring_sum[lch] / static_cast(size); + return last_high_avg[lch]; } 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); 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) { - 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(); 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) { 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 = - (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, tty_do1_noise_state.next_index,