import math
import numpy as np
import torch
import memtorch
from memtorch.utils import clip, convert_range
from .Memristor import Memristor as Memristor
[docs]class LinearIonDrift(Memristor):
"""Linear Ion behvaioural drift model.
Parameters
----------
time_series_resolution : float
Time series resolution (s).
u_v : float
Dopant drift mobility of the device material.
d : float
Device length (m).
r_on : float
On (minimum) resistance of the device (ohms).
r_off : float
Off (maximum) resistance of the device (ohms).
pos_write_threshold: float
Positive write threshold voltage (V).
neg_write_threshold : float
Negative write threshold voltage (V).
p : int
Joglekar window p constant.
"""
def __init__(
self,
time_series_resolution=1e-4,
u_v=1e-14,
d=10e-9,
r_on=100,
r_off=16e3,
pos_write_threshold=0.55,
neg_write_threshold=-0.55,
p=1,
**kwargs
):
args = memtorch.bh.unpack_parameters(locals())
super(LinearIonDrift, self).__init__(
args.r_off,
args.r_on,
args.time_series_resolution,
args.pos_write_threshold,
args.neg_write_threshold,
)
self.u_v = args.u_v
self.d = args.d
self.r_i = args.r_on
self.p = args.p
self.g = 1 / self.r_i
self.x = convert_range(self.r_i, self.r_on, self.r_off, 0, 1)
[docs] def simulate(self, voltage_signal, return_current=False):
len_voltage_signal = 1
try:
len_voltage_signal = len(voltage_signal)
except:
voltage_signal = [voltage_signal]
if return_current:
current = np.zeros(len_voltage_signal)
np.seterr(all="raise")
for t in range(0, len_voltage_signal):
current_ = self.current(voltage_signal[t])
if (
voltage_signal[t] >= self.pos_write_threshold
or voltage_signal[t] <= self.neg_write_threshold
):
self.x = self.x + self.dxdt(current_) * self.time_series_resolution
self.x = max(min(1.0, self.x), 0.0)
try:
self.g = 1 / ((self.r_on * self.x) + (self.r_off * (1 - self.x)))
except:
self.g = 0
if self.g > (1 / self.r_on):
self.g = 1 / self.r_on
elif self.g < (1 / self.r_off):
self.g = 1 / self.r_off
if return_current:
current[t] = current_
if return_current:
return current
[docs] def set_conductance(self, conductance):
conductance = clip(conductance, 1 / self.r_off, 1 / self.r_on)
self.x = convert_range(1 / conductance, self.r_on, self.r_off, 0, 1)
self.g = conductance
[docs] def current(self, voltage):
"""Method to determine the current of the model given an applied voltage.
Parameters
----------
voltage : float
The current applied voltage (V).
Returns
-------
float
The observed current (A).
"""
return voltage / (((self.r_on * self.x) + (self.r_off * (1 - self.x))))
[docs] def dxdt(self, current):
"""Method to determine the derivative of the state variable, dx/dt.
Parameters
----------
current : float
The observed current (A).
Returns
-------
float
The derivative of the state variable, dx/dt.
"""
return (
self.u_v
* (self.r_on / (self.d**2))
* current
* memtorch.bh.memristor.window.Jogelkar(self.x, self.p)
)
[docs] def plot_hysteresis_loop(
self,
duration=4,
voltage_signal_amplitude=5,
voltage_signal_frequency=2.5,
return_result=False,
):
return super().plot_hysteresis_loop(
self,
duration=duration,
voltage_signal_amplitude=voltage_signal_amplitude,
voltage_signal_frequency=voltage_signal_frequency,
return_result=return_result,
)
[docs] def plot_bipolar_switching_behaviour(
self,
voltage_signal_amplitude=5,
voltage_signal_frequency=2.5,
log_scale=True,
return_result=False,
):
return super().plot_bipolar_switching_behaviour(
self,
voltage_signal_amplitude=voltage_signal_amplitude,
voltage_signal_frequency=voltage_signal_frequency,
log_scale=log_scale,
return_result=return_result,
)