Source code for piel.visual.plot.signals.frequency.two_port

from typing import Optional, Tuple
import numpy as np

import piel.types.units
from piel.types import NetworkTransmission
from piel.visual.plot.core import save
from piel.visual.plot.basic import plot_simple
from piel.visual.plot.position import create_axes_per_figure
import matplotlib.figure as mpl_fig
import matplotlib.axes as mpl_axes
import logging

logger = logging.getLogger(__name__)


[docs] def plot_s21_gain_per_input_power_dBm( network_transmission: NetworkTransmission, fig: Optional[mpl_fig.Figure] = None, axs: Optional[mpl_axes.Axes] = None, label: Optional[str] = None, xlabel: str = None, ylabel: str = None, **kwargs, ) -> tuple[mpl_fig.Figure, mpl_axes.Axes]: """ Plots input power (p_in_dbm) vs S21 gain (s_21_db) from a NetworkTransmission object. Parameters: ----------- frequency_array_state : NetworkTransmission The NetworkTransmission object containing the measurement data. fig : matplotlib.figure.Figure, optional The figure object to plot on. If None, a new figure is created. axs : matplotlib.axes.Axes, optional The axes object to plot on. If None, a new set of axes is created. label : str, optional The label for the plot. If None, a default label is used. Returns: -------- tuple A tuple containing the matplotlib Figure and Axes objects. """ # Create axes if not provided if (fig is None) or (axs is None): fig, axs = create_axes_per_figure(rows=1, columns=1) if xlabel is None: xlabel = r"$P_{in}$ $dBm$" if ylabel is None: ylabel = r"$S_{21}$ $dB$" # Extract input power in dBm from ScalarSource.input.magnitude try: p_in_dbm = np.array(network_transmission.input.magnitude) except AttributeError as e: logger.error( f"Failed to extract 'p_in_dbm' from NetworkTransmission.input.phasor.magnitude: {network_transmission}" ) raise e # Initialize s_21_db as None s_21_db = None # Iterate through network transmissions to find S21 for path_transmission in network_transmission.network: if path_transmission.connection == ("in0", "out0"): # Compute magnitude in dB from complex transmission transmission = np.array(path_transmission.transmission.magnitude) # Avoid log of zero by adding a small epsilon # Convert if linear units # epsilon = 1e-12 # s_21_db = 20 * np.log10(np.abs(transmission) + epsilon) s_21_db = transmission break if s_21_db is None: logger.error( "S21 transmission ('in0', 'out0') not found in NetworkTransmission.network." ) raise ValueError("S21 transmission ('in0', 'out0') not found.") # Determine label plot_label = label if label is not None else "S21 Magnitude" # Plot the data fig, axs = plot_simple( p_in_dbm, s_21_db, fig=fig, axs=axs, xlabel=xlabel, ylabel=ylabel, label=plot_label, **kwargs, ) save(fig, **kwargs) return fig, axs
[docs] def plot_s11_magnitude_per_input_frequency( network_transmission: NetworkTransmission, fig: Optional[mpl_fig.Figure] = None, axs: Optional[mpl_axes.Axes] = None, label: str = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, **kwargs, ) -> Tuple[mpl_fig.Figure, mpl_axes.Axes]: """ Plots S11 magnitudes vs input power (P_in_dBm) from a NetworkTransmission object on the same axes. Parameters: ----------- network_transmission : NetworkTransmission The NetworkTransmission object containing the measurement data. fig : matplotlib.figure.Figure, optional The figure object to plot on. If None, a new figure is created. axs : matplotlib.axes.Axes, optional The axes object to plot on. If None, a new set of axes is created. labels : tuple of str, optional A tuple containing labels for S21 and S11 plots. If None, defaults to ("S21 Gain", "S11 Magnitude"). xlabel : str, optional The label for the x-axis. If None, defaults to "P_in dBm". ylabel : str, optional The label for the y-axis. If None, defaults to "Magnitude (dB)". **kwargs : Additional keyword arguments passed to the plot function. Returns: -------- tuple A tuple containing the matplotlib Figure and Axes objects. """ from piel.analysis.signals.frequency.core.extract import ( extract_two_port_network_transmission_to_dataframe, ) # Create axes if not provided if (fig is None) or (axs is None): fig, axs = create_axes_per_figure(rows=1, columns=1) # Set default labels if not provided if xlabel is None: xlabel = piel.types.units.GHz if ylabel is None: ylabel = piel.types.units.dB # Set default plot labels default_label = "S11 Magnitude" s11_label = label if label is not None else default_label dataframe = extract_two_port_network_transmission_to_dataframe(network_transmission) f_in_Hz = dataframe.frequency_Hz s11_db = dataframe.s_11_magnitude_dBm # Plot S11 on the same axes fig, axs = plot_simple( f_in_Hz, s11_db, fig=fig, axs=[axs[0]], label=s11_label, xlabel=xlabel, ylabel=ylabel, **kwargs, ) # Add legend to distinguish S21 and S11 axs[0].legend(loc="lower right") # Save the figure if needed save(fig, **kwargs) return fig, axs
[docs] def plot_s21_magnitude_per_input_frequency( network_transmission: NetworkTransmission, fig: Optional[mpl_fig.Figure] = None, axs: Optional[mpl_axes.Axes] = None, label: Optional[Tuple[str, str]] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, **kwargs, ) -> Tuple[mpl_fig.Figure, mpl_axes.Axes]: """ Plots S21 and S11 magnitudes vs input power (P_in_dBm) from a NetworkTransmission object on the same axes. Parameters: ----------- network_transmission : NetworkTransmission The NetworkTransmission object containing the measurement data. fig : matplotlib.figure.Figure, optional The figure object to plot on. If None, a new figure is created. axs : matplotlib.axes.Axes, optional The axes object to plot on. If None, a new set of axes is created. labels : tuple of str, optional A tuple containing labels for S21 and S11 plots. If None, defaults to ("S21 Gain", "S11 Magnitude"). xlabel : str, optional The label for the x-axis. If None, defaults to "P_in dBm". ylabel : str, optional The label for the y-axis. If None, defaults to "Magnitude (dB)". **kwargs : Additional keyword arguments passed to the plot function. Returns: -------- tuple A tuple containing the matplotlib Figure and Axes objects. """ from piel.analysis.signals.frequency.core.extract import ( extract_two_port_network_transmission_to_dataframe, ) # Create axes if not provided if (fig is None) or (axs is None): fig, axs = create_axes_per_figure(rows=1, columns=1) # Set default labels if not provided if xlabel is None: xlabel = piel.types.units.GHz if ylabel is None: ylabel = piel.types.units.dB # Set default plot labels default_label = "S21 Magnitude" s21_label = label if label is not None else default_label dataframe = extract_two_port_network_transmission_to_dataframe(network_transmission) f_in_Hz = dataframe.frequency_Hz if kwargs.get("bug_patch", True): s21_db = ( dataframe.s_12_magnitude_dBm ) # TODO FIX THIS BUT HOW? Something is weird somewhere else: s21_db = dataframe.s_21_magnitude_dBm # Plot S21 fig, axs = plot_simple( f_in_Hz, s21_db, fig=fig, axs=[axs[0]], xlabel=xlabel, ylabel=ylabel, label=s21_label, **kwargs, ) # Add legend to distinguish S21 and S11 axs[0].legend(loc="lower right") # Save the figure if needed save(fig, **kwargs) return fig, axs
[docs] def plot_s11_s21_magnitude_per_input_frequency( network_transmission: NetworkTransmission, fig: Optional[mpl_fig.Figure] = None, axs: Optional[mpl_axes.Axes] = None, labels: Optional[Tuple[str, str]] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, **kwargs, ) -> Tuple[mpl_fig.Figure, mpl_axes.Axes]: """ Plots S21 and S11 magnitudes vs input power (P_in_dBm) from a NetworkTransmission object on the same axes. Parameters: ----------- network_transmission : NetworkTransmission The NetworkTransmission object containing the measurement data. fig : matplotlib.figure.Figure, optional The figure object to plot on. If None, a new figure is created. axs : matplotlib.axes.Axes, optional The axes object to plot on. If None, a new set of axes is created. labels : tuple of str, optional A tuple containing labels for S21 and S11 plots. If None, defaults to ("S21 Gain", "S11 Magnitude"). xlabel : str, optional The label for the x-axis. If None, defaults to "P_in dBm". ylabel : str, optional The label for the y-axis. If None, defaults to "Magnitude (dB)". **kwargs : Additional keyword arguments passed to the plot function. Returns: -------- tuple A tuple containing the matplotlib Figure and Axes objects. """ from piel.analysis.signals.frequency.core.extract import ( extract_two_port_network_transmission_to_dataframe, ) # Create axes if not provided if (fig is None) or (axs is None): fig, axs = create_axes_per_figure(rows=1, columns=1) # Set default labels if not provided if xlabel is None: xlabel = piel.types.units.GHz if ylabel is None: ylabel = piel.types.units.dB # Set default plot labels default_labels = ("S21 Magnitude", "S11 Magnitude") s21_label, s11_label = labels if labels is not None else default_labels dataframe = extract_two_port_network_transmission_to_dataframe(network_transmission) f_in_Hz = dataframe.frequency_Hz s11_db = dataframe.s_11_magnitude_dBm s21_db = dataframe.s_21_magnitude_dBm # Plot S11 on the same axes fig, axs = plot_simple( f_in_Hz, s11_db, fig=fig, axs=[axs[0]], label=s11_label, xlabel=xlabel, ylabel=ylabel, **kwargs, ) # Plot S21 fig, axs = plot_simple( f_in_Hz, s21_db, fig=fig, axs=[axs[0]], xlabel=xlabel, ylabel=ylabel, label=s21_label, **kwargs, ) # Add legend to distinguish S21 and S11 axs[0].legend(loc="lower right") # Save the figure if needed save(fig, **kwargs) return fig, axs