Skip to content

Function Generator

AWG / function generator control (Siglent SDG and generic SCPI-99)

Main FunctionGenerator class for controlling SCPI function generators and AWGs.

Supports generic SCPI-99 compliant arbitrary waveform generators and Siglent SDG series models.

Installation

pip install "SCPI-Instrument-Control"

Features
  • Multiple connection types: Ethernet/LAN, USB, GPIB, Serial
  • Full control of waveform type, frequency, amplitude, and offset
  • Model-specific capability detection
  • Basic waveform generation (sine, square, ramp, pulse)
  • Context manager support for automatic connection management

FunctionGenerator

FunctionGenerator(host: str, port: int = 5025, timeout: float = 5.0, connection: Optional[BaseConnection] = None)

Main class for controlling SCPI function generators and arbitrary waveform generators.

This class provides a high-level interface for controlling function generator operations including waveform type, frequency, amplitude, and output control.

Supports both generic SCPI-99 function generators and Siglent SDG series models with automatic model detection and capability-based feature availability.

Example

awg = FunctionGenerator('192.168.1.100') awg.connect() print(awg.identify()) print(f"Model: {awg.model_capability.model_name}") print(f"Channels: {awg.model_capability.num_channels}") awg.channel1.configure_sine(frequency=1000, amplitude=5.0) awg.channel1.enable() awg.disconnect()

Or using context manager:

with FunctionGenerator('192.168.1.100') as awg: ... awg.channel1.configure_square(frequency=10e3, amplitude=3.0) ... awg.channel1.enable()

Initialize function generator connection.

Parameters:

Name Type Description Default
host str

IP address or hostname of the function generator

required
port int

TCP port for SCPI communication (default: 5025, the Siglent raw SCPI socket; 5024 is the telnet-style port with prompts and is not recommended)

5025
timeout float

Command timeout in seconds (default: 5.0)

5.0
connection Optional[BaseConnection]

Optional custom connection object (uses SocketConnection if None)

None
Note

Channels are created dynamically after connection based on model capabilities. Call connect() to establish connection and initialize channels.

Source code in scpi_control/function_generator.py
def __init__(
    self,
    host: str,
    port: int = 5025,
    timeout: float = 5.0,
    connection: Optional[BaseConnection] = None,
):
    """Initialize function generator connection.

    Args:
        host: IP address or hostname of the function generator
        port: TCP port for SCPI communication (default: 5025, the Siglent raw SCPI socket; 5024 is the telnet-style port with prompts and is not recommended)
        timeout: Command timeout in seconds (default: 5.0)
        connection: Optional custom connection object (uses SocketConnection if None)

    Note:
        Channels are created dynamically after connection based on model capabilities.
        Call connect() to establish connection and initialize channels.
    """
    self.host = host
    self.port = port
    self.timeout = timeout

    # Create connection
    if connection is not None:
        self._connection = connection
    else:
        self._connection = SocketConnection(host, port, timeout)

    # Model capability and SCPI commands (populated after connection)
    self.model_capability: Optional[AWGCapability] = None
    self._scpi_commands: Optional[AWGSCPICommandSet] = None

    # Device information (populated after connection)
    self._device_info: Optional[Dict[str, str]] = None

is_connected property

is_connected: bool

Check if connected to function generator.

Returns:

Type Description
bool

True if connected, False otherwise

device_info property

device_info: Optional[Dict[str, str]]

Get parsed device information.

Returns:

Type Description
Optional[Dict[str, str]]

Dictionary with keys: manufacturer, model, serial, firmware

Optional[Dict[str, str]]

None if not connected

supported_channels property

supported_channels: List[int]

Get list of supported channel numbers for this model.

Returns:

Type Description
List[int]

List of channel numbers (e.g., [1, 2] for 2-channel model)

List[int]

Empty list if not connected

Example

awg.connect() print(awg.supported_channels) [1, 2]

connect

connect() -> None

Establish connection to the function generator.

This method connects to the function generator, detects the model, and initializes model-specific capabilities and output channels.

Raises:

Type Description
SiglentConnectionError

If connection fails

SiglentTimeoutError

If connection times out

Source code in scpi_control/function_generator.py
def connect(self) -> None:
    """Establish connection to the function generator.

    This method connects to the function generator, detects the model, and initializes
    model-specific capabilities and output channels.

    Raises:
        SiglentConnectionError: If connection fails
        SiglentTimeoutError: If connection times out
    """
    logger.info(f"Connecting to function generator at {self.host}:{self.port}")
    self._connection.connect()
    logger.info("Connected successfully")

    # Verify connection by getting device identification
    try:
        idn_string = self.identify()
        self._device_info = self._parse_idn(idn_string)
        logger.info(f"Connected to: {self._device_info.get('manufacturer', 'Unknown')} " f"{self._device_info.get('model', 'Unknown')}")

        # Detect model capability
        self.model_capability = detect_awg_from_idn(idn_string)
        logger.info(f"Model capability: {self.model_capability}")

        # Initialize SCPI command set for this model
        self._scpi_commands = AWGSCPICommandSet(self.model_capability.scpi_variant)
        logger.info(f"Using SCPI variant: {self.model_capability.scpi_variant}")

        # Create channels dynamically based on model capability
        self._create_channels()

        # Update device info with capability information
        self._device_info["manufacturer"] = self.model_capability.manufacturer
        self._device_info["num_channels"] = str(self.model_capability.num_channels)

    except Exception as e:
        logger.error(f"Failed to identify device or initialize: {e}")
        self.disconnect()
        raise exceptions.SiglentConnectionError(f"Connected but failed to identify device: {e}")

disconnect

disconnect() -> None

Close connection to the function generator.

Source code in scpi_control/function_generator.py
def disconnect(self) -> None:
    """Close connection to the function generator."""
    logger.info("Disconnecting from function generator")
    self._connection.disconnect()
    self._device_info = None
    self.model_capability = None
    self._scpi_commands = None

    # Remove dynamically created channels
    for i in range(1, 5):  # Check all possible channels
        channel_attr = f"channel{i}"
        if hasattr(self, channel_attr):
            delattr(self, channel_attr)

write

write(command: str) -> None

Send a SCPI command to the function generator.

Parameters:

Name Type Description Default
command str

SCPI command string

required

Raises:

Type Description
SiglentConnectionError

If not connected

CommandError

If command contains invalid characters

Source code in scpi_control/function_generator.py
def write(self, command: str) -> None:
    """Send a SCPI command to the function generator.

    Args:
        command: SCPI command string

    Raises:
        SiglentConnectionError: If not connected
        CommandError: If command contains invalid characters
    """
    logger.debug(f"Write: {command}")
    self._connection.write(command)

query

query(command: str) -> str

Send a SCPI query and get the response.

Parameters:

Name Type Description Default
command str

SCPI query command

required

Returns:

Type Description
str

Response string from function generator

Raises:

Type Description
SiglentConnectionError

If not connected

SiglentTimeoutError

If query times out

CommandError

If command contains invalid characters

Source code in scpi_control/function_generator.py
def query(self, command: str) -> str:
    """Send a SCPI query and get the response.

    Args:
        command: SCPI query command

    Returns:
        Response string from function generator

    Raises:
        SiglentConnectionError: If not connected
        SiglentTimeoutError: If query times out
        CommandError: If command contains invalid characters
    """
    logger.debug(f"Query: {command}")
    response = self._connection.query(command)
    logger.debug(f"Response: {response}")
    return response

identify

identify() -> str

Get device identification string.

Returns:

Type Description
str

Device identification string (manufacturer, model, serial, firmware)

Example

'Siglent Technologies,SDG1032X,SDG1XXXXXXXXXXX,2.01.01.37R1'

Source code in scpi_control/function_generator.py
def identify(self) -> str:
    """Get device identification string.

    Returns:
        Device identification string (manufacturer, model, serial, firmware)

    Example:
        'Siglent Technologies,SDG1032X,SDG1XXXXXXXXXXX,2.01.01.37R1'
    """
    return self.query("*IDN?")

reset

reset() -> None

Reset function generator to default settings.

Note: This may take several seconds to complete and will turn off all outputs.

Source code in scpi_control/function_generator.py
def reset(self) -> None:
    """Reset function generator to default settings.

    Note: This may take several seconds to complete and will turn off all outputs.
    """
    logger.info("Resetting function generator to defaults")
    self.write("*RST")

clear_status

clear_status() -> None

Clear status registers.

Source code in scpi_control/function_generator.py
def clear_status(self) -> None:
    """Clear status registers."""
    self.write("*CLS")

get_error

get_error() -> str

Get the last error from the error queue.

Returns:

Type Description
str

Error string (format: "code,description")

Source code in scpi_control/function_generator.py
def get_error(self) -> str:
    """Get the last error from the error queue.

    Returns:
        Error string (format: "code,description")
    """
    return self.query("SYST:ERR?")

all_outputs_off

all_outputs_off() -> None

Disable all outputs (safety feature).

This is a safety method to quickly turn off all function generator outputs.

Source code in scpi_control/function_generator.py
def all_outputs_off(self) -> None:
    """Disable all outputs (safety feature).

    This is a safety method to quickly turn off all function generator outputs.
    """
    if self.model_capability is None:
        logger.warning("Cannot disable outputs - not connected")
        return

    logger.info("Disabling all outputs (safety)")
    for i in range(1, self.model_capability.num_channels + 1):
        channel = getattr(self, f"channel{i}", None)
        if channel:
            try:
                channel.disable()
            except Exception as e:
                logger.error(f"Failed to disable channel {i}: {e}")

get_channel

get_channel(channel_num: int) -> Optional[AWGOutput]

Get channel object by number.

Parameters:

Name Type Description Default
channel_num int

Channel number (1-based)

required

Returns:

Type Description
Optional[AWGOutput]

AWGOutput object or None if channel doesn't exist

Example

awg.connect() ch1 = awg.get_channel(1)

Source code in scpi_control/function_generator.py
def get_channel(self, channel_num: int) -> Optional[AWGOutput]:
    """Get channel object by number.

    Args:
        channel_num: Channel number (1-based)

    Returns:
        AWGOutput object or None if channel doesn't exist

    Example:
        >>> awg.connect()
        >>> ch1 = awg.get_channel(1)
    """
    channel_attr = f"channel{channel_num}"
    return getattr(self, channel_attr, None)

sync_channels

sync_channels(phase_offset: float = 0.0) -> None

Synchronize multiple channels with optional phase offset.

Parameters:

Name Type Description Default
phase_offset float

Phase offset in degrees for channel 2 relative to channel 1 (only applicable for 2-channel models)

0.0
Note

This sets channel 1 to 0 degrees and channel 2 to the specified offset. Both channels should be configured to the same frequency for best results.

Source code in scpi_control/function_generator.py
def sync_channels(self, phase_offset: float = 0.0) -> None:
    """Synchronize multiple channels with optional phase offset.

    Args:
        phase_offset: Phase offset in degrees for channel 2 relative to channel 1
                     (only applicable for 2-channel models)

    Note:
        This sets channel 1 to 0 degrees and channel 2 to the specified offset.
        Both channels should be configured to the same frequency for best results.
    """
    if self.model_capability is None or self.model_capability.num_channels < 2:
        logger.warning("Channel synchronization requires multi-channel model")
        return

    logger.info(f"Synchronizing channels with {phase_offset}° offset")
    self.channel1.phase = 0.0
    self.channel2.phase = phase_offset