Skip to content

TC Temperature Controller¤

TCSeries (Serial) ¤

TCSeries(equipment: Equipment)

              flowchart LR
              msl.equipment_resources.electron_dynamics.tc_series.TCSeries[TCSeries]
              msl.equipment.interfaces.serial.Serial[Serial]
              msl.equipment.interfaces.message_based.MessageBased[MessageBased]
              msl.equipment.schema.Interface[Interface]

                              msl.equipment.interfaces.serial.Serial --> msl.equipment_resources.electron_dynamics.tc_series.TCSeries
                                msl.equipment.interfaces.message_based.MessageBased --> msl.equipment.interfaces.serial.Serial
                                msl.equipment.schema.Interface --> msl.equipment.interfaces.message_based.MessageBased
                




              click msl.equipment_resources.electron_dynamics.tc_series.TCSeries href "" "msl.equipment_resources.electron_dynamics.tc_series.TCSeries"
              click msl.equipment.interfaces.serial.Serial href "" "msl.equipment.interfaces.serial.Serial"
              click msl.equipment.interfaces.message_based.MessageBased href "" "msl.equipment.interfaces.message_based.MessageBased"
              click msl.equipment.schema.Interface href "" "msl.equipment.schema.Interface"
            

Establishes a connection to a TC Series Temperature Controller from Electron Dynamics Ltd.

Regular-expression patterns that are used to select this Resource when connect() is called.

manufacturer=r"Electron Dynamics"
model=r"TC\s*[M|L]"
flags=IGNORECASE

Parameters:

Name Type Description Default
equipment Equipment

An Equipment instance.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
def __init__(self, equipment: Equipment) -> None:
    r"""Establishes a connection to a TC Series Temperature Controller from Electron Dynamics Ltd.

    Regular-expression patterns that are used to select this Resource when
    [connect()][msl.equipment.schema.Equipment.connect] is called.
    ```python
    manufacturer=r"Electron Dynamics"
    model=r"TC\s*[M|L]"
    flags=IGNORECASE
    ```

    Args:
        equipment: An [Equipment][] instance.
    """
    assert equipment.connection is not None  # noqa: S101
    if not equipment.connection.properties:
        # then use the default connection properties
        equipment.connection.properties = {
            "baud_rate": 19200,
            "write_termination": None,
            "read_termination": "\r\n",
            "timeout": 10.0,
        }
    super().__init__(equipment)

get_alarm ¤

get_alarm() -> Alarm

Get the alarm parameters.

Returns:

Type Description
Alarm

The alarm parameters.

Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
def get_alarm(self) -> Alarm:
    """Get the alarm parameters.

    Returns:
        The alarm parameters.
    """
    a, b, c, d, e, f, g = map(float, self._reply("d"))
    return Alarm(
        type=AlarmType(int(a)),
        alarm_min=b,
        alarm_max=c,
        ok_min=d,
        ok_max=e,
        limit_min=f,
        limit_max=g,
    )

get_control ¤

get_control() -> Control

Get the PID control parameters.

Returns:

Type Description
Control

The control parameters.

Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
def get_control(self) -> Control:
    """Get the PID control parameters.

    Returns:
        The control parameters.
    """
    a, b, c, d, e, f, g = map(float, self._reply("b"))
    return Control(
        type=ControlType(int(a)),
        p=b,
        i=c,
        d=d,
        d_filter=e,
        dead_band=f,
        power_up_state=PowerUpState(int(g)),
    )

get_output ¤

get_output() -> Output

Get the output parameters.

Returns:

Type Description
Output

The output parameters.

Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
399
400
401
402
403
404
405
406
407
408
409
410
411
def get_output(self) -> Output:
    """Get the output parameters.

    Returns:
        The output parameters.
    """
    a, b, c, d = map(float, self._reply("h"))
    return Output(
        polarity=Polarity(int(a)),
        minimum=b,
        maximum=c,
        frequency=d,
    )

get_sensor ¤

get_sensor() -> Sensor

Get the sensor parameters.

Returns:

Type Description
Sensor

The sensor parameters.

Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
def get_sensor(self) -> Sensor:
    """Get the sensor parameters.

    Returns:
        The sensor parameters.
    """
    data = list(map(float, self._reply("f")))
    return Sensor(
        type=SensorType(int(data[0])),
        x2=data[1],
        x=data[2],
        c=data[3],
        unit=Unit(data[4]),
        averaging=data[5] == 1,
        r=0.0 if len(data) < 7 else data[6],  # noqa: PLR2004
    )

get_setpoint ¤

get_setpoint() -> Setpoint

Get the setpoint parameters.

Returns:

Type Description
Setpoint

The setpoint parameters.

Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
430
431
432
433
434
435
436
437
438
439
440
441
442
def get_setpoint(self) -> Setpoint:
    """Get the setpoint parameters.

    Returns:
        The setpoint parameters.
    """
    a, b, c, d = map(float, self._reply("q"))
    return Setpoint(
        method=Method(int(a)),
        value=b,
        pot_range=c,
        pot_offset=d,
    )

get_status ¤

get_status() -> Status

Get the status.

Returns:

Type Description
Status

The status parameters.

Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
def get_status(self) -> Status:
    """Get the status.

    Returns:
        The status parameters.
    """
    r = self._reply("j")
    return Status(
        setpoint=float(r[0]),
        temperature=float(r[1]),
        controlled=r[2] == "1",
        output=float(r[3]),
        alarm_type=AlarmType(int(r[4])),
        faults=int(r[5]),
        temp_ok=r[6] == "1",
        supply_v=float(r[7]),
        version=r[8],
        test_cycles=int(r[9]),
        test_mode_completed=r[10] == "1",
    )

set_alarm ¤

set_alarm(alarm: Alarm) -> None

Set the alarm parameters.

Parameters:

Name Type Description Default
alarm Alarm

The alarm parameters.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
465
466
467
468
469
470
471
472
473
474
475
def set_alarm(self, alarm: Alarm) -> None:
    """Set the alarm parameters.

    Args:
        alarm: The alarm parameters.
    """
    data = (
        f"{alarm.type};{alarm.alarm_min:.3f};{alarm.alarm_max:.3f};{alarm.ok_min:.3f};"
        f"{alarm.ok_max:.3f};{alarm.limit_min:.3f};{alarm.limit_max:.3f};"
    )
    self._send("c", data)

set_control ¤

set_control(control: Control) -> None

Set the PID control parameters.

Parameters:

Name Type Description Default
control Control

The control parameters.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
477
478
479
480
481
482
483
484
485
486
487
def set_control(self, control: Control) -> None:
    """Set the PID control parameters.

    Args:
        control: The control parameters.
    """
    data = (
        f"{control.type};{control.p:.3f};{control.i:.3f};{control.d:.3f};"
        f"{control.d_filter:.3f};{control.dead_band:.3f};{control.power_up_state};"
    )
    self._send("a", data)

set_output ¤

set_output(output: Output) -> None

Set the output parameters.

Parameters:

Name Type Description Default
output Output

The output parameters.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
489
490
491
492
493
494
495
496
def set_output(self, output: Output) -> None:
    """Set the output parameters.

    Args:
        output: The output parameters.
    """
    data = f"{output.polarity};{output.minimum:.3f};{output.maximum:.3f};{output.frequency:.3f};"
    self._send("g", data)

set_output_drive ¤

set_output_drive(*, enable: bool, value: float) -> None

Set the output drive state and value.

Parameters:

Name Type Description Default
enable bool

Whether to enable or disable the output drive.

required
value float

Percent drive output.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
498
499
500
501
502
503
504
505
def set_output_drive(self, *, enable: bool, value: float) -> None:
    """Set the output drive state and value.

    Args:
        enable: Whether to enable or disable the output drive.
        value: Percent drive output.
    """
    self._send("m", f"{int(enable)};{value:.3f};")

set_sensor ¤

set_sensor(sensor: Sensor) -> None

Set the sensor type and the sensor parameters.

Parameters:

Name Type Description Default
sensor Sensor

The sensor parameters.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
507
508
509
510
511
512
513
514
515
516
def set_sensor(self, sensor: Sensor) -> None:
    """Set the sensor type and the sensor parameters.

    Args:
        sensor: The sensor parameters.
    """
    data = f"{sensor.type};{sensor.x2:.3f};{sensor.x:.3f};{sensor.c:.3f};{sensor.unit};{int(sensor.averaging)};"
    if sensor.type in (SensorType.NTC_THERMISTOR, SensorType.RES):
        data += f"{sensor.r:.3f};"
    self._send("e", data)

set_setpoint ¤

set_setpoint(setpoint: Setpoint) -> None

Set the setpoint parameters.

Parameters:

Name Type Description Default
setpoint Setpoint

The setpoint parameters.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
518
519
520
521
522
523
524
525
def set_setpoint(self, setpoint: Setpoint) -> None:
    """Set the setpoint parameters.

    Args:
        setpoint: The setpoint parameters.
    """
    data = f"{setpoint.method};{setpoint.value:.3f};{setpoint.pot_range:.3f};{setpoint.pot_offset:.3f};"
    self._send("i", data)

set_test ¤

set_test(mode: int, *data: float) -> None

Set the test parameters.

Parameters:

Name Type Description Default
mode int

The test mode. One of:

  • 0: Off
  • 1: Normal
  • 2: Temperature cycle
  • 3: Temperature ramp
  • 4: Auto tune
required
data float

The test data.

()
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
def set_test(self, mode: int, *data: float) -> None:
    """Set the test parameters.

    Args:
        mode: The test mode. One of:

            * `0`: Off
            * `1`: Normal
            * `2`: Temperature cycle
            * `3`: Temperature ramp
            * `4`: Auto tune

        data: The test data.
    """
    if mode < 0 or mode > 4:  # noqa: PLR2004
        msg = f"Invalid test mode={mode}. Must be 0, 1, 2, 3 or 4"
        raise ValueError(msg)

    values = ";".join(f"{v:.3f}" for v in data)
    self._send("k", f"{mode};{values};")

Establishes a connection to a TC Series Temperature Controller from Electron Dynamics Ltd.

The main communication class is TCSeries.

Alarm dataclass ¤

Alarm(
    type: AlarmType,
    alarm_min: float,
    alarm_max: float,
    ok_min: float,
    ok_max: float,
    limit_min: float,
    limit_max: float,
)

Alarm parameters.

Parameters:

Name Type Description Default
alarm_min float

The temperature below which the alarm is activated.

required
alarm_max float

The temperature above which the alarm is activated.

required
ok_min float

The minimum temperature difference from the setpoint for the temperature to be okay.

required
ok_max float

The maximum temperature difference from the setpoint for the temperature to be okay.

required
limit_min float

The minimum temperature below which the drive output is disabled.

required
limit_max float

The maximum temperature above which the drive output is disabled.

required

AlarmType (IntEnum) ¤

Alarm type.

Attributes:

Name Type Description
OFF int

0

MIN int

1

MAX int

2

BOTH int

3

Control dataclass ¤

Control(
    type: ControlType,
    p: float,
    i: float,
    d: float,
    d_filter: float,
    dead_band: float,
    power_up_state: PowerUpState,
)

The PID control parameters.

Parameters:

Name Type Description Default
type ControlType

The control type.

required
p float

The proportional (gain) value. With a proportional control type, the controller output is proportional to the temperature error from the setpoint. The proportional terms sets the gain for this, i.e., Output = setpoint-actual-temperature * proportional-term

required
i float

The integral value. With integral action, the controller output is proportional to the amount of time the error is present. Integral action eliminates offset. The integral term is a time unit in seconds. NB for larger effects of integration reduce the integral time, also for operation without integral, integral time can be set to a large number, e.g. 1e6.

required
d float

The derivative value. With derivative action, the controller output is proportional to the rate of change of the measurement or error. The controller output is calculated by the rate of change of the measurement with time, in seconds. To increase the derivative action increase the derivative value.

required
d_filter float

The derivative filter is a low pass filter function on the derivative value. This allows the filtration of noise components which are a problem with a pure derivative function. The filter value should be set to be between 0 and 1.

required
dead_band float

For use with On/Off control the dead band specifies the temperature range around the set point where the output is zero. For example:

  • Temperature > setpoint + dead_band (Fully Cooling)
  • Temperature < setpoint - dead_band (Fully Heating)
  • Temperature < setpoint + dead_band AND > setpoint-dead_band (Output off)
required
power_up_state PowerUpState

Temperature control state from power up.

required

ControlType (IntEnum) ¤

Control type.

Attributes:

Name Type Description
ON_OFF int

Output drive is only fully on (heating or cooling) or off, 1.

P int

Proportional, 2.

PI int

Proportional and integral, 3.

PID int

Proportional, integral and derivative, 4.

Method (IntEnum) ¤

Setpoint method type.

The temperature setpoint can be set via software or by altering the potentiometer on the temperature controller hardware.

Attributes:

Name Type Description
POTENTIOMETER int

0

SOFTWARE int

1

INPUT int

2

Output dataclass ¤

Output(
    polarity: int | Polarity, minimum: float, maximum: float, frequency: float
)

Output parameters.

Parameters:

Name Type Description Default
polarity int | Polarity

Output drive polarity.

required
minimum float

The minimum value limit of the output. Range -100 to +100.

required
maximum float

The maximum value limit of the output. Range -100 to +100.

required
frequency float

Sets the pulse-width modulation repetition frequency of the output drive. Range 20 to 1000 Hz.

required
Source code in packages/resources/src/msl/equipment_resources/electron_dynamics/tc_series.py
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def __init__(self, polarity: int | Polarity, minimum: float, maximum: float, frequency: float) -> None:
    """Output parameters.

    Args:
        polarity: Output drive polarity.
        minimum: The minimum value limit of the output. Range -100 to +100.
        maximum: The maximum value limit of the output. Range -100 to +100.
        frequency: Sets the pulse-width modulation repetition frequency of the output drive.
            Range 20 to 1000 Hz.
    """
    if abs(minimum) > 100:  # noqa: PLR2004
        msg = f"Invalid minimum={minimum}. Must be between -100 and +100"
        raise ValueError(msg)
    if abs(maximum) > 100:  # noqa: PLR2004
        msg = f"Invalid maximum={maximum}. Must be between -100 and +100"
        raise ValueError(msg)
    if minimum > maximum:
        msg = f"The minimum={minimum} value must be less than the maximum={maximum}"
        raise ValueError(msg)
    if frequency < 20 or frequency > 1000:  # noqa: PLR2004
        msg = f"Invalid frequency={frequency}. Must be between 20 and 1000"
        raise ValueError(msg)

    self.polarity: Polarity = to_enum(polarity, Polarity)
    self.minimum: float = minimum
    self.maximum: float = maximum
    self.frequency: float = frequency

Polarity (IntEnum) ¤

Output drive polarity.

Attributes:

Name Type Description
NEGATIVE int

0

POSITIVE int

1

PowerUpState (IntEnum) ¤

Temperature control state from power up.

Attributes:

Name Type Description
OFF int

0

ON int

1

LAST int

2 (same as the last setting prior to power off)

Sensor dataclass ¤

Sensor(
    type: SensorType,
    x2: float,
    x: float,
    c: float,
    unit: Unit,
    averaging: bool,
    r: float = 22000.0,
)

Sensor parameters.

Parameters:

Name Type Description Default
type SensorType

Sensor type.

required
x2 float

See c description.

required
x float

See c description.

required
c float

The x2, x and c parameters are the quadratic, linear and constant coefficients that are used to convert the sensor voltage into a temperature, i.e., temperature = (v * v * x2) + (v * x) + c, where v is the measured sensor voltage. For NTC thermistors, x2 is the beta value as specified for the thermistor type, x is the resistance at \(25~^\circ\text{C}\), and c is still the offset.

required
unit Unit

The temperature unit.

required
averaging bool

Whether to enable or disable averaging.

required
r float

Used for NTC or RES sensors and corresponds to the RL drive resistance.

22000.0

SensorType (IntEnum) ¤

Sensor type.

Attributes:

Name Type Description
VOLTAGE int

0

PT100 int

1

LM35 int

2

LM50 int

3

LM60 int

4

LM61 int

5

NTC_THERMISTOR int

6

RES int

7

PT1000 int

8

RTD int

9

Setpoint dataclass ¤

Setpoint(method: Method, value: float, pot_range: float, pot_offset: float)

The setpoint parameters.

Parameters:

Name Type Description Default
method Method

The setpoint method.

required
value float

The setpoint value.

required
pot_range float

The temperature range of the potentiometer.

required
pot_offset float

The minimum temperature value of the potentiometer.

required

Status dataclass ¤

Status(
    setpoint: float,
    temperature: float,
    controlled: bool,
    output: float,
    alarm_type: AlarmType,
    faults: int,
    temp_ok: bool,
    supply_v: float,
    version: str,
    test_cycles: float,
    test_mode_completed: bool,
)

Controller status.

Parameters:

Name Type Description Default
setpoint float

Setpoint value.

required
temperature float

The measured temperature (for the specified Sensor Unit).

required
controlled bool

Whether the temperature control drive is on or off.

required
output float

The output value (between -100 and 100).

required
alarm_type AlarmType

The type of alarm used.

required
faults int

Fault flags.

  • bit 0: ADC fault.
  • bit 1: ADCR fault.
  • bit 2: VDC limit.
  • bit 3: Temperature limit.
  • bit 4: Inhibited.
required
temp_ok bool

Whether the temperature is ok (within range).

required
supply_v float

The supply voltage.

required
version str

The firmware version number of the controller.

required
test_cycles float

The number of test cycles that have occurred.

required
test_mode_completed bool

Whether the test has completed.

required

Unit (Enum) ¤

The temperature unit.

Attributes:

Name Type Description
C str

Celsius, "C".

F str

Fahrenheit, "F".

K str

Kelvin, "K".

V str

Voltage, "V".

R str

Resistance, "R".