C2D
Continuous-to-discrete conversion (“discretization”) is essential for implementing control algorithms on digital hardware. This function converts a continuous-time LTI system into a mathematically equivalent discrete-time system, matching the original dynamics as closely as possible at the given sample rate (T_s).
The default method is Zero-Order Hold (ZOH), which assumes the control inputs are held constant between samples. Other available transformation methods include Bilinear (Tustin’s approximation).
Excel Usage
=C2D(sysc, Ts, disc_method)
sysc(list[list], required): The continuous-time transfer function to convert (provided as numerator and denominator coefficients).Ts(float, required): The sampling period (must be > 0) in seconds.disc_method(str, optional, default: “zoh”): Method to use for conversion (‘zoh’, ‘bilinear’, ‘tustin’, ‘euler’, ‘backward_diff’, ‘foh’).
Returns (str): A string representation of the discrete-time system model.
Example 1: ZOH Discretization of 1/s
Inputs:
| sysc | Ts | disc_method |
|---|---|---|
| 1 | 0.1 | zoh |
| 1 |
Excel formula:
=C2D({1;1,0}, 0.1, "zoh")
Expected output:
"<TransferFunction>: sys[0]$sampled\nInputs (1): ['u[0]']\nOutputs (1): ['y[0]']\ndt = 0.1\n\n 0.1\n -----\n z - 1"
Example 2: Bilinear Discretization of 1/(s+1)
Inputs:
| sysc | Ts | disc_method |
|---|---|---|
| 1 | 0.05 | bilinear |
| 1 |
Excel formula:
=C2D({1;1,1}, 0.05, "bilinear")
Expected output:
"<TransferFunction>: sys[2]$sampled\nInputs (1): ['u[0]']\nOutputs (1): ['y[0]']\ndt = 0.05\n\n 0.02439 z + 0.02439\n -------------------\n z - 0.9512"
Example 3: Second order system with 1 sec sample
Inputs:
| sysc | Ts | disc_method | |
|---|---|---|---|
| 1 | 2 | 1 | zoh |
| 1 | 3 |
Excel formula:
=C2D({1,2;1,3,2}, 1, "zoh")
Expected output:
"<TransferFunction>: sys[4]$sampled\nInputs (1): ['u[0]']\nOutputs (1): ['y[0]']\ndt = 1.0\n\n 0.6321 z - 0.08555\n ------------------------\n z^2 - 0.5032 z + 0.04979"
Example 4: First order hold discretization
Inputs:
| sysc | Ts | disc_method |
|---|---|---|
| 2 | 0.01 | foh |
| 1 |
Excel formula:
=C2D({2;1,5}, 0.01, "foh")
Expected output:
"<TransferFunction>: sys[6]$sampled\nInputs (1): ['u[0]']\nOutputs (1): ['y[0]']\ndt = 0.01\n\n 0.009835 z + 0.009673\n ---------------------\n z - 0.9512"
Python Code
Show Code
import control as ct
import numpy as np
def c2d(sysc, Ts, disc_method='zoh'):
"""
Convert a continuous-time system to discrete-time by sampling.
See: https://python-control.readthedocs.io/en/latest/generated/control.c2d.html
This example function is provided as-is without any representation of accuracy.
Args:
sysc (list[list]): The continuous-time transfer function to convert (provided as numerator and denominator coefficients).
Ts (float): The sampling period (must be > 0) in seconds.
disc_method (str, optional): Method to use for conversion ('zoh', 'bilinear', 'tustin', 'euler', 'backward_diff', 'foh'). Valid options: Zero-Order Hold, Bilinear (Tustin), Tustin Alias, Euler, Backward Difference, First-Order Hold. Default is 'zoh'.
Returns:
str: A string representation of the discrete-time system model.
"""
try:
def flatten_to_1d(x):
if not isinstance(x, list):
return [float(x)] if str(x) != "" else []
flat = []
for row in x:
if isinstance(row, list):
for val in row:
if str(val) != "":
flat.append(float(val))
elif str(row) != "":
flat.append(float(row))
return flat
# For simplicity in Excel, we will assume sysc is provided as a Transfer Function
# with num and den in consecutive rows
if len(sysc) < 2:
return "Error: sysc must contain at least two rows (numerator and denominator)"
num = flatten_to_1d(sysc[0])
den = flatten_to_1d(sysc[1])
if not num or not den:
return "Error: Invalid numerator or denominator arrays"
sys_continuous = ct.tf(num, den)
sample_time = float(Ts)
if sample_time <= 0:
return "Error: Sampling time Ts must be greater than zero"
valid_methods = ['zoh', 'bilinear', 'tustin', 'euler', 'backward_diff', 'foh']
conv_method = disc_method.lower() if isinstance(disc_method, str) else 'zoh'
if conv_method not in valid_methods:
return f"Error: Invalid method '{conv_method}'. Valid options are {', '.join(valid_methods)}"
sys_discrete = ct.c2d(sys_continuous, sample_time, method=conv_method)
return str(sys_discrete)
except Exception as e:
return f"Error: {str(e)}"