///|
/// Bit-level counters for a vector signal.
pub struct BitStatistics {
signal_id : String
bits : Int
zeros : Int
ones : Int
unknown : Int
high_impedance : Int
} derive(Debug, Eq)
///|
/// Count every observed bit in scalar and vector values.
pub fn bit_statistics(trace : Trace, signal_id : String) -> BitStatistics {
let mut bits = 0
let mut zeros = 0
let mut ones = 0
let mut unknown = 0
let mut high_impedance = 0
for change in signal_changes(trace, signal_id) {
let text = change.value.bits()
for bit in text {
bits += 1
match bit {
Zero => zeros += 1
One => ones += 1
Unknown => unknown += 1
HighImpedance => high_impedance += 1
}
}
}
{ signal_id, bits, zeros, ones, unknown, high_impedance }
}
///|
/// Return the fraction of observed bits that are one.
pub fn one_bit_ratio(stats : BitStatistics) -> Double {
if stats.bits == 0 {
0.0
} else {
stats.ones.to_double() / stats.bits.to_double()
}
}
///|
/// Return the fraction of observed bits that are unknown or high impedance.
pub fn uncertain_bit_ratio(stats : BitStatistics) -> Double {
if stats.bits == 0 {
0.0
} else {
(stats.unknown + stats.high_impedance).to_double() / stats.bits.to_double()
}
}
///|
/// Return the first occurrence of each distinct value token.
pub fn distinct_value_tokens(
trace : Trace,
signal_id : String,
) -> Array[String] {
let result : Array[String] = []
for change in signal_changes(trace, signal_id) {
let token = canonical_value_text(change.value)
if !result.contains(token) {
result.push(token)
}
}
result
}
///|
/// Return run lengths for consecutive equal values.
pub fn value_run_lengths(
trace : Trace,
signal_id : String,
) -> Array[(String, Int)] {
let result : Array[(String, Int)] = []
let mut previous : String? = None
let mut length = 0
for change in signal_changes(trace, signal_id) {
let token = canonical_value_text(change.value)
match previous {
Some(value) if value == token => length += 1
Some(value) => {
result.push((value, length))
previous = Some(token)
length = 1
}
None => {
previous = Some(token)
length = 1
}
}
}
match previous {
Some(value) => result.push((value, length))
None => ()
}
result
}
///|
/// Return the longest stable run of one value token.
pub fn longest_value_run(trace : Trace, signal_id : String) -> (String, Int) {
let mut best = ("", 0)
for item in value_run_lengths(trace, signal_id) {
if item.1 > best.1 {
best = item
}
}
best
}
///|
/// Return all scalar values in source order.
pub fn scalar_sequence(trace : Trace, signal_id : String) -> Array[Char] {
signal_changes(trace, signal_id).fold(init=[], fn(result, change) {
match change.value {
Scalar(value) => {
result.push(value)
result
}
_ => result
}
})
}
///|
/// Return the most common canonical value token.
pub fn dominant_value_token(trace : Trace, signal_id : String) -> String? {
let counts : Array[(String, Int)] = []
for token in distinct_value_tokens(trace, signal_id) {
counts.push(
(
token,
signal_changes(trace, signal_id).count_if(fn(change) {
canonical_value_text(change.value) == token
}),
),
)
}
let mut best : (String, Int)? = None
for item in counts {
match best {
Some(current) if current.1 >= item.1 => ()
_ => best = Some(item)
}
}
match best {
Some(item) => Some(item.0)
None => None
}
}
///|
/// Render bit statistics as a stable line.
pub fn bit_statistics_line(stats : BitStatistics) -> String {
"signal=" +
stats.signal_id +
" bits=" +
stats.bits.to_string() +
" zero=" +
stats.zeros.to_string() +
" one=" +
stats.ones.to_string() +
" x=" +
stats.unknown.to_string() +
" z=" +
stats.high_impedance.to_string()
}
///|
/// Render bit statistics as JSON.
pub fn bit_statistics_json(stats : BitStatistics) -> String {
"{\"signal_id\":\"" +
escape_text(stats.signal_id) +
"\",\"bits\":" +
stats.bits.to_string() +
",\"zeros\":" +
stats.zeros.to_string() +
",\"ones\":" +
stats.ones.to_string() +
",\"unknown\":" +
stats.unknown.to_string() +
",\"high_impedance\":" +
stats.high_impedance.to_string() +
"}"
}