Source code for piel.visual.table.electronic.metrics
from typing import Optional, Union, Set, List, Dict
from piel.types import RFAmplifierCollection, ComponentMetrics, ScalarMetric
from piel.visual.table.latex import escape_latex
default_metric_header_map = {
"bandwidth_Hz": r"\textbf{Bandwidth} (GHz)",
"power_consumption_mW": r"\textbf{Power} (mW)",
"power_gain_dB": r"\textbf{Power Gain} (dB)",
"supply_voltage_V": r"\textbf{Supply Voltage} (V)",
"noise_figure": r"\textbf{Minimum Noise Figure} (dB)",
"power_added_efficiency": r"\textbf{Power Added Efficiency} (%)",
"saturated_power_output_dBm": r"\textbf{Saturated Power Output} (dBm)",
"technology_nm": r"\textbf{CMOS Node}",
"footprint_mm2": r"\textbf{Footprint} ($mm^2$)",
"technology_material": r"\textbf{Technology Material}",
# Add more mappings as needed
}
# Function to format metric values
[docs]
def format_amplifier_metric(metric: str, metric_obj: Optional[ScalarMetric]) -> str:
if isinstance(metric_obj, ScalarMetric):
min_val = getattr(metric_obj, "min", None)
max_val = getattr(metric_obj, "max", None)
if min_val is not None and max_val is not None:
if min_val == max_val:
value = f"{min_val}"
else:
value = f"{min_val} - {max_val}"
elif min_val is not None:
value = f"{min_val}"
else:
value = "N/A"
# Specific formatting based on metric type
try:
if metric == "bandwidth_Hz":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val / 1e9:.2f}"
else:
value = f"{min_val / 1e9:.2f} - {max_val / 1e9:.2f}"
elif metric == "technology_nm":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{int(min_val)}nm"
else:
value = f"{int(min_val)} - {int(max_val)}nm"
elif metric == "saturated_power_output_dBm":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val:.2f}"
else:
value = f"{min_val:.2f} - {max_val:.2f}"
elif metric == "power_added_efficiency":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val:.1f}"
else:
value = f"{min_val:.1f} - {max_val:.1f}"
elif metric == "footprint_mm2":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val:.3f}"
else:
value = f"{min_val:.3f} - {max_val:.3f}"
elif metric == "power_gain_dB":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val:.2f}"
else:
value = f"{min_val:.2f} - {max_val:.2f}"
elif metric == "power_consumption_mW":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val:.2f}"
else:
value = f"{min_val:.2f} - {max_val:.2f}"
elif metric == "supply_voltage_V":
min_val = float(getattr(metric_obj, "min", 0))
max_val = float(getattr(metric_obj, "max", 0))
if min_val == max_val:
value = f"{min_val:.2f}"
else:
value = f"{min_val:.2f} - {max_val:.2f}"
# Add more specific formatting as needed
except (ValueError, TypeError):
value = "N/A"
else:
# For non-ScalarMetric or missing metrics
if metric_obj is not None:
value = str(metric_obj)
else:
value = "N/A"
# Escape LaTeX special characters
if isinstance(value, str):
value = escape_latex(value)
return value
[docs]
def compose_amplifier_collection_performance_latex_table(
amplifier_collection: RFAmplifierCollection,
desired_metrics: Union[List[str], str] = "*",
caption: str = "Compiled electronic performance available from the best CMOS LNA and PA literature for successful low-noise and power amplification.",
label: str = "table:amplifier_designs_review",
metrics_header_map: Dict[str, str] = default_metric_header_map,
) -> str:
"""
Composes performance parameters of amplifiers into a LaTeX table,
handling multiple metrics instances per component.
Args:
amplifier_collection (RFAmplifierCollection): The collection of RF amplifiers.
desired_metrics (List[str] or "*"): List of metric names to include in the table or "*" to include all metrics.
caption (str): The caption for the LaTeX table.
label (str): The label for referencing the table in LaTeX.
metrics_header_map (Dict[str, str]): Mapping from metric names to LaTeX-formatted headers.
Returns:
str: A string containing the LaTeX code for the table.
"""
# Collect all unique metrics if desired_metrics is "*"
if desired_metrics == "*":
all_metrics: Set[str] = set()
for component in amplifier_collection.components:
metrics_list: List[ComponentMetrics] = getattr(component, "metrics", [])
for metrics in metrics_list:
for attr in dir(metrics):
if not attr.startswith("_"):
attr_value = getattr(metrics, attr)
if isinstance(attr_value, ScalarMetric) or isinstance(
attr_value, str
):
all_metrics.add(attr)
desired_metrics_list = sorted(all_metrics)
else:
desired_metrics_list = desired_metrics
# Update metric_headers with any new metrics not predefined
for metric in desired_metrics_list:
if metric not in metrics_header_map:
# Generate a LaTeX-friendly header by splitting camelCase or snake_case
# Example: 'saturated_power_output_dBm' -> 'Saturated Power Output (dBm)'
parts = metric.split("_")
if parts[-1].lower() in ["hz", "dbm", "mw", "v", "nm", "mm2"]:
unit = parts[-1]
header = (
" ".join([part.capitalize() for part in parts[:-1]])
+ f" ({unit.upper()})"
)
else:
header = " ".join([part.capitalize() for part in parts])
metrics_header_map[metric] = rf"\textbf{{{header}}}"
# Initialize LaTeX table string
# Define column format: one for citation, one for metrics instance, and the rest for metrics
column_format = "|l|l|" + "X|" * len(desired_metrics_list)
latex_table = (
r"""\begin{center}
\begin{table}[h!]
\centering
\makebox[\textwidth]{%
\begin{tabularx}{\textwidth}{"""
+ column_format
+ r"""}
\hline
\textbf{Citation} & \textbf{Metrics Instance} & """
+ " & ".join(
[metrics_header_map.get(metric, metric) for metric in desired_metrics_list]
)
+ r""" \\
\hline
"""
)
# Iterate over each amplifier component to populate table rows
for comp_idx, component in enumerate(amplifier_collection.components, start=1):
metrics_list: List[ComponentMetrics] = getattr(component, "metrics", [])
if not metrics_list:
# If no metrics are present, add a single row with Metrics Instance as "N/A"
citation = "N/A"
# Attempt to retrieve the BibTeX key from component or its metrics
reference = None
if hasattr(component, "metrics") and component.metrics:
reference = getattr(component.metrics[0], "reference", None)
if reference and hasattr(reference, "bibtex_id") and reference.bibtex_id:
citation = f"\\cite{{{escape_latex(reference.bibtex_id)}}}"
elif hasattr(component, "name") and component.name:
citation = f"\\cite{{{escape_latex(component.name)}}}"
row = f"{citation} & N/A & "
row_entries = ["N/A"] * len(desired_metrics_list)
row += " & ".join(row_entries) + r" \\" + "\n" + r"\hline" + "\n"
latex_table += row
continue
for metric_idx, metrics in enumerate(metrics_list, start=1):
# Retrieve the citation
citation = "N/A"
reference = getattr(metrics, "reference", None)
if reference and hasattr(reference, "bibtex_id") and reference.bibtex_id:
citation = f"\\cite{{{escape_latex(reference.bibtex_id)}}}"
elif hasattr(component, "name") and component.name:
citation = f"\\cite{{{escape_latex(component.name)}}}"
# Start the row with citation and metrics instance
row = f"{citation} & {metric_idx} & "
row_entries = []
for metric in desired_metrics_list:
metric_obj = getattr(metrics, metric, None)
entry = format_amplifier_metric(metric, metric_obj)
row_entries.append(entry)
row += " & ".join(row_entries) + r" \\" + "\n" + r"\hline" + "\n"
latex_table += row
# Close the tabularx and table environments
latex_table += (
r""" \end{tabularx}%
}
\caption{"""
+ caption
+ r"""}
\label{"""
+ label
+ r"""}
\end{table}
\end{center}
"""
)
return latex_table