nibcq.EIS ========= .. py:class:: nibcq.EIS(device: nibcq._device.Device, test_parameters: EISTestParameters) Bases: :py:obj:`nibcq._acir.ACIR` Electrochemical Impedance Spectroscopy (EIS) measurement handler class. This class extends the ACIR class to provide multi-frequency impedance spectroscopy capabilities. EIS measurements characterize the frequency-dependent impedance behavior of electrochemical systems by sweeping across a range of frequencies and measuring the complex impedance at each point. EIS is a powerful technique for analyzing electrochemical processes, battery characterization, corrosion studies, and material property investigations. The class manages frequency sweeps, data collection across multiple frequencies, and provides methods for generating common EIS visualization formats like Nyquist and Bode plots. The class inherits all ACIR functionality for single-frequency measurements and extends it with frequency sweep management, multi-point data storage, and EIS-specific analysis capabilities. .. rubric:: Example >>> device = Device("PXIe-4139") >>> eis = EIS(device) >>> >>> # Configure frequency sweep >>> sweep_config = { ... 1000.0: FrequencySet(current_amplitude=0.1, number_of_periods=20), ... 100.0: FrequencySet(current_amplitude=0.1, number_of_periods=50) ... } >>> params = EISTestParameters(frequency_sweep_characteristics=sweep_config) >>> >>> # Run EIS measurement >>> results = eis.run(params, compensation) >>> print(f"Measured {len(results)} frequency points") .. py:property:: test_parameters :type: EISTestParameters Get the current EIS test parameters. Returns the EISTestParameters object containing all configuration settings for the EIS measurement including voltage limits, nominal voltage, compensation method, and frequency sweep characteristics. :returns: The current test parameters configuration :rtype: EISTestParameters .. rubric:: Examples >>> eis = EIS(device) >>> params = eis.test_parameters >>> print(params.voltage_limit_hi) 5.0 .. py:property:: current_frequency :type: float Get the current measurement frequency. Returns the frequency currently being used for measurements. This value changes during frequency sweeps as the EIS measurement progresses through different frequencies. :returns: The current frequency in Hz, or None if not set :rtype: float .. rubric:: Examples >>> eis.current_frequency = 1000.0 >>> print(eis.current_frequency) 1000.0 .. py:property:: frequency_list Get the frequency sweep frequencies as a descending sorted list. Returns all frequencies defined in the frequency sweep characteristics, sorted in descending order (highest to lowest frequency). This order is typically used in EIS measurements to start with high frequencies and sweep down to low frequencies. :returns: A list of frequencies in Hz, sorted in descending order :rtype: list[float] :raises ValueError: If frequency sweep characteristics are not set or empty .. rubric:: Examples >>> eis.frequency_list [1000.0, 500.0, 100.0, 50.0, 10.0] .. py:property:: result :type: Union[list[nibcq.measurement.SMUResult], list[tuple[nibcq.switch.SMUCellData, list[nibcq.measurement.SMUResult]]]] Get the result of the last EIS measurement. Returns the measurement result from the most recent measurement operation. The result type depends on whether switching was used or not. :returns: The measurement result(s). For switching measurements, returns a list of tuples where each tuple contains the cell data and its corresponding results. :rtype: list[SMUResult] | list[tuple[SMUCellData, list[SMUResult]]] :raises RuntimeError: If no measurement has been performed yet or if the result is not available .. py:method:: get_plots() -> tuple[PlotSeries, PlotSeries, PlotSeries] | list[tuple[PlotSeries, PlotSeries, PlotSeries]] Return plotting datasets for Nyquist and Bode plots. For single device measurements, returns a 3-tuple: - (nyquist_x, nyquist_y): Nyquist (Cole) data where nyquist_x is R and nyquist_y is -X (both lists of floats) sorted by ascending frequency. - (freqs, magnitudes): Bode magnitude data (frequency ascending, abs(Z)). - (freqs, phases): Bode phase data (frequency ascending, theta in degrees). For switching measurements, returns a list of 3-tuples, one for each cell. The method reads measurement results and sorts the returned points by frequency (ascending) to make plotting predictable for common plotting conventions. :raises RuntimeError: If no measurement results are available. .. py:method:: run(compensation: nibcq.compensation.Compensation, measurement_callback: Optional[Callable[[nibcq.measurement.SMUMeasurement], None]] = None) -> list[nibcq.measurement.SMUResult] Run the EIS process with the passed configuration parameters. Validates temperature if the compensation specifies a target temperature, and the device supports temperature measurement. Then performs a full frequency sweep as defined in the test parameters, measuring impedance at each frequency point. :param compensation: The compensation object to use for impedance correction :param measurement_callback: Optional callback function to call after each measurement cycle. One measurement cycle is a waveform generation and measurement done on a specific frequency. Pass your callback function here what you use to document the raw measurement data. It should have one input parameter, which is a SMUMeasurement object. :returns: A list of SMUResults, containing all of the results from the done measurements. :raises ValueError: If configuration parameters are invalid or would cause measurement errors. Also raised if temperature validation fails. :raises RuntimeError: If device configuration or measurement fails. :raises AttributeError: If frequency sweep characteristics are missing or improperly formatted. .. rubric:: Examples >>> params = EISTestParameters() >>> eis = EIS(device, params) >>> compensation = eis.load_compensation_file() >>> results = eis.run(compensation) .. py:method:: run_with_switching(compensation: nibcq.compensation.Compensation | list[nibcq.compensation.Compensation], measurement_callback: Optional[Callable[[nibcq.measurement.SMUMeasurement], None]] = None) Run complete EIS frequency sweeps across multiple DUTs using switch matrix configuration. This method performs comprehensive Electrochemical Impedance Spectroscopy measurements on multiple devices under test (DUTs) by automatically switching between different channels. For each connected DUT, it executes a complete frequency sweep as defined in the test parameters, collecting impedance data across the entire frequency range. The switching process ensures proper isolation between measurements, with automatic debounce timing for stable connections and complete disconnection between DUTs. This enables efficient multi-battery characterization, comparative electrochemical analysis, or production testing scenarios where multiple samples need identical frequency sweep measurements. Returns partial, already processed measurements, even if an error occurs during switching or measurement. Each DUT receives the same complete EIS treatment: frequency sweep from high to low frequencies, compensation application, and result collection. The method maintains measurement consistency across all DUTs while leveraging hardware switching for efficiency. :param compensation: The compensation object containing frequency-dependent error correction data for impedance accuracy improvement across all measurement frequencies in the sweep. This can be passed as a list of compensations, a different one for each cell. :type compensation: Compensation | list[Compensation] :param measurement_callback: Optional callback function invoked after each individual frequency measurement within each DUT's sweep. Receives the raw SMUMeasurement data for real-time monitoring, logging, or progress tracking. Called once per frequency per DUT. :type measurement_callback: Optional[Callable[[SMUMeasurement], None]] :returns: A list of tuples mapping each cell to its complete EIS measurement results. Each SMUCellData represents a DUT connection point, and the corresponding list[SMUResult] contains impedance measurements for all frequencies in the sweep, enabling complete frequency-domain analysis for each individual DUT. :rtype: list[tuple[SMUCellData, list[SMUResult]]] :raises RuntimeError: If switching capability is not enabled (call device.with_switching() first) or if no switch channels are configured in the switch matrix. :raises ValueError: If configuration parameters are invalid, would cause measurement errors across the frequency range, or if compensation list length doesn't match the number of DUTs. Also raised if temperature validation fails for any cell. :raises AttributeError: If frequency sweep characteristics are missing or improperly formatted in the test parameters. :raises Exception: If connection to any DUT fails during switching operations or if any frequency measurement fails during the sweep. .. rubric:: Examples >>> params = EISTestParameters() >>> eis = EIS(device, params) >>> compensation = eis.load_compensation_file() >>> results = eis.run_with_switching(compensation) .. note:: This method performs a complete frequency sweep for each DUT, which can be time-intensive for large frequency ranges or many DUTs. The measurement callback can be used to monitor progress and provide feedback during long measurement sequences. Switch timing includes automatic debounce delays for measurement stability, and proper disconnection is guaranteed even if exceptions occur. .. py:method:: write_compensation_file(compensation_file_path: Optional[str] = None, kit_file_path: Optional[str] = None, comment: Optional[str] = None, measurement_callback: Optional[Callable[[nibcq.measurement.SMUMeasurement], None]] = None) -> str Create a compensation file based on measurements at all frequencies in the sweep. :param compensation_file_path: Optional specific file path to write to. If None, generates path automatically. :type compensation_file_path: Optional[str] :param kit_file_path: Optional specific file path to the known impedance table. If None, no known impedance table is used. :type kit_file_path: Optional[str] :param comment: Optional comment to include in the compensation file. If None, no comment is included. :type comment: Optional[str] :returns: The path of the created compensation file. :rtype: str :raises ValueError: If parameters are invalid or compensation method does not support compensation files. :raises FileNotFoundError: If compensation file is required but not found. :raises RuntimeError: If device configuration or measurement fails. :raises NotImplementedError: If unsupported compensation method is specified. .. py:attribute:: DEVICE_FAMILY :type: Final[nibcq.enums.DeviceFamily] Device family for ACIR and similar measurement types. :type: DeviceFamily .. py:attribute:: FREQUENCY_LIMIT :type: Final[float] :value: 10000.0 Frequency limit for ACIR and similar measurement types. :type: float .. py:attribute:: CURRENT_LIMIT :type: Final[float] :value: 2.0 Current limit for ACIR and similar measurement types. :type: float .. py:method:: generate_compensation_file_path() -> str Generate compensation file path using current compensation method setting. :returns: The generated file path for compensation data, or None if no compensation is needed :rtype: str :raises NotImplementedError: If compensation_method is not supported by nibcq Python API :raises ValueError: If test parameters are not set .. py:property:: measurement_data :type: nibcq.measurement.SMUMeasurement Get the processed measurement data used for impedance calculations. Only allows measurement to be read, not access it directly. For frequencies > 60 Hz, sanitizes data by removing edge effects. Applies DC offset removal to ensure measurements start and end near zero. :returns: Sanitized measurement data containing tone frequency, voltage values, and current values :rtype: SMUMeasurement :raises ValueError: If no measurement data is available or measurement is incomplete .. py:property:: raw_data :type: nibcq.measurement.SMUMeasurement Get the raw measurement data read from the device. Only allows measurement to be read, not access it directly. Returns unprocessed data as captured from the device. :returns: Raw measurement data containing tone frequency, voltage values, and current values :rtype: SMUMeasurement :raises ValueError: If no measurement data is available or measurement is incomplete .. py:method:: validate_current_amplitude(current_amplitude: float) -> bool :staticmethod: Validate that the current amplitude is within acceptable limits. .. py:method:: load_compensation_file(file_path: Optional[str] = None) -> nibcq.compensation.Compensation Load compensation file based on compensation method and device serial number. Creates and returns a compensation object with the appropriate compensation data. For NO_COMPENSATION, creates a default compensation object. For other methods, loads compensation data from file. :param file_path: Optional specific file path to read from. If None, generates path automatically :type file_path: Optional[str] :returns: The loaded compensation object :rtype: Compensation :raises FileNotFoundError: If compensation file is not found and compensation is required :raises ValueError: If compensation file is invalid and compensation is required :raises NotImplementedError: If compensation method is not supported by the nibcq Python API .. py:property:: has_switch_capability :type: bool Check if the device has switch capability. :returns: True if switch capability is available, False otherwise .. py:method:: connect_channel(channel: SMUCellData) -> None Connect to a specific DUT channel using the device's switch capability. :param channel: SwitchChannel containing connection information :raises RuntimeError: If no switch capability is available .. py:method:: disconnect_all() -> None Disconnect all channels using the device's switch capability. :raises RuntimeError: If no switch capability is available .. py:method:: wait_for_debounce() -> None Wait for switch relays to settle using the device's switch capability. :raises RuntimeError: If no switch capability is available .. py:property:: switch_cells :type: List[str] | List[SMUCellData] Get the configured switch cells from the device. :returns: A list of DUT channel names or SMUCellData objects, which contain the DUT and switch channel information. .. py:property:: acceptable_temperature_delta :type: float Get the acceptable temperature delta for compensation validation. Returns the maximum allowed temperature difference from the device's temperature capability. This is a pass-through property that delegates to the underlying TemperatureCapability. :returns: The acceptable temperature delta in degrees, or NaN if no temperature capability :rtype: float .. rubric:: Examples >>> measurement = EIS(device) >>> measurement.acceptable_temperature_delta = 2.5 >>> delta = measurement.acceptable_temperature_delta .. py:property:: temperature :type: float Get the latest temperature reading from the device. :returns: The most recent temperature measurement, or NaN if no temperature capability .. py:property:: temperature_range :type: CenteredRange Get the latest temperature reading from the device, coupled with the user-set delta. :returns: A CenteredRange representing the most recent temperature measurement (NaN if not available), along with the acceptable temperature delta (NaN if not set). .. py:method:: measure_temperature() -> CenteredRange Get a new temperature reading from the device. :returns: Current temperature reading, or NaN if no temperature capability .. py:method:: validate_temperature(target_temperature: CenteredRange) -> bool Validate the current temperature against the compensation file's target. Delegates to the device's temperature capability for validation. The capability handles all validation logic including checking if thermocouple is configured, using overridden delta values if set, and printing appropriate warnings. :param target_temperature: The target temperature parameters for validation :returns: True if thermocouple is configured and temperature is within range. False if thermocouple is not configured (capability missing or not set up), or if target temperature/delta is NaN. :rtype: bool :raises ValueError: If the current temperature exceeds the target ± delta range (only raised when capability is configured) .. rubric:: Examples >>> measurement = EIS(device) >>> measurement.measure_temperature() >>> target = compensation.temperature_parameter >>> is_valid = measurement.validate_temperature(target)