“Digital Twin” with Python: A hands-on example | by Tirthajyoti Sarkar | Towards Data Science

IBM defines a digital twin as follows “A digital twin is a virtual model designed to accurately reflect a physical object”.
They go on to describe how the main enabling factors for creating a digital twin are the sensors that gather data and the processing system that inserts the data in some particular format/model into the digital copy of the object.
Further, IBM says “Once informed with such data, the virtual model can be used to run simulations, study performance issues and generate possible improvements”.
So, we can draw this mental model, can’t we?
So, how do we use our favorite language Python to create a digital twin? Why do we even think it will work?
The answer is deceptively simple. Just look at the figure above and then at the one below to see the equivalency between a Digital Twin model and a classic Python object. We can emulate the sensors and data processors with suitable methods/functions, store the gathered data in a database or internal variables, and encapsulate everything into a Python class.
Once we accomplish that, we can also hope that the Python object
can be used in suitable simulation programs,
can be probed for data, and
can even be subject to optimization routines for enhancing suitable internal parameters.
We can, of course, add virtually infinite layers of complexity to this scheme and make the object a truly complex digital construct. But, following Occam’s Razor principle, we should start simple, and add sophistication as we go along.
...main enabling factors for creating a digital twin are the sensors that gather data and the processing system...
In this article, we will take a simple step-by-step approach to creating a digital twin object out of a single semiconductor device (the physical object). For the sake of simplicity, we will not even get into modeling sensors, but emulate them as simple terminal voltages on the semiconductor device.
There are a select few physical objects around us that define and embody the march of modern civilization quite spectacularly. An incomplete list may look like the following,
internal combustion engine — embodies all mobility
printing press — embodies all knowledge
electrical motor — embodies all industrial motion
a semiconductor-based transistor — embodies all electronics/internet
I have worked in the semiconductor industry for more than a decade before joining the world of data science. Naturally, I would be attracted towards using a related example for this digital twin demo, won’t I?
Although the first semiconductor transistors were so-called ‘Bipolar Junction Device”, almost all modern transistors are of the form called MOSFET. It is an acronym that stands for “Metal-Oxide-Semiconductor Field-Effect-Transistor”.
Basically, it is a device made of metal and semiconductor (e.g., silicon or germanium) layers that sandwich a thin oxide (or another electrical insulator) material layer in between.
This is a historical image of one of the earliest MOSFET patents,
We can simplify the internal structure by adopting a device model (also called a circuit model) with three terminals — Drain, Source, and Gate.
This is one of the first considerations while building a digital twin — what characteristics we want to model in our digital object. This determines the complexity and data structure choice for the twin.
For instance, although we can model all kinds of complex physics phenomena with the MOSFET structure, we may choose to restrict ourselves to modeling only the most basic characteristic viz. the drain-source current and voltage relationships in their simplest form.
Now, we don’t have the bandwidth to explain all these characteristics (and their underlying physics) in detail in this article. Interested readers can refer to excellent online materials,
https://www.electronics-tutorials.ws/transistor/tran_6.html
The most succinct way to remember the behavior of a MOSFET is to imagine it as a digital switch. Here is how it works,
If the voltage between Gate and Source is below a certain threshold, then the switch is OFF and no current (or information) flows between the Drain and Source. This is shown in the bottom-right image of the figure above.
When the Gate to Source voltage is above this threshold, the switch is ON. The Drain to Source current is also determined by the voltage between them. This is shown in the top-right image of the figure above.
So, the fundamental utility of a MOSFET is as a voltage-controlled switch i.e. we can control the amount of current (or information) between two of its terminals by controlling the voltage on the third terminal.
What characteristics do we want to model in our digital object? This determines the complexity and data structure choice for the digital twin
With this in mind, the only thing to remember for creating a digital twin, are three important parameters of a generic MOSFET,
Vth: It is the threshold voltage (between Gate and Source) above which the switch is ON.
gm: It is the ‘ease’ with which a MOSFET can carry current between Drain and Source once it is ON. The higher this number is, the more is the current. It can be thought of as an inverse quantity to resistance (which represents the resistance to the flow of current for a given voltage).
BV: This is called the “Breakdown voltage”. This was not discussed in the ideal switch description and will not be modeled in the digital twin. This represents a limit on how much voltage the MOSFET can hold between its Drain and Source while it is in the OFF state. Above this limit, the MOSFET starts conducting again but not in a controlled manner i.e. we cannot control the current flow and it is essentially useless. However, this parameter is important to design and model as it limits the choice of a particular device in a particular application.
fundamental utility of a MOSFET is as a voltage-controlled switch...
The boilerplate code for this demo is here in my Github repo. For brevity, I will only show partial code snippets in this article.
We define the main MOSFET class with a choice for the user to also define some parameters and the terminal voltages. Partial code is shown below,
class MOSFET:    def __init__(self,params=None,terminals=None):                # Params        if params is None:            self._params_ = {'BV':20,                             'Vth':1.0,                             'gm':1e-2}        else:            self._params_ = params                # Terminals        if terminals is None:            self._terminals_ = {'source':0.0,                        'drain':0.0,                        'gate':0.0}        else:            self._terminals_ = terminals
In this code, we can observe the familiar terminals and parameters that we discussed at length before. There are some default parameters.
We can also have a __repr__ method to describe the object in one line,
def __repr__(self):        return "Digital Twin of a MOSFET"
We can easily translate the MOSFET characteristic of a digital switch (ON/OFF) into a programming logic by defining a method within the class.
def determine_state(self,vgs=None):        """        """        if vgs is None:            vgs = self._terminals_['gate'] - self._terminals_['source']        else:            vgs = vgs        if vgs > self._params_['Vth']:            return 'ON'        else:            return 'OFF'
In the __init__ method, we can have the state determined from the instantiation of the object.
# Determine state  self._state_ = self.determine_state()
You are getting a hang of defining a Digital Twin with its characteristics and behavior, aren’t you?
Before going deeper into other characteristics, let’s see the behavior of this digital twin as defined so far.
mosfet = MOSFET()
In Jupyter notebook, we type this for testing the one-line description,
mosfet>> Digital Twin of a MOSFET
We test the state of the mosfet object.
mosfet._state_>> 'OFF'
We get the default parameters’ dictionary back in this way,
mosfet._params_>> {'BV': 20, 'Vth': 1.0, 'gm': 0.01}
Now, if we explicitly define an object with some terminal and parameters value,
mosfet = MOSFET(terminals={'source':0.0,            'drain':0.0,            'gate':2.0},            params={'BV':20,                   'Vth':1.0,                   'gm':1e-2})
What do you think the state of this object is? Let’s check,
mosfet._state_>> 'ON'
The MOSFET (or its Digital Twin) is ON because the voltage between Gate and Source is larger than the parameter Vth as defined in the instance. I repeat the code snippet again with highlighted portion of interest,
terminals={'source':0.0,            'drain':0.0,            'gate':2.0}
and
params={'BV':20,        'Vth':1.0,        'gm':1e-2})
Next, we define a method to calculate the Drain-to-Source current for the ON-state MOSFET using a simple, first-order analytical model. The code and equation are contained in the Notebook, and I only show a partial code snippet here,
def id_vd(self,vgs=None,vds=None,rounding=True):        """        Calculates drain-source current from         terminal voltages and gm        """        <code>        if state=='ON':            if vds <= vgs - vth:                ids = self._params_['gm']*(vgs - vth - (vds/2))*vds            else:                ids = (self._params_['gm']/2)*(vgs-vth)**2                 <more code...>
What will be more interesting is that checking if the Digital Twin can generate current-voltage characteristics similar to a physical device. We can calculate a series of Drain-Source currents for a range of Drain-Source voltage.
ids = []mosfet = MOSFET()vds_vals = [0.01*i for i in range(1,501)]for v in vds_vals:    ids.append(mosfet.id_vd(vgs=3.0,vds=v,rounding=False))
The result looks beautifully matched to a generic, ideal MOSFET characteristic. Here Vds (x-axis) represents Drain-Source voltage and Ids (y-axis) represent Drain-Source current.
The analytical model involves Gate-Source voltage (Vgs) too, and therefore, we can calculate Ids vs. Vds curves for a range of Vgs. That result looks like,
Digital twin modeling does not necessarily need tools from data science or machine learning. However, in the modern world, dominated by data-driven models, it is prudent to use such modeling techniques wherever applicable and suitable.
This does not mean that you should eliminate all analytical models from your digital twins and start throwing deep learning models at every characteristic. As a domain expert (or with the help of one if you are not the domain expert), you must determine a balanced mix of analytical and machine-learning models (or even discrete simulation models), to embed inside the Digital Twin object for representing the real-world characteristics of the physical asset.
Digital twin modeling does not necessarily need tools from data science or machine learning
So, where should we apply a suitable ML technique in our digital twin object? It turns out that calculating (or predicting with an ML estimator) the so-called “Sub-threshold leakage” will be a good candidate.
What is this “Sub-threshold leakage”?
As we discussed earlier, the MOSFET is in the OFF state when the Vgs is below Vth. So, the ideal behavior for it is to carry zero current between Drain and Source. However, due to the wonderful whimsical nature of quantum mechanics (the details of which we don’t need to know), a real MOSFET carries a small amount of ‘leakage’ current even in the OFF state. We can attempt to calculate this using an ML model — specifically a deep neural network (DNN).
So, why did we choose an analytical equation for modeling the Ids-Vds in the ON-state and a DNN for leakage current?
There is no right or wrong answer to this question. It depends on a few factors,
the type, and nature of the data you have
the nature and complexity of the physical process that you are trying to model
the trade-off between performance and accuracy of the Digital Twin model
In this case, the measurement of the leakage current is often noisy. The actual value is also somewhat stochastic, being a strong function of the natural variability in the material properties and manufacturing processes that created the physical MOSFET. The physics also dictates that it is a nonlinear function of the terminal voltage and a few other internal parameters. All of these make an ML approach suitable for modeling this characteristic.
For every digital twin you create, you have to investigate deeply and make the choice based on your judgment. However, the beauty of a digital twin is that it allows you to swap out an analytical model with an ML model (and vice versa) anytime you fancy.
you must determine a balanced mix of analytical and machine-learning models (or even discrete simulation models), to embed inside the Digital Twin object
The choice of the model training and prediction interface is entirely flexible. In this example, we have separate training and prediction methods. The code snippet for the training method looks like the following.
def train_leakage(self,data=None,                      batch_size=5,                      epochs=20,                      learning_rate=2e-5,                      verbose=1):        """        Trains the digital twin for leakage current model with experimental data        Args:            data: The training data, expected as a Pandas DataFrame            batch_size (int): Training batch size            epochs (int): Number of epochs for training            learning_rate (float): Learning rate for training            verbose (0 or 1): Verbosity of display while training        """
Note the inclusion of parameters like batch_size, epochs, and learning_rate — familiar to anybody knowledgeable about building a deep learning model. As the main input, all you have to supply is the data which is expected to be a Pandas DataFrame.
Internally, the code builds a Tensorflow Keras model, compiles and trains it, and saves the trained model as an internal property (self.leakage_model) of the Digital Twin.
# Deep-learning modelmodel = build_model(num_layers=3,                    architecture=[32,32,32],                    input_dim=3)# Compile and trainmodel_trained = compile_train_model(model,                                    X_train_scaled,                                    y_train_scaled,                                    batch_size=batch_size,                                    epochs=epochs,                                    learning_rate=learning_rate,                                    verbose=verbose)self.leakage_model = model_trained
Hyperparameters like the number of hidden layers and the activation function are pre-fixed in this implementation, but they can be exposed easily to the developer who is using the Digital Twin in the real-world application.
beauty of a digital twin is that it allows you to swap out an analytical model with an ML model (and vice versa) anytime you fancy
For this demo, we created some synthetic data using a special helper function (included in the Notebook) to train the DNN. This helper included random variables to mimic the variability and noise in the manufacturing and measurement, mentioned earlier.
However, in real life, the semiconductor plant/ fab will run physical test suites (using other machines) on millions of MOSFETs and record their leakage current for various Vgs bias voltages. It will also record the Vth of those MOSFETs in the test. All these data will flow into the Digital Twin and the model will be continuously trained and updated.
With this arrangement, we just write one line of code to train the model with the training data supplied as df DataFrame,
mosfet.train_leakage(df)
and the familiar training starts,
We write a separate leakage method to predict the sub-Vth leakage for any combination of transconductance, Vgs, and Vth as input.
def leakage(self,                w_l=1e-2,                vgs=None,                vth=None):        """        Calculates leakage current using the deep learning model        """        if not self._leakage_:            return "Leakage model is not trained yet"        # Vgs        if vgs is None:            vgs = self._terminals_['gate'] - self._terminals_['source']        else:            vgs = vgs        # Vth        if vth is None:            vth = self._params_['Vth']        else:            vth = vth                # Predict        x = np.array([w_l,vgs,vth])        ip = x.reshape(-1,3)        result = float(10**(-self.leakage_model.predict(ip)))                return result
The exponentiation in the code (raising to the power of 10) is due to the fact that we supplied the negative 10-logarithm of actual leakage values as training targets to the DNN model. This was done to achieve faster convergence and higher accuracy.
Digital Twins welcome friends with their open arms. On both sides of the aisle, too.
Basically, they are particularly amenable to connecting to industrial systems — upstream and downstream — and exploit that connection for the optimal behavior of the whole plant/industrial system. This is important to keep in mind while designing Digital Twin with a programming language, or any other modern data-oriented tool for that matter.
Connection. Communication. Co-work. These are the keys to making a successful and well-liked Digital Twin. So, the designer must carefully evaluate the choice of data structures, programming platforms, and AI/ML methods to make sure they play well with that design philosophy.
In this article, we just peeled the upper layers of a Digital Twin design by showing you some simple steps with Python programmatic framework. It is up to you — the readers — to take the concepts forward and add more sophisticated layers of programming, logic, and data science layers to the system/asset of your choice and design powerful digital twins.
The Industry 4.0/ Smart factory is already here and ready to take advantage of all the progress in Digital Transformation, Artificial Intelligence, and Machine Learning. Digital twins are a vital co-component of that journey.
Connection. Communication. Co-work. These are the keys to making a successful and well-liked Digital Twin
Loved the article? Become a Medium member to continue learning without limits. I’ll receive a portion of your membership fee if you use the following link, with no extra cost to you.