new do1_noise_subtract logic

This commit is contained in:
awe
2026-04-27 19:54:07 +03:00
parent 8175d1cba0
commit b9559cbe8c

View File

@ -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<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<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_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<double>(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<double>(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,