├── GUI ├── README.md ├── memristor1.jpg ├── memristor_GUI.py ├── question1.png ├── set_memristor_parameters.py └── set_waveforms.py ├── LICENSE ├── README.md ├── TODO ├── circuit_creator ├── README.md └── controller.py ├── functions ├── README.md └── functions.py └── models └── ideal_memristor.py /GUI/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /GUI/memristor1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuttaAbhigyan/Memristor-Simulation-Using-Python/267ea3a8972176f3fa7f6186501b510ebabbd161/GUI/memristor1.jpg -------------------------------------------------------------------------------- /GUI/memristor_GUI.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Feb 27 19:20:06 2019 5 | 6 | @author: abhigyan 7 | """ 8 | 9 | import sys 10 | from PyQt5.QtGui import * 11 | from PyQt5.QtWidgets import * 12 | from PyQt5.QtCore import * 13 | import controller as cntrl 14 | import set_memristor_parameters as semp 15 | import set_waveforms as sew 16 | 17 | """Class to implement the functionalities of the Home screen. It also has getter 18 | functions to get the inputs from the user from all windows""" 19 | 20 | class memristor_GUI(QMainWindow): 21 | 22 | #Default parameters of a Memristor and Input Wave 23 | numberOfMemristors = 1 24 | samplingFrequency = 10000 25 | dpi = 720 26 | savePath = '' 27 | sw = None 28 | smp = None 29 | 30 | D = 10 ** -9 31 | R_on = 100 32 | R_off = 16000 33 | W_0 = 0.5 * D 34 | mobility = 0.01 * 10**-12 35 | polarity = +1 36 | memristorType = 'Ideal' 37 | Q_0 = 10**-6 38 | R_delta = 15900 39 | R_0 = 8050 40 | defaultMemristorParameters = {'D':[D], 'R_on':[R_on], 'R_off':[R_off], 41 | 'W_0':[W_0], 'mobility':[mobility], 'polarity':[polarity], 42 | 'type': [memristorType]} 43 | 44 | 45 | waveType = 'Sine' 46 | amplitude = 1 47 | omega = 1000 48 | pulsewidth = 0.5 49 | start = 0 50 | stop = 1 51 | defaultWaveParameters = {'type':[waveType], 'amplitude':[amplitude], 'omega':[omega], 52 | 'pulsewidth':[pulsewidth], 'start':[start], 'stop':[stop]} 53 | 54 | 55 | #Creates the main window 56 | def __init__(self, windowLength, windowBreadth): 57 | 58 | #Create the main window 59 | super(memristor_GUI, self).__init__() 60 | self.windowLength = windowLength 61 | self.windowBreadth = windowBreadth 62 | self.setGeometry(200, 200, self.windowLength, self.windowBreadth) 63 | self.setWindowTitle('Memristor Simulation') 64 | self.setWindowIcon(QIcon('memristor_icon.ico')) 65 | 66 | #Set default buttons pressed to False 67 | self.setMemristorParametersOKButtonClicked = False 68 | self.setWaveformsOKButtonClicked = False 69 | 70 | #Set Fontstyles 71 | self.titleFont = QFont("Times", 22, QFont.Bold) 72 | self.titleFont.setUnderline(True) 73 | self.writingFont = QFont("Calibri", 15) 74 | self.otherWritingFont = QFont("Arial", 13) 75 | self.buttonFont = QFont('Times', 13) 76 | 77 | #Used for small question icon 78 | self.pixmap = QPixmap('question1.png') 79 | 80 | #Draw background Image and the home screen 81 | self.drawBackgroundImage() 82 | self.home() 83 | self.show() 84 | 85 | 86 | #Draws the background Image 87 | def drawBackgroundImage(self): 88 | backgroundImage = QImage('memristor1.jpg') 89 | backgroundScaledImage = backgroundImage.scaled(QSize(900,700)) 90 | palette = QPalette() 91 | palette.setBrush(10, QBrush(backgroundScaledImage)) 92 | self.setPalette(palette) 93 | 94 | 95 | #Draws the homescreen 96 | def home(self): 97 | 98 | #Set home window Title at top 99 | self.titleLabel = QLabel(self) 100 | self.titleLabel.setText('Memristor Simulation') 101 | self.titleLabel.setStyleSheet('QLabel{color:purple}') 102 | self.titleLabel.setFont(self.titleFont) 103 | self.titleLabel.setGeometry(QRect(self.windowLength/2 - 150, 10, 500, 50)) 104 | 105 | 106 | #Create text box for number of Memristors to be simulated 107 | self.memristorLabel = QLabel(self) 108 | self.memristorLabel.setText('Memristors: ') 109 | self.memristorLabel.setFont(self.writingFont) 110 | self.memristorLabel.setGeometry(QRect(30, 75, 120, 50)) 111 | 112 | self.memristorQLabel = QLabel(self) 113 | self.memristorQLabel.setPixmap(self.pixmap) 114 | self.memristorQLabel.setToolTip('Enter the number of Memristors \nyou' + 115 | ' want to simulate. Maximum = 10') 116 | self.memristorQLabel.move(370,85) 117 | 118 | self.memristorBox = QLineEdit(self) 119 | self.memristorBox.move(305, 88) 120 | self.memristorBox.resize(60,25) 121 | 122 | 123 | #Create Change parameters button to change default Memristor parameters 124 | self.changeParamButton = QPushButton('Change Parameters', self) 125 | self.changeParamButton.resize(140, 40) 126 | self.changeParamButton.move(665, 400) 127 | self.changeParamButton.clicked.connect(self.changeDefaultParameters) 128 | 129 | self.changeParamQLabel = QLabel(self) 130 | self.changeParamQLabel.setPixmap(self.pixmap) 131 | self.changeParamQLabel.setToolTip('Change Default Parameters') 132 | self.changeParamQLabel.move(815,402) 133 | 134 | 135 | #Create text box for Sampling Frequency of the simulation 136 | self.samplingFrequencyLabel = QLabel(self) 137 | self.samplingFrequencyLabel.setText('Sampling Frequency:') 138 | self.samplingFrequencyLabel.setFont(self.writingFont) 139 | self.samplingFrequencyLabel.setGeometry(QRect(30, 125, 220, 50)) 140 | 141 | self.samplingFrequencyQLabel = QLabel(self) 142 | self.samplingFrequencyQLabel.setPixmap(self.pixmap) 143 | self.samplingFrequencyQLabel.setToolTip(' Sampling Frequency for \n output waveforms. Higher\n'+ 144 | ' Frequency gives better \n results but require more \n'+ 145 | ' time to compute') 146 | self.samplingFrequencyQLabel.move(370,135) 147 | 148 | self.samplingFrequencyBox = QLineEdit(self) 149 | self.samplingFrequencyBox.move(305, 138) 150 | self.samplingFrequencyBox.resize(60,25) 151 | 152 | 153 | #Display Default parameters in the homescreen 154 | self.displayDefaultParameters() 155 | 156 | 157 | #Create drop down lists for values to be plotted 158 | self.valueLabel = QLabel(self) 159 | self.valueLabel.setText('Plot Values: ') 160 | self.valueLabel.setFont(self.writingFont) 161 | self.valueLabel.setGeometry(QRect(30, 177, 220, 50)) 162 | 163 | self.comboBox1 = QComboBox(self) 164 | self.comboBox1.addItem('Voltage') 165 | self.comboBox1.addItem('Current') 166 | self.comboBox1.addItem('Charge') 167 | self.comboBox1.addItem('Flux') 168 | self.comboBox1.addItem('Time') 169 | self.comboBox1.addItem('Resistance') 170 | self.comboBox1.move(305, 188) 171 | 172 | self.vsLabel = QLabel(self) 173 | self.vsLabel.setText('vs') 174 | self.vsLabelFont = QFont("Calibri", 12) 175 | self.vsLabel.setFont(self.vsLabelFont) 176 | self.vsLabel.setGeometry(QRect(420, 177, 80, 50)) 177 | 178 | self.comboBox2 = QComboBox(self) 179 | self.comboBox2.addItem('Current') 180 | self.comboBox2.addItem('Voltage') 181 | self.comboBox2.addItem('Charge') 182 | self.comboBox2.addItem('Flux') 183 | self.comboBox2.addItem('Time') 184 | self.comboBox2.addItem('Resistance') 185 | self.comboBox2.move(455, 188) 186 | 187 | self.valueQLabel = QLabel(self) 188 | self.valueQLabel.setPixmap(self.pixmap) 189 | self.valueQLabel.setToolTip(' Values to be plotted. \n 1st Argument will \n' + 190 | ' be on the x-axis and \n 2nd argument on \n y-axis') 191 | self.valueQLabel.move(563,185) 192 | 193 | 194 | #Display On same plot checkbox? 195 | self.dispSamePlotLabel = QLabel(self) 196 | self.dispSamePlotLabel.setText('Display on Same Plot:') 197 | self.dispSamePlotLabel.setFont(self.otherWritingFont) 198 | self.dispSamePlotLabel.setGeometry(QRect(30, 257 + 40, 220, 50)) 199 | 200 | self.dispSamePlotCheck = QCheckBox(self) 201 | self.dispSamePlotCheck.move(220, 267 + 40) 202 | 203 | self.dispSamePlotQLabel = QLabel(self) 204 | self.dispSamePlotQLabel.setPixmap(self.pixmap) 205 | self.dispSamePlotQLabel.setToolTip(' Display all the output \n Waveforms in the' + 206 | ' same plot') 207 | self.dispSamePlotQLabel.move(237,307) 208 | 209 | #Display Waveform checkbox? 210 | self.dispWavePlotLabel = QLabel(self) 211 | self.dispWavePlotLabel.setText('Display Waveform Now:') 212 | self.dispWavePlotLabel.setFont(self.otherWritingFont) 213 | self.dispWavePlotLabel.setGeometry(QRect(265, 257 + 40, 220, 50)) 214 | 215 | self.dispWavePlotCheck = QCheckBox(self) 216 | self.dispWavePlotCheck.move(453, 267 + 40) 217 | 218 | self.dispWaveQLabel = QLabel(self) 219 | self.dispWaveQLabel.setPixmap(self.pixmap) 220 | self.dispWaveQLabel.setToolTip(' Show Waveforms now?') 221 | self.dispWaveQLabel.move(470,307) 222 | 223 | 224 | #Save Waveform checkbox? 225 | self.savePlotLabel = QLabel(self) 226 | self.savePlotLabel.setText('Save Waveform:') 227 | self.savePlotLabel.setFont(self.otherWritingFont) 228 | self.savePlotLabel.setGeometry(QRect(30, 297 + 40, 220, 50)) 229 | 230 | self.savePlotCheck = QCheckBox(self) 231 | self.savePlotCheck.move(220, 307 + 40) 232 | 233 | self.savePlotQLabel = QLabel(self) 234 | self.savePlotQLabel.setPixmap(self.pixmap) 235 | self.savePlotQLabel.setToolTip(' Save the plots?') 236 | self.savePlotQLabel.move(237,347) 237 | 238 | 239 | #Dropdown list File Extension for saving the waveform 240 | self.fileExtPlotLabel = QLabel(self) 241 | self.fileExtPlotLabel.setText('File Extension:') 242 | self.fileExtPlotLabel.setFont(self.otherWritingFont) 243 | self.fileExtPlotLabel.setGeometry(QRect(265, 297 + 40, 220 + 40, 50)) 244 | 245 | self.comboBox3 = QComboBox(self) 246 | self.comboBox3.addItem('.pdf') 247 | self.comboBox3.addItem('.jpeg') 248 | self.comboBox3.addItem('.png') 249 | self.comboBox3.move(453, 307 + 40) 250 | self.comboBox3.resize(60,30) 251 | 252 | self.savePlotQLabel = QLabel(self) 253 | self.savePlotQLabel.setPixmap(self.pixmap) 254 | self.savePlotQLabel.setToolTip(' Extension of file for \n saving the plots.') 255 | self.savePlotQLabel.move(520,347) 256 | 257 | 258 | #Save path for saving the waveform 259 | self.savePathLabel = QLabel(self) 260 | self.savePathLabel.setText('Save Path:') 261 | self.savePathLabel.setFont(self.otherWritingFont) 262 | self.savePathLabel.setGeometry(QRect(30, 342 + 40, 220, 50)) 263 | 264 | self.savePathBox = QLineEdit(self) 265 | self.savePathBox.move(140, 352 + 40) 266 | self.savePathBox.resize(400,29) 267 | 268 | self.savePathQLabel = QLabel(self) 269 | self.savePathQLabel.setPixmap(self.pixmap) 270 | self.savePathQLabel.setToolTip(' Save path for the plots.') 271 | self.savePathQLabel.move(550,392) 272 | 273 | 274 | #DPI 275 | self.dpiLabel = QLabel(self) 276 | self.dpiLabel.setText('DPI:') 277 | self.dpiLabel.setFont(self.otherWritingFont) 278 | self.dpiLabel.setGeometry(QRect(30, 382 + 40, 220, 50)) 279 | 280 | self.dpiBox = QLineEdit(self) 281 | self.dpiBox.move(140, 392 + 40) 282 | self.dpiBox.resize(60,25) 283 | 284 | self.dpiQLabel = QLabel(self) 285 | self.dpiQLabel.setPixmap(self.pixmap) 286 | self.dpiQLabel.setToolTip(' Save path for the plots.') 287 | self.dpiQLabel.move(210,432) 288 | 289 | 290 | #Set Device Parameters (launches window for setting parameters for multiple Memristors) 291 | self.setParamButton = QPushButton('Set Device \n Parameters', self) 292 | self.setParamButton.resize(130, 50) 293 | self.setParamButton.move(240, 500) 294 | 295 | self.setParamButton.setStyleSheet('QPushButton {background-color: #A3C1DA; color: darkgreen;}') 296 | self.setParamButton.setFont(self.buttonFont) 297 | self.setParamButton.clicked.connect(self.setMemristorParameters) 298 | 299 | self.setParamQLabel = QLabel(self) 300 | self.setParamQLabel.setPixmap(self.pixmap) 301 | self.setParamQLabel.setToolTip(' Set parameters for all \n' + 302 | ' the Memristors') 303 | self.setParamQLabel.move(380,510) 304 | 305 | 306 | #Set waveforms (launches window to input waveform for multiple Memristors) 307 | self.setWavesButton = QPushButton('Set Waveforms', self) 308 | self.setWavesButton.resize(130, 50) 309 | self.setWavesButton.move(490, 500) 310 | 311 | self.setWavesButton.setStyleSheet('QPushButton {background-color: #A3C1DA; color: darkgreen;}') 312 | self.setWavesButton.setFont(self.buttonFont) 313 | self.setWavesButton.clicked.connect(self.setWaveforms) 314 | 315 | self.setWavesQLabel = QLabel(self) 316 | self.setWavesQLabel.setPixmap(self.pixmap) 317 | self.setWavesQLabel.setToolTip(' Set input Waveforms \n'+ 318 | ' for different Memristors') 319 | self.setWavesQLabel.move(630,510) 320 | 321 | 322 | #Run Simulation 323 | self.runSimButton = QPushButton('Run Simulation', self) 324 | self.runSimButton.resize(130, 50) 325 | self.runSimButton.move(370, 570) 326 | 327 | self.runSimButton.setStyleSheet('QPushButton {background-color: #A3C1DA; color: red;}') 328 | self.runSimButton.setFont(self.buttonFont) 329 | self.runSimButton.clicked.connect(self.runSimulation) 330 | 331 | self.runSimQLabel = QLabel(self) 332 | self.runSimQLabel.setPixmap(self.pixmap) 333 | self.runSimQLabel.setToolTip(' Run the simulations. \n'+ 334 | ' Can take some time depending \n' + 335 | ' on comutational resources') 336 | self.runSimQLabel.move(510,580) 337 | 338 | 339 | #Form to change the paramters of the default Memristor 340 | def changeDefaultParameters(self): 341 | self.txtD = QLineEdit(self) 342 | self.txtR_on = QLineEdit(self) 343 | self.txtR_off = QLineEdit(self) 344 | self.txtW = QLineEdit(self) 345 | self.txtMobility = QLineEdit(self) 346 | self.txtPolarity = QLineEdit(self) 347 | self.memristorTypeCB = QComboBox(self) 348 | self.memristorTypeCB.addItem('Ideal') 349 | btnOk = QPushButton('OK', self) 350 | 351 | self.DPGroupBox = QGroupBox("Default Paramters:") 352 | self.DPGroupBox.setStyleSheet('QGroupBox {color: blue; font:bold 14px}') 353 | self.DPGroupBox.move(300, 300) 354 | layout = QFormLayout() 355 | 356 | layout.addRow(QLabel("D (nm):"), self.txtD) 357 | layout.addRow(QLabel("R_on (\u03A9):"), self.txtR_on) 358 | layout.addRow(QLabel("R_off (\u03A9):"), self.txtR_off) 359 | layout.addRow(QLabel("W_0 (nm):"), self.txtW) 360 | layout.addRow(QLabel("Mobility (pm/s):"), self.txtMobility) 361 | layout.addRow(QLabel("Polarity (\u03B7):"), self.txtPolarity) 362 | layout.addRow(QLabel("Type:"), self.memristorTypeCB) 363 | layout.addRow(QLabel(), btnOk) 364 | self.DPGroupBox.setLayout(layout) 365 | 366 | btnOk.clicked.connect(self.readAndUpdateDefaultParameters) 367 | 368 | 369 | #Reads and updates the paramters of the default Memristor 370 | def readAndUpdateDefaultParameters(self): 371 | if(self.txtD.text() != ''): 372 | self.D = float(self.txtD.text()) * 10**-9 373 | if(self.txtR_on.text() != ''): 374 | self.R_on = float(self.txtR_on.text()) 375 | if(self.txtR_off.text() != ''): 376 | self.R_off = float(self.txtR_off.text()) 377 | if(self.txtW.text() != ''): 378 | self.W_0 = float(self.txtW.text()) * 10**-9 379 | if(self.txtMobility.text() != ''): 380 | self.mobility = float(self.txtMobility.text()) * 10**-12 381 | if(self.txtPolarity.text() != ''): 382 | self.polarity = int(self.txtPolarity.text()) 383 | self.calculateFixedParameters() 384 | self.memristorType = self.memristorTypeCB.currentText() 385 | self.drawBackgroundImage() 386 | self.close() 387 | self.DPGroupBox.close() 388 | self.__init__(self.windowLength, self.windowBreadth) 389 | 390 | 391 | #Calculates default fixed dependent parameters 392 | def calculateFixedParameters(self): 393 | self.Q_0 = (self.D ** 2) / (self.mobility * self.R_on) 394 | self.R_delta = self.R_off - self.R_on 395 | self.R_0 = self.R_on * (self.W_0 / self.D) + self.R_off * (1 - self.W_0 / self.D) 396 | 397 | 398 | #Displays the default paramters of a memristor 399 | def displayDefaultParameters(self): 400 | #Create Default Parameters 401 | self.useDFParamsLabel = QLabel(self) 402 | self.useDFParamsLabel.setText('Default Parameters:') 403 | #self.useDFParamsLabelFont.setUnderline(True) 404 | self.useDFParamsLabel.setFont(self.writingFont) 405 | self.useDFParamsLabel.setGeometry(QRect(650, 75, 220, 50)) 406 | 407 | self.DFParamsQLabel = QLabel(self) 408 | self.DFParamsQLabel.setPixmap(self.pixmap) 409 | self.DFParamsQLabel.setToolTip('Default Parameters when \nno input is provided.') 410 | self.DFParamsQLabel.move(860,85) 411 | 412 | self.paramFont = QFont("Arial", 12, QFont.Bold) 413 | self.DLabel = QLabel(self) 414 | self.DLabel.setText('D = ' + str(self.D / 10**-9) + ' nm') 415 | self.DLabel.setFont(self.paramFont) 416 | self.DLabel.setGeometry(QRect(675, 110, 220, 50)) 417 | 418 | self.RoNLabel = QLabel(self) 419 | self.RoNLabel.setText('R_on = ' + str(self.R_on) + ' \u03A9') 420 | self.RoNLabel.setFont(self.paramFont) 421 | self.RoNLabel.setGeometry(QRect(675, 135, 220, 50)) 422 | 423 | self.RoFFLabel = QLabel(self) 424 | self.RoFFLabel.setText('R_off = ' + str(self.R_off) + ' \u03A9') 425 | self.RoFFLabel.setFont(self.paramFont) 426 | self.RoFFLabel.setGeometry(QRect(675, 160, 220, 50)) 427 | 428 | self.WLabel = QLabel(self) 429 | self.WLabel.setText('W_0 = ' + str(self.W_0/10**-9) +' nm') 430 | self.WLabel.setFont(self.paramFont) 431 | self.WLabel.setGeometry(QRect(675, 185, 220, 50)) 432 | 433 | self.mobilityLabel = QLabel(self) 434 | self.mobilityLabel.setText('Mobility (\u03BC) = '+str(self.mobility/10**-12) + ' pm/s') 435 | self.mobilityLabel.setFont(self.paramFont) 436 | self.mobilityLabel.setGeometry(QRect(675, 210, 220, 50)) 437 | 438 | self.polarityLabel = QLabel(self) 439 | self.polarityLabel.setText('Polarity (\u03B7) = ' + str(self.polarity)) 440 | self.polarityLabel.setFont(self.paramFont) 441 | self.polarityLabel.setGeometry(QRect(675, 235, 220, 50)) 442 | 443 | self.QLabel = QLabel(self) 444 | self.QLabel.setText('Q_0 = '+str(self.Q_0/10**-6) +' \u03BCC') 445 | self.QLabel.setFont(self.paramFont) 446 | self.QLabel.setGeometry(QRect(675, 260, 220, 50)) 447 | 448 | self.R0Label = QLabel(self) 449 | self.R0Label.setText('R_0 = '+str(self.R_0)+' \u03A9') 450 | self.R0Label.setFont(self.paramFont) 451 | self.R0Label.setGeometry(QRect(675, 285, 220, 50)) 452 | 453 | self.polarityLabel = QLabel(self) 454 | self.polarityLabel.setText('\u0394R = '+str(self.R_delta)+' \u03A9') 455 | self.polarityLabel.setFont(self.paramFont) 456 | self.polarityLabel.setGeometry(QRect(675, 310, 220, 50)) 457 | 458 | self.typeLabel = QLabel(self) 459 | self.typeLabel.setText('Type : ' + str(self.memristorType)) 460 | self.typeLabel.setFont(self.paramFont) 461 | self.typeLabel.setGeometry(QRect(675, 335, 220, 50)) 462 | 463 | 464 | #Reads all the values in the different fields of the home screen 465 | def readValues(self): 466 | self.preferences = {} 467 | 468 | if(self.memristorBox.text() != ''): 469 | self.numberOfMemristors = int(self.memristorBox.text()) 470 | self.preferences['number'] = self.numberOfMemristors 471 | 472 | if(self.samplingFrequencyBox.text() != ''): 473 | self.samplingFrequency = int(self.samplingFrequencyBox.text()) 474 | self.preferences['sampling_frequency'] = self.samplingFrequency 475 | 476 | if(self.dpiBox.text() != ''): 477 | self.dpi = int(self.dpiBox.text()) 478 | self.preferences['dpi'] = self.dpi 479 | 480 | if(self.savePathBox.text() != ''): 481 | self.savePath = self.savePathBox.text() 482 | self.preferences['save_path'] = self.savePath 483 | 484 | self.preferences['x_axis'] = self.comboBox1.currentText() 485 | self.preferences['y_axis'] = self.comboBox2.currentText() 486 | self.preferences['format'] = self.comboBox3.currentText() 487 | 488 | self.preferences['display_same_plot'] = self.dispSamePlotCheck.isChecked() 489 | self.preferences['display_wave'] = self.dispWavePlotCheck.isChecked() 490 | self.preferences['save_plot'] = self.savePlotCheck.isChecked() 491 | 492 | 493 | #Calls the core function and runs all the associated methods 494 | def runSimulation(self): 495 | if(self.smp != None): 496 | self.setMemristorParametersOKButtonClicked = self.smp.getOKButton() 497 | if(self.sw != None): 498 | self.setWaveformsOKButtonClicked = self.sw.getOKButton() 499 | 500 | self.readValues() 501 | self.collectUserInput() 502 | self.data = {} 503 | if(self.setMemristorParametersOKButtonClicked == False and self.setWaveformsOKButtonClicked == False): 504 | self.data['memristor_parameters'] = self.defaultMemristorParameters 505 | self.data['wave_parameters'] = self.defaultWaveParameters 506 | 507 | elif(self.setMemristorParametersOKButtonClicked == True and self.setWaveformsOKButtonClicked == False): 508 | self.data['memristor_parameters'] = self.memristorParameters 509 | self.data['wave_parameters'] = self.defaultWaveParameters 510 | 511 | elif(self.setMemristorParametersOKButtonClicked == False and self.setWaveformsOKButtonClicked == True): 512 | self.data['memristor_parameters'] = self.defaultMemristorParameters 513 | self.data['wave_parameters'] = self.waveParameters 514 | 515 | elif(self.setMemristorParametersOKButtonClicked == True and self.setWaveformsOKButtonClicked == True): 516 | self.data['memristor_parameters'] = self.memristorParameters 517 | self.data['wave_parameters'] = self.waveParameters 518 | 519 | self.data['preferences'] = self.preferences 520 | 521 | cntrl.multiple_memristor_circuits(self.data) 522 | 523 | 524 | 525 | #Launches window to set the default paramters of the Memristor (connected to Set Paramters button) 526 | def setMemristorParameters(self): 527 | self.readValues() 528 | self.smp = semp.set_memristor_parameters(self.numberOfMemristors) 529 | 530 | 531 | #Launches window to set the waveforms (connected to Set Waveforms button) 532 | def setWaveforms(self): 533 | self.readValues() 534 | self.sw = sew.set_waveforms(self.numberOfMemristors) 535 | 536 | 537 | #Getter functions 538 | def collectUserInput(self): 539 | print(self.setWaveformsOKButtonClicked) 540 | if(self.setMemristorParametersOKButtonClicked == True): 541 | self.memristorParameters = self.smp.getMemristorParamters() 542 | for i in self.memristorParameters: 543 | self.memristorParameters[i] = [self.defaultMemristorParameters[i][0] if x == None else x for x in self.memristorParameters[i]] 544 | 545 | if(self.setWaveformsOKButtonClicked == True): 546 | self.waveParameters = self.sw.getWaveParameters() 547 | for i in self.waveParameters: 548 | self.waveParameters[i] = [self.defaultWaveParameters[i][0] if x == None else x for x in self.waveParameters[i]] 549 | 550 | 551 | def getMemristorInput(self): 552 | return self.memristorParameters 553 | 554 | def getWaveInput(self): 555 | return self.waveParameters 556 | 557 | def getUserPreferences(self): 558 | return self.preferences 559 | 560 | 561 | if __name__ == '__main__': 562 | windowLength = 900 563 | windowBreadth = 800 564 | app = 0 565 | app = QApplication(sys.argv) 566 | gui = memristor_GUI(windowLength, windowBreadth) 567 | sys.exit(app.exec_()) 568 | -------------------------------------------------------------------------------- /GUI/question1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuttaAbhigyan/Memristor-Simulation-Using-Python/267ea3a8972176f3fa7f6186501b510ebabbd161/GUI/question1.png -------------------------------------------------------------------------------- /GUI/set_memristor_parameters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon Mar 18 18:54:20 2019 5 | 6 | @author: abhigyan 7 | """ 8 | from PyQt5.QtGui import * 9 | from PyQt5.QtWidgets import * 10 | from PyQt5.QtCore import * 11 | 12 | """Class to take in various paramters of the Memristors to be simulated""" 13 | class set_memristor_parameters(QMainWindow): 14 | 15 | #Create and launch the main window 16 | def __init__(self, numberOfMemristors): 17 | super(set_memristor_parameters, self).__init__() 18 | self.setMemristorParametersOKButtonClicked = False 19 | self.numberOfMemristors = numberOfMemristors 20 | self.windowLength = 110 * self.numberOfMemristors + 280 21 | self.windowBreadth = 550 22 | self.setGeometry(300, 300, self.windowLength, self.windowBreadth) 23 | self.setWindowTitle('Memristor Parameters') 24 | self.setWindowIcon(QIcon('memristor_icon.ico')) 25 | 26 | #Sets backgorund Image 27 | backgroundImage = QImage('memristor1.jpg') 28 | backgroundScaledImage = backgroundImage.scaled(QSize(self.windowLength, 29 | self.windowBreadth)) 30 | palette = QPalette() 31 | palette.setBrush(10, QBrush(backgroundScaledImage)) 32 | self.setPalette(palette) 33 | 34 | #Sets Fonts 35 | self.labelFont = QFont("Arial", 13, QFont.Bold) 36 | self.buttonFont = QFont('Times', 13) 37 | 38 | self.home() 39 | self.show() 40 | 41 | 42 | #Create the homescreen 43 | def home(self): 44 | 45 | #Window title 46 | self.titleLabel = QLabel(self) 47 | self.titleLabel.setText('Memristor Parameters') 48 | self.titleFont = QFont("Times", 18, QFont.Bold) 49 | self.titleLabel.setStyleSheet('QLabel{color:purple}') 50 | self.titleFont.setUnderline(True) 51 | self.titleLabel.setFont(self.titleFont) 52 | self.titleLabel.setGeometry(QRect(self.windowLength/2 - 120, 10, 500, 50)) 53 | 54 | #Device numbers title 55 | self.DeviceLabel = QLabel(self) 56 | self.DeviceLabel.setText('Device:') 57 | self.DeviceLabelFont = QFont("Calibri", 14, QFont.Bold) 58 | self.DeviceLabel.setStyleSheet('QLabel{color:blue}') 59 | self.DeviceLabel.setFont(self.DeviceLabelFont) 60 | self.DeviceLabel.setGeometry(QRect(35, 60, 100, 50)) 61 | 62 | 63 | #Parameter labels 64 | self.DLabel = QLabel(self) 65 | self.DLabel.setText('D (nm):') 66 | self.DLabel.setFont(self.labelFont) 67 | self.DLabel.setGeometry(QRect(55, 100, 70, 50)) 68 | 69 | self.RoNLabel = QLabel(self) 70 | self.RoNLabel.setText('R_on (\u03A9):') 71 | self.RoNLabel.setFont(self.labelFont) 72 | self.RoNLabel.setGeometry(QRect(37, 140, 90, 50)) 73 | 74 | self.RoFFLabel = QLabel(self) 75 | self.RoFFLabel.setText('R_off (\u03A9):') 76 | self.RoFFLabel.setFont(self.labelFont) 77 | self.RoFFLabel.setGeometry(QRect(36, 180, 90, 50)) 78 | 79 | self.WLabel = QLabel(self) 80 | self.WLabel.setText('W_0 (nm):') 81 | self.WLabel.setFont(self.labelFont) 82 | self.WLabel.setGeometry(QRect(33, 220, 90, 50)) 83 | 84 | self.mobLabel = QLabel(self) 85 | self.mobLabel.setText('Mobility (\u03BC):') 86 | self.mobLabel.setFont(self.labelFont) 87 | self.mobLabel.setGeometry(QRect(19, 260, 100, 50)) 88 | 89 | self.polLabel = QLabel(self) 90 | self.polLabel.setText('Polarity (\u03B7):') 91 | self.polLabel.setFont(self.labelFont) 92 | self.polLabel.setGeometry(QRect(22, 300, 100, 50)) 93 | 94 | self.typeLabel = QLabel(self) 95 | self.typeLabel.setText('Type:') 96 | self.typeLabel.setFont(self.labelFont) 97 | self.typeLabel.setGeometry(QRect(73, 340, 100, 50)) 98 | 99 | 100 | #Stores widgets to take in parameters 101 | self.DValueFields = [] 102 | self.R_onValueFields = [] 103 | self.R_offValueFields = [] 104 | self.W_0ValueFields = [] 105 | self.mobilityValueFields = [] 106 | self.polarityValueFields = [] 107 | self.memristorTypeValueFields = [] 108 | 109 | 110 | #Crestes the various widgets to take in Memristor Paramters 111 | for i in range(0, self.numberOfMemristors): 112 | 113 | numberLabel = QLabel(self) 114 | numberLabel.setText(str(i+1)) 115 | numberLabelFont = QFont("Calibri", 14, QFont.Bold) 116 | numberLabel.setStyleSheet('QLabel{color:blue}') 117 | numberLabel.setFont(self.DeviceLabelFont) 118 | numberLabel.setGeometry(QRect(75 + (1+i)*120, 62, 50, 50)) 119 | 120 | 121 | DVFBox = QLineEdit(self) 122 | DVFBox.move(55 + (1+i)*120, 112) 123 | DVFBox.resize(60,25) 124 | self.DValueFields.append(DVFBox) 125 | 126 | R_oNBox = QLineEdit(self) 127 | R_oNBox.move(55 + (1+i)*120, 152) 128 | R_oNBox.resize(60, 25) 129 | self.R_onValueFields.append(R_oNBox) 130 | 131 | R_offBox = QLineEdit(self) 132 | R_offBox.move(55 + (1+i)*120, 192) 133 | R_offBox.resize(60,25) 134 | self.R_offValueFields.append(R_offBox) 135 | 136 | W_0Box = QLineEdit(self) 137 | W_0Box.move(55 + (1+i)*120, 232) 138 | W_0Box.resize(60,25) 139 | self.W_0ValueFields.append(W_0Box) 140 | 141 | mobilityBox = QLineEdit(self) 142 | mobilityBox.move(55 + (1+i)*120, 272) 143 | mobilityBox.resize(60,25) 144 | self.mobilityValueFields.append(mobilityBox) 145 | 146 | polarityBox = QLineEdit(self) 147 | polarityBox.move(55 + (1+i)*120, 312) 148 | polarityBox.resize(60,25) 149 | self.polarityValueFields.append(polarityBox) 150 | 151 | comboBox = QComboBox(self) 152 | comboBox.addItem('Ideal') 153 | #comboBox3.addItem('Strukov') 154 | #comboBox.addItem('Prodromakis') 155 | #comboBox.addItem('Biolek') 156 | comboBox.move(55 + (1+i)*120, 353) 157 | comboBox.resize(80,25) 158 | self.memristorTypeValueFields.append(comboBox) 159 | 160 | #Creates OK and Cancel button 161 | self.OKButton = QPushButton('OK', self) 162 | self.OKButton.resize(100, 40) 163 | self.OKButton.move(self.windowLength/2 -150, 473) 164 | 165 | self.OKButton.setStyleSheet('QPushButton {color: darkgreen;}') 166 | self.OKButtonFont = QFont('Times', 13) 167 | self.OKButton.setFont(self.OKButtonFont) 168 | self.OKButton.clicked.connect(self.readParameters) 169 | 170 | self.cancelButton = QPushButton('Cancel', self) 171 | self.cancelButton.resize(100, 40) 172 | self.cancelButton.move(self.windowLength/2 , 473) 173 | 174 | self.cancelButton.setStyleSheet('QPushButton {color: darkgreen;}') 175 | self.cancelButtonFont = QFont('Times', 13) 176 | self.cancelButton.setFont(self.cancelButtonFont) 177 | self.cancelButton.clicked.connect(self.close) 178 | 179 | 180 | #Reads the parameters input by user 181 | def readParameters(self): 182 | self.setMemristorParametersOKButtonClicked = True 183 | 184 | self.D = [] 185 | self.R_on = [] 186 | self.R_off = [] 187 | self.W_0 = [] 188 | self.mobility = [] 189 | self.polarity = [] 190 | self.type = [] 191 | self.pValues= [] 192 | 193 | for i in range(0, self.numberOfMemristors): 194 | if(self.DValueFields[i].text() != ''): 195 | self.D.append(float(self.DValueFields[i].text()) * 10**-9) 196 | else: 197 | self.D.append(None) 198 | 199 | if(self.R_onValueFields[i].text() != ''): 200 | self.R_on.append(float(self.R_onValueFields[i].text())) 201 | else: 202 | self.R_on.append(None) 203 | 204 | if(self.R_offValueFields[i].text() != ''): 205 | self.R_off.append(float(self.R_offValueFields[i].text())) 206 | else: 207 | self.R_off.append(None) 208 | 209 | if(self.W_0ValueFields[i].text() != ''): 210 | self.W_0.append(float(self.W_0ValueFields[i].text())) 211 | else: 212 | self.W_0.append(None) 213 | 214 | if(self.mobilityValueFields[i].text() != ''): 215 | self.mobility.append(float(self.mobilityValueFields[i].text() * 10**-12)) 216 | else: 217 | self.mobility.append(None) 218 | 219 | if(self.polarityValueFields[i].text() != ''): 220 | self.polarity.append(float(self.polarityValueFields[i].text())) 221 | else: 222 | self.polarity.append(None) 223 | self.type.append(self.memristorTypeValueFields[i].currentText()) 224 | 225 | self.close() 226 | 227 | 228 | #Getter functions 229 | def getMemristorParamters(self): 230 | parameterDictionary = {} 231 | parameterDictionary['D'] = self.D[:] 232 | parameterDictionary['R_on'] = self.R_on[:] 233 | parameterDictionary['R_off'] = self.R_off[:] 234 | parameterDictionary['W_0'] = self.W_0[:] 235 | parameterDictionary['mobility'] = self.mobility[:] 236 | parameterDictionary['polarity'] = self.polarity[:] 237 | parameterDictionary['type'] = self.type[:] 238 | return parameterDictionary 239 | 240 | def getOKButton(self): 241 | return self.setMemristorParametersOKButtonClicked 242 | -------------------------------------------------------------------------------- /GUI/set_waveforms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon Mar 18 18:56:58 2019 5 | 6 | @author: abhigyan 7 | """ 8 | from PyQt5.QtGui import * 9 | from PyQt5.QtWidgets import * 10 | from PyQt5.QtCore import * 11 | 12 | """Class to set paramters of the input waveforms""" 13 | 14 | class set_waveforms(QMainWindow): 15 | 16 | #Create and launch the main window 17 | def __init__(self, numberOfMemristors): 18 | super(set_waveforms, self).__init__() 19 | self.setWaveformsOKButtonClicked = False 20 | self.numberOfMemristors = numberOfMemristors 21 | self.windowLength = 130 * self.numberOfMemristors + 210 22 | self.windowBreadth = 500 23 | self.setGeometry(300, 300, self.windowLength, self.windowBreadth) 24 | self.setWindowTitle('Input Waveforms') 25 | self.setWindowIcon(QIcon('memristor_icon.ico')) 26 | 27 | #Sets backgorund Image 28 | backgroundImage = QImage('memristor1.jpg') 29 | backgroundScaledImage = backgroundImage.scaled(QSize(self.windowLength, 30 | self.windowBreadth)) 31 | palette = QPalette() 32 | palette.setBrush(10, QBrush(backgroundScaledImage)) 33 | self.setPalette(palette) 34 | 35 | #Sets Fonts 36 | self.labelFont = QFont("Arial", 13, QFont.Bold) 37 | self.buttonFont = QFont('Times', 13) 38 | 39 | self.home() 40 | self.show() 41 | 42 | 43 | 44 | #Create the homescreen 45 | def home(self): 46 | #Window title 47 | self.titleLabel = QLabel(self) 48 | self.titleLabel.setText('Input Waveforms') 49 | self.titleFont = QFont("Times", 18, QFont.Bold) 50 | self.titleLabel.setStyleSheet('QLabel{color:purple}') 51 | self.titleFont.setUnderline(True) 52 | self.titleLabel.setFont(self.titleFont) 53 | self.titleLabel.setGeometry(QRect(self.windowLength/2 - 120, 10, 500, 50)) 54 | 55 | #Device numbers 56 | self.DeviceLabel = QLabel(self) 57 | self.DeviceLabel.setText('Device:') 58 | self.DeviceLabelFont = QFont("Calibri", 14, QFont.Bold) 59 | self.DeviceLabel.setStyleSheet('QLabel{color:blue}') 60 | self.DeviceLabel.setFont(self.DeviceLabelFont) 61 | self.DeviceLabel.setGeometry(QRect(35, 60, 100, 50)) 62 | 63 | 64 | #Parameter labels 65 | self.typeLabel = QLabel(self) 66 | self.typeLabel.setText('Type:') 67 | self.typeLabel.setFont(self.labelFont) 68 | self.typeLabel.setGeometry(QRect(87, 100, 70, 50)) 69 | 70 | self.amplitudeLabel = QLabel(self) 71 | self.amplitudeLabel.setText('Amplitude (V):') 72 | self.amplitudeLabel.setFont(self.labelFont) 73 | self.amplitudeLabel.setGeometry(QRect(15, 140, 120, 50)) 74 | 75 | self.omegaLabel = QLabel(self) 76 | self.omegaLabel.setText('Omega (\u03C9):') 77 | self.omegaLabel.setFont(self.labelFont) 78 | self.omegaLabel.setGeometry(QRect(37, 180, 100, 50)) 79 | 80 | self.pwLabel = QLabel(self) 81 | self.pwLabel.setText('Pulsewidth:') 82 | self.pwLabel.setFont(self.labelFont) 83 | self.pwLabel.setGeometry(QRect(35, 220, 100, 50)) 84 | 85 | self.startLabel = QLabel(self) 86 | self.startLabel.setText('Start:') 87 | self.startLabel.setFont(self.labelFont) 88 | self.startLabel.setGeometry(QRect(85, 260, 100, 50)) 89 | 90 | self.stopLabel = QLabel(self) 91 | self.stopLabel.setText('Stop:') 92 | self.stopLabel.setFont(self.labelFont) 93 | self.stopLabel.setGeometry(QRect(85, 300, 100, 50)) 94 | 95 | self.typeValueFields = [] 96 | self.amplitudeValueFields = [] 97 | self.omegaValueFields = [] 98 | self.pwValueFields = [] 99 | self.startValueFields = [] 100 | self.stopValueFields = [] 101 | #self.memristorTypeValueFields = [] 102 | 103 | #Creates the widgets to take in paramters of the waveforms 104 | for i in range(0, self.numberOfMemristors): 105 | 106 | numberLabel = QLabel(self) 107 | numberLabel.setText(str(i+1)) 108 | numberLabelFont = QFont("Calibri", 14, QFont.Bold) 109 | numberLabel.setStyleSheet('QLabel{color:blue}') 110 | numberLabel.setFont(self.DeviceLabelFont) 111 | numberLabel.setGeometry(QRect(75 + (1+i)*120, 62, 50, 50)) 112 | 113 | typeBox = QComboBox(self) 114 | typeBox.addItem('Sine') 115 | typeBox.addItem('Cosine') 116 | typeBox.addItem('Uniform Pulse') 117 | typeBox.addItem('Non-Uniform Amplitude Pulse') 118 | typeBox.addItem('Custom Pulse') 119 | typeBox.move(55 + (1+i)*120, 112) 120 | typeBox.resize(80,25) 121 | self.typeValueFields.append(typeBox) 122 | 123 | amplitudeBox = QLineEdit(self) 124 | amplitudeBox.move(55 + (1+i)*120, 152) 125 | amplitudeBox.resize(80, 25) 126 | self.amplitudeValueFields.append(amplitudeBox) 127 | 128 | omegaBox = QLineEdit(self) 129 | omegaBox.move(55 + (1+i)*120, 192) 130 | omegaBox.resize(80,25) 131 | self.omegaValueFields.append(omegaBox) 132 | 133 | pwBox = QLineEdit(self) 134 | pwBox.move(55 + (1+i)*120, 232) 135 | pwBox.resize(80,25) 136 | self.pwValueFields.append(pwBox) 137 | 138 | startBox = QLineEdit(self) 139 | startBox.move(55 + (1+i)*120, 272) 140 | startBox.resize(80,25) 141 | self.startValueFields.append(startBox) 142 | 143 | stopBox = QLineEdit(self) 144 | stopBox.move(55 + (1+i)*120, 312) 145 | stopBox.resize(80,25) 146 | self.stopValueFields.append(stopBox) 147 | 148 | #Creates OK button and Cancel button 149 | self.OKButton = QPushButton('OK', self) 150 | self.OKButton.resize(100, 40) 151 | self.OKButton.move(self.windowLength/2 -150, 423) 152 | 153 | self.OKButton.setStyleSheet('QPushButton {color: darkgreen;}') 154 | self.OKButton.setFont(self.buttonFont) 155 | self.OKButton.clicked.connect(self.readParameters) 156 | 157 | self.cancelButton = QPushButton('Cancel', self) 158 | self.cancelButton.resize(100, 40) 159 | self.cancelButton.move(self.windowLength/2 , 423) 160 | 161 | self.cancelButton.setStyleSheet('QPushButton {color: darkgreen;}') 162 | self.cancelButton.setFont(self.buttonFont) 163 | self.cancelButton.clicked.connect(self.close) 164 | 165 | 166 | #Reads the paramters input by the user 167 | def readParameters(self): 168 | self.setWaveformsOKButtonClicked = True 169 | self.type = [] 170 | self.amplitude = [] 171 | self.omega = [] 172 | self.pulsewidth = [] 173 | self.start = [] 174 | self.stop = [] 175 | 176 | for i in range(0, self.numberOfMemristors): 177 | if(self.amplitudeValueFields[i].text() != ''): 178 | self.amplitude.append(float(self.amplitudeValueFields[i].text())) 179 | else: 180 | self.amplitude.append(None) 181 | if(self.omegaValueFields[i].text() != ''): 182 | self.omega.append(float(self.omegaValueFields[i].text())) 183 | else: 184 | self.omega.append(None) 185 | if(self.pwValueFields[i].text() != ''): 186 | self.pulsewidth.append(float(self.pwValueFields[i].text())) 187 | else: 188 | self.pulsewidth.append(None) 189 | if(self.startValueFields[i].text() != ''): 190 | self.start.append(float(self.startValueFields[i].text())) 191 | else: 192 | self.start.append(None) 193 | if(self.stopValueFields[i].text() != ''): 194 | self.stop.append(float(self.stopValueFields[i].text())) 195 | else: 196 | self.stop.append(None) 197 | self.type.append(self.typeValueFields[i].currentText()) 198 | 199 | self.close() 200 | 201 | 202 | #Getter function 203 | def getWaveParameters(self): 204 | parameterDictionary = {} 205 | parameterDictionary['type'] = self.type[:] 206 | parameterDictionary['amplitude'] = self.amplitude[:] 207 | parameterDictionary['omega'] = self.omega[:] 208 | parameterDictionary['pulsewidth'] = self.pulsewidth[:] 209 | parameterDictionary['start'] = self.start[:] 210 | parameterDictionary['stop'] = self.stop[:] 211 | return parameterDictionary 212 | 213 | def getOKButton(self): 214 | return self.setWaveformsOKButtonClicked 215 | 216 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Memristor-Simulation-Using-Python 2 | In this repository I have simulated Memristors using Python3 and also created GUI for easy use by researchers to visualise the functioning of a Memristor. 3 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 1.) Better Documentation 2 | 2.) More Memristor Models (Strukov, Biolek, Prodromakis) 3 | 3.) Better error handling 4 | 4.) More functions 5 | -------------------------------------------------------------------------------- /circuit_creator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /circuit_creator/controller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sun Feb 24 16:00:44 2019 5 | 6 | @author: abhigyan 7 | """ 8 | 9 | import matplotlib.pyplot as plt 10 | import functions as fn 11 | import memristor_scipy as mem 12 | import numpy as np 13 | 14 | 15 | class create_memristor_circuit(object): 16 | 17 | def __init__(self, voltageFunction, memristor, time1, time2, samplingFrequency): 18 | self.voltageFunction = voltageFunction 19 | self.memristor = memristor 20 | self.memristor.calculate_fixed_parameters() 21 | self.time1 = time1 22 | self.time2 = time2 23 | self.samples = int(samplingFrequency * (self.time2 - self.time1)) 24 | self.timeInstants = np.linspace(self.time1, self.time2, self.samples) 25 | 26 | 27 | def calculate_voltage_dependent_params(self, time1, time2): 28 | self.voltageFunction.evaluate_function(time2) 29 | self.voltageFunction.evaluate_integration_function(time1, time2) 30 | self.instantaneousVoltage = self.voltageFunction.return_evaluation() 31 | self.delFlux = self.voltageFunction.return_integration_evaluation() 32 | 33 | self.memristor.calculate_time_variable_parameters(self.delFlux[0]) 34 | self.memristor.calculate_current(self.instantaneousVoltage) 35 | self.memristor.calculate_charge() 36 | 37 | self.memristor.save_flux_history() 38 | self.instantaneousCurrent = self.memristor.get_current() 39 | self.instantaneousTime = time2 40 | self.instantaneousCharge = self.memristor.get_charge() 41 | self.instantaneousFlux = self.memristor.get_flux() 42 | self.instantaneousResistance = self.memristor.get_resistance() 43 | 44 | def create_value_matrix(self): 45 | self.current = np.array([]) 46 | self.charge = np.array([]) 47 | self.voltage = np.array([]) 48 | self.flux = np.array([]) 49 | self.resistance = np.array([]) 50 | self.time = np.array([]) 51 | 52 | for i in range(0, self.samples-1): 53 | self.calculate_voltage_dependent_params(self.timeInstants[i], self.timeInstants[i+1]) 54 | self.current = np.append(self.current, self.instantaneousCurrent) 55 | self.charge = np.append(self.charge, self.instantaneousCharge) 56 | self.voltage = np.append(self.voltage, self.instantaneousVoltage) 57 | self.flux = np.append(self.flux, self.instantaneousFlux) 58 | self.resistance = np.append(self.resistance, self.instantaneousResistance) 59 | self.time = np.append(self.time, self.instantaneousTime) 60 | 61 | 62 | def plot_function(self, x, y, label_x, label_y): 63 | self.x = getattr(self, x) 64 | self.y = getattr(self, y) 65 | plt.plot(self.x, self.y, linewidth = 0.7) 66 | plt.xlabel(label_x) 67 | plt.ylabel(label_y) 68 | 69 | def get_current(self): 70 | return self.current 71 | 72 | def get_charge(self): 73 | return self.charge 74 | 75 | def get_voltage(self): 76 | return self.voltage 77 | 78 | def get_flux(self): 79 | return self.flux 80 | 81 | def get_resistance(self): 82 | return self.resistance 83 | 84 | 85 | 86 | 87 | class multiple_memristor_circuits(object): 88 | 89 | waveDictionary = {'Sine':'sine_function', 'Cosine':'cosine_function', 90 | 'Uniform Pulse':'uniform_pulse_function', 91 | 'Non-Uniform Amplitude Pulse':'uniform_time_pulse_function', 92 | 'Custom Pulse':'custom_pulse_function'} 93 | 94 | valueDictionary = {'Current':'current', 'Voltage':'voltage', 'Charge':'charge', 95 | 'Flux':'flux', 'Time':'time', 'Resistance':'resistance'} 96 | 97 | def __init__(self, data): 98 | self.data = data 99 | print(self.data) 100 | self.memristorParameters = self.data['memristor_parameters'] 101 | self.waveParameters = self.data['wave_parameters'] 102 | self.preferences = self.data['preferences'] 103 | self.numberOfMemristors = self.data['preferences']['number'] 104 | self.defaultMemristor = False 105 | self.defaultWave = False 106 | 107 | 108 | if(self.numberOfMemristors != len(self.data['memristor_parameters']['D'])): 109 | self.defaultMemristor = True 110 | 111 | if(self.numberOfMemristors != len(self.data['wave_parameters']['type'])): 112 | self.defaultWave = True 113 | 114 | self.equalize_parameters() 115 | self.run_circuit() 116 | 117 | 118 | def equalize_parameters(self): 119 | self.memristors = [] 120 | self.waveFunctions = [] 121 | self.memristorCircuits = [] 122 | 123 | for i in self.memristorParameters: 124 | if(len(self.memristorParameters[i]) != self.numberOfMemristors): 125 | self.memristorParameters[i] = self.memristorParameters[i] * self.numberOfMemristors 126 | 127 | for i in self.waveParameters: 128 | if(len(self.waveParameters[i]) != self.numberOfMemristors): 129 | self.waveParameters[i] = self.waveParameters[i] * self.numberOfMemristors 130 | 131 | for i in range(0, self.numberOfMemristors): 132 | if(self.memristorParameters['type'][i] == 'Ideal'): 133 | memristor = mem.ideal_memristor(self.memristorParameters['D'][i], 134 | self.memristorParameters['W_0'][i], 135 | self.memristorParameters['R_on'][i], 136 | self.memristorParameters['R_off'][i], 137 | self.memristorParameters['mobility'][i], 138 | self.memristorParameters['polarity'][i]) 139 | self.memristors.append(memristor) 140 | 141 | 142 | for i in range(0, self.numberOfMemristors): 143 | wave = fn.functions(self.waveDictionary[self.waveParameters['type'][i]], 144 | self.waveParameters['amplitude'][i], 145 | self.waveParameters['omega'][i], 146 | self.waveParameters['pulsewidth'][i], 147 | self.waveParameters['start'][i] - 2, 148 | self.waveParameters['stop'][i] + 2) 149 | self.waveFunctions.append(wave) 150 | 151 | for i in range(0, self.numberOfMemristors): 152 | cmc = create_memristor_circuit(self.waveFunctions[i], self.memristors[i], 153 | self.waveParameters['start'][i], self.waveParameters['stop'][i], 154 | self.preferences['sampling_frequency']) 155 | self.memristorCircuits.append(cmc) 156 | 157 | 158 | 159 | def run_circuit(self): 160 | for i in self.memristorCircuits: 161 | i.create_value_matrix() 162 | 163 | yAxis = self.valueDictionary[self.preferences['y_axis']] 164 | xAxis = self.valueDictionary[self.preferences['x_axis']] 165 | yLabel = self.preferences['y_axis'] 166 | xLabel = self.preferences['x_axis'] 167 | 168 | 169 | if(self.preferences['dspc'] == True and self.preferences['dwpc'] == True): 170 | for i in self.memristorCircuits: 171 | i.plot_function(xAxis, yAxis, xLabel, yLabel) 172 | if(self.preferences['spc'] == True): 173 | plt.savefig(self.preferences['save_path'] + 'memrsitor_graph' + self.preferences['format'], 174 | self.preferences['dpi']) 175 | plt.show() 176 | 177 | 178 | elif(self.preferences['dspc'] == True and self.preferences['dwpc'] == False): 179 | for i in self.memristorCircuits: 180 | i.plot_function(xAxis, yAxis, xLabel, yLabel) 181 | if(self.preferences['spc'] == True): 182 | plt.savefig(self.preferences['save_path'] + 'memrsitor_graph' + self.preferences['format'], 183 | self.preferences['dpi']) 184 | 185 | elif(self.preferences['dspc'] == False and self.preferences['dwpc'] == True): 186 | count = 0 187 | for i in self.memristorCircuits: 188 | i.plot_function(xAxis, yAxis, xLabel, yLabel) 189 | if(self.preferences['spc'] == True): 190 | plt.savefig(self.preferences['save_path'] + 'memrsitor_graph'+ str(count) + self.preferences['format'], 191 | self.preferences['dpi']) 192 | count += 1 193 | plt.show() 194 | 195 | 196 | elif(self.preferences['dspc'] == False and self.preferences['dwpc'] == False): 197 | count = 0 198 | for i in self.memristorCircuits: 199 | i.plot_function(xAxis, yAxis, xLabel, yLabel) 200 | if(self.preferences['spc'] == True): 201 | plt.savefig(self.preferences['save_path'] + 'memrsitor_graph'+ str(count) + self.preferences['format'], 202 | self.preferences['dpi']) 203 | count += 1 204 | -------------------------------------------------------------------------------- /functions/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /functions/functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Feb 22 00:19:39 2019 5 | 6 | @author: abhigyan 7 | """ 8 | 9 | import scipy.integrate as spi 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | 13 | """This is the function class which can be used to create user defined functions. 14 | Currently the following functions are supported: 15 | -> Sine 16 | -> Cosine 17 | -> Unit Step function 18 | -> Pulse with uniform amplitude and uniform frequency 19 | -> Pulse with non-uniform amplitude and uniform frequency 20 | -> Pulse with non-uniform amplitude, non-unifrom on time uniform frequency 21 | """ 22 | 23 | class functions(object): 24 | 25 | #Initializaion of various parameters related to the functions 26 | def __init__(self, typeOfFunction, amplitude, omega, pulsewidth = None, 27 | start = None, stop = None): 28 | self.typeOfFunction = typeOfFunction 29 | self.amplitude = amplitude 30 | self.omega = omega 31 | self.period = 2 * np.pi/omega 32 | self.start = start 33 | self.stop = stop 34 | self.pulsewidth = pulsewidth 35 | 36 | #Sine function 37 | def sine_function(self, t): 38 | func = self.amplitude * np.sin(self.omega*t) 39 | return func 40 | 41 | #Cosine Function 42 | def cosine_function(self, t): 43 | func = self.amplitude * np.cos(self.omega*t) 44 | return func 45 | 46 | #Unit Step function 47 | def unit_step_function(self, t): 48 | func = self.amplitude * np.where(t > self.start, 1, 0) 49 | return func 50 | 51 | #Pulse with uniform amplitude and uniform frequency 52 | def uniform_pulse_function(self, t): 53 | func = self.amplitude * np.where((t > self.start and t < self.stop and (t % self.period < (self.pulsewidth))), 54 | 1, 0) 55 | return func 56 | 57 | #Pulse with non-uniform amplitude and uniform frequency 58 | def uniform_time_pulse_function(self, t): 59 | func = self.amplitude[int(t//self.period) - self.start] \ 60 | * np.where((t > self.start and t < self.stop and (t % self.period < (self.pulsewidth))), 1, 0) 61 | return func 62 | 63 | #Pulse with non-uniform amplitude, non-unifrom on time uniform frequency 64 | def custom_pulse_function(self, t): 65 | func = (self.amplitude[int(t//self.period) - self.start]) * np.where((t > self.start and t < self.stop and \ 66 | (t % self.period < (self.pulsewidth[int(t//self.period) - self.start]))), 1, 0) 67 | return func 68 | 69 | #Evaluates the function value at any given point in time 70 | def evaluate_function(self, time): 71 | func = getattr(self, self.typeOfFunction) 72 | self.funcValue = func(time) 73 | 74 | #Evaluates the function value of the integral function at any given point in time 75 | def evaluate_integration_function(self, time1, time2): 76 | options = {'limit':10000} 77 | func = self.return_function_address() 78 | self.funcIntegrationValue = spi.nquad(func, [[time1, time2]], opts=[options]) 79 | 80 | #Calls the function specified by user 81 | def return_function_address(self): 82 | func = getattr(self, self.typeOfFunction) 83 | return func 84 | 85 | #Returning functions 86 | def return_evaluation(self): 87 | return self.funcValue 88 | 89 | def return_integration_evaluation(self): 90 | return self.funcIntegrationValue 91 | 92 | -------------------------------------------------------------------------------- /models/ideal_memristor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Jan 11 16:56:20 2019 5 | 6 | @author: abhigyan 7 | """ 8 | 9 | """We have created an ideal memristor here with inspiration from the paper titled: 10 | 11 | 'The elusive memristor: properties of basic electrical circuits - Y Joglekar and S Wolf' 12 | 13 | The paramters for the memristor are as defined in the aforementioned paper but defined 14 | here again for convenience with typical values (for TiO2) mentioned in the brackets: 15 | 16 | voltage = Voltage function (A SymPy function object) 17 | D = Length of Memristor (~ 10nm) 18 | w_0 = Length of doped region of the memristor 19 | R_off = Resistance of undoped Memristor of length D (~ > 100 kOhm) 20 | R_on = Resistance of doped Memristor of length D (∼ 1 kOhm) 21 | mobility_u = Mobility of the dopants (∼ 10^−10 cm2 V−1 s−1 ) 22 | polarity_n = Value of polarity determines expansion or contraction of the 23 | doped region (+1 for expansion) 24 | """ 25 | 26 | 27 | class ideal_memristor(object): 28 | 29 | #Initialize the ideal memristor with paramters to be used 30 | def __init__(self, D = 10 ** -9, w_0 = 0.5 * 10 ** -9, R_on = 16000, R_off = 100, 31 | mobility_u = 10 ** -14, polarity_n = +1): 32 | self.D = D 33 | self.w_0 = w_0 34 | self.R_off = R_off 35 | self.R_on = R_on 36 | self.mobility_u = mobility_u 37 | self.polarity_n = polarity_n 38 | self.flux_history = 0 39 | 40 | #print(self.D, self.w_0,self.R_off, self.mobility_u) 41 | 42 | #Calculate parameters which are not time varying 43 | def calculate_fixed_parameters(self): 44 | self.Q_0 = (self.D ** 2) / (self.mobility_u * self.R_on) 45 | self.R_delta = self.R_off - self.R_on 46 | self.R_0 = self.R_on * (self.w_0 / self.D) + self.R_off * (1 - self.w_0 / self.D) 47 | 48 | #Calculate time variable paramters 49 | def calculate_time_variable_parameters(self, flux): 50 | self.flux = self.flux_history + flux 51 | self.drift_factor = (2 * self.polarity_n * self.R_delta * self.flux) / \ 52 | (self.Q_0 * (self.R_0 ** 2)) 53 | 54 | #Calculate current through memristor 55 | def calculate_current(self, voltage): 56 | self.current = (voltage / self.R_0) / ((1 - self.drift_factor) ** 0.5) 57 | self.resistance = self.R_0 * ((1 - self.drift_factor) ** 0.5) 58 | 59 | #Calculate charge through Memristor 60 | def calculate_charge(self): 61 | self.charge = ((self.Q_0 * self.R_0) / self.R_delta) * \ 62 | (1 - (1 - self.drift_factor) ** 0.5) 63 | 64 | #Update flux history 65 | def save_flux_history(self): 66 | self.flux_history = self.flux 67 | 68 | 69 | #Getter functions 70 | def get_current(self): 71 | return self.current 72 | 73 | def get_charge(self): 74 | return self.charge 75 | 76 | def get_flux(self): 77 | return self.flux 78 | 79 | def get_resistance(self): 80 | return self.resistance 81 | 82 | #End of Ideal Memristor class definition 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | --------------------------------------------------------------------------------