cabana: enhance message heatmap visualization (#34239)

* enhance message heatmap visualization

* TODO

* improve log_factor

* typo

* bit_flip_counts
pull/34215/head
Dean Lee 4 months ago committed by GitHub
parent 9c9b273a3e
commit 9f3c2f0a37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 44
      tools/cabana/binaryview.cc
  2. 11
      tools/cabana/streams/abstractstream.cc
  3. 2
      tools/cabana/streams/abstractstream.h

@ -292,10 +292,15 @@ void BinaryViewModel::updateItem(int row, int col, uint8_t val, const QColor &co
}
}
// TODO:
// 1. Detect instability through frequent bit flips and highlight stable bits to indicate steady signals.
// 2. Track message sequence and timestamps to understand how patterns evolve.
// 3. Identify time-based or periodic bit state changes to spot recurring patterns.
// 4. Support multiple time windows for short-term and long-term analysis, helping to observe changes in different time frames.
void BinaryViewModel::updateState() {
const auto &last_msg = can->lastMessage(msg_id);
const auto &binary = last_msg.dat;
// data size may changed.
// Handle size changes in binary data
if (binary.size() > row_count) {
beginInsertRows({}, row_count, binary.size() - 1);
row_count = binary.size();
@ -303,21 +308,36 @@ void BinaryViewModel::updateState() {
endInsertRows();
}
const double max_f = 255.0;
const double factor = 0.25;
const double scaler = max_f / log2(1.0 + factor);
for (int i = 0; i < binary.size(); ++i) {
// Find the maximum bit flip count across the message
uint32_t max_bit_flip_count = 1; // Default to 1 to avoid division by zero
for (const auto &row : last_msg.bit_flip_counts) {
for (auto count : row) {
max_bit_flip_count = std::max(max_bit_flip_count, count);
}
}
const double max_alpha = 255.0;
const double min_alpha_with_signal = 25.0; // Base alpha for small flip counts
const double min_alpha_no_signal = 10.0; // Base alpha for small flip counts for no signal bits
const double log_factor = 1.0 + 0.2; // Factor for logarithmic scaling
const double log_scaler = max_alpha / log2(log_factor * max_bit_flip_count);
for (size_t i = 0; i < binary.size(); ++i) {
for (int j = 0; j < 8; ++j) {
auto &item = items[i * column_count + j];
int val = ((binary[i] >> (7 - j)) & 1) != 0 ? 1 : 0;
// Bit update frequency based highlighting
double offset = !item.sigs.empty() ? 50 : 0;
auto n = last_msg.last_changes[i].bit_change_counts[j];
double min_f = n == 0 ? offset : offset + 25;
double alpha = std::clamp(offset + log2(1.0 + factor * (double)n / (double)last_msg.count) * scaler, min_f, max_f);
int bit_val = (binary[i] >> (7 - j)) & 1;
double alpha = item.sigs.empty() ? 0 : min_alpha_with_signal;
uint32_t flip_count = last_msg.bit_flip_counts[i][j];
if (flip_count > 0) {
double normalized_alpha = log2(1.0 + flip_count * log_factor) * log_scaler;
double min_alpha = item.sigs.empty() ? min_alpha_no_signal : min_alpha_with_signal;
alpha = std::clamp(normalized_alpha, min_alpha, max_alpha);
}
auto color = item.bg_color;
color.setAlpha(alpha);
updateItem(i, j, val, color);
updateItem(i, j, bit_val, color);
}
updateItem(i, 8, binary[i], last_msg.colors[i]);
}

@ -39,7 +39,7 @@ void AbstractStream::updateMasks() {
const int size = std::min(mask.size(), m.last_changes.size());
for (int i = 0; i < size; ++i) {
for (int j = 0; j < 8; ++j) {
if (((mask[i] >> (7 - j)) & 1) != 0) m.last_changes[i].bit_change_counts[j] = 0;
if (((mask[i] >> (7 - j)) & 1) != 0) m.bit_flip_counts[i][j] = 0;
}
}
}
@ -59,9 +59,12 @@ size_t AbstractStream::suppressHighlighted() {
if (dt < 2.0) {
last_change.suppressed = true;
}
last_change.bit_change_counts.fill(0);
cnt += last_change.suppressed;
}
for (auto &row_bit_flips : m.bit_flip_counts) {
row_bit_flips.fill(0);
}
}
return cnt;
}
@ -251,6 +254,7 @@ void CanData::compute(const MessageId &msg_id, const uint8_t *can_data, const in
dat.resize(size);
colors.assign(size, QColor(0, 0, 0, 0));
last_changes.resize(size);
bit_flip_counts.resize(size);
std::for_each(last_changes.begin(), last_changes.end(), [current_sec](auto &c) { c.ts = current_sec; });
} else {
constexpr int periodic_threshold = 10;
@ -282,10 +286,11 @@ void CanData::compute(const MessageId &msg_id, const uint8_t *can_data, const in
}
// Track bit level changes
auto &row_bit_flips = bit_flip_counts[i];
const uint8_t diff = (cur ^ last);
for (int bit = 0; bit < 8; bit++) {
if (diff & (1u << bit)) {
++last_change.bit_change_counts[7 - bit];
++row_bit_flips[7 - bit];
}
}

@ -33,9 +33,9 @@ struct CanData {
int delta = 0;
int same_delta_counter = 0;
bool suppressed = false;
std::array<uint32_t, 8> bit_change_counts;
};
std::vector<ByteLastChange> last_changes;
std::vector<std::array<uint32_t, 8>> bit_flip_counts;
double last_freq_update_ts = 0;
};

Loading…
Cancel
Save