add the simulation result plot
parent
3b6d299816
commit
c90af4e313
|
@ -59,6 +59,11 @@ app.py ----服务器的主程序
|
||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
|
* 2021年3月20号,前端更新
|
||||||
|
|
||||||
|
* 新增:仿真结果数据显示,成功将仿真得到的节点电压绘制出来。
|
||||||
|
* todo:绘制仿真结果时增加用户配置项目,可以进行选择性绘图。
|
||||||
|
* ![avatar](./doc/schematic7.png)
|
||||||
* 2021年3月18号,后端更新
|
* 2021年3月18号,后端更新
|
||||||
|
|
||||||
* idea & todo:仿真结果数据可视化的基本思路为:在后端的python代码中,用一个自定义类封装的simulation result data container来容纳数据,并新增一个用于处理get/post请求的处理函数,当前端需要这些相关数据时,通过ajax发送过去;同时前端使用bokehjs封装一个通用的结果显示的“示波器”,向服务器后端发送请求,接收相关数据,并展示结果。
|
* idea & todo:仿真结果数据可视化的基本思路为:在后端的python代码中,用一个自定义类封装的simulation result data container来容纳数据,并新增一个用于处理get/post请求的处理函数,当前端需要这些相关数据时,通过ajax发送过去;同时前端使用bokehjs封装一个通用的结果显示的“示波器”,向服务器后端发送请求,接收相关数据,并展示结果。
|
||||||
|
|
1
app.py
1
app.py
|
@ -24,6 +24,7 @@ class Application(tornado.web.Application): #引入Application类,重写方
|
||||||
(r'/test',main.TestHandler),
|
(r'/test',main.TestHandler),
|
||||||
(r'/spice',spice.SpiceHandler),
|
(r'/spice',spice.SpiceHandler),
|
||||||
(r'/simulation',spice.SimulationHandler),
|
(r'/simulation',spice.SimulationHandler),
|
||||||
|
(r'/getsiminfo',spice.SimulationInfoRequest_Handler),
|
||||||
]
|
]
|
||||||
settings = dict(
|
settings = dict(
|
||||||
debug = False, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性
|
debug = False, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
BSIM3V3.1 Parameter Check
|
||||||
|
Model = cmosp_180nm
|
||||||
|
W = 2e-05, L = 1e-06
|
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,8 +1,42 @@
|
||||||
|
|
||||||
|
|
||||||
class Sim_Data_Container :
|
class Sim_Data_Container :
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.analysis = None
|
self.sim_type = {'transient':False,'ac':False,'dc':False}
|
||||||
|
# self.analysis = None
|
||||||
|
self.result = {}
|
||||||
|
print('container initial sucessfully !!!')
|
||||||
|
|
||||||
def load_analysis(self,analysis):
|
def load_analysis(self, simtype, analysis):
|
||||||
self.analysis = analysis
|
print()
|
||||||
|
self.sim_type[simtype] = True
|
||||||
|
# self.analysis = analysis
|
||||||
|
# print("loading analysising")
|
||||||
|
if(simtype == 'transient'):
|
||||||
|
self.parse_transient(analysis)
|
||||||
|
|
||||||
|
|
||||||
|
def del_analysis(self):
|
||||||
|
self.sim_type = {'transient':False,'ac':False,'dc':False}
|
||||||
|
self.result = {}
|
||||||
|
|
||||||
|
def parse_transient(self, analysis):
|
||||||
|
# print('parsing the transient analysising !!!')
|
||||||
|
result_tran = {}
|
||||||
|
result_tran['time'] = [float(i) for i in analysis.time]
|
||||||
|
result_tran['nodes_name'] = list(analysis.nodes.keys())
|
||||||
|
nodes = {}
|
||||||
|
for i in result_tran['nodes_name'] :
|
||||||
|
nodes[i] = [float(j) for j in analysis.nodes[i]]
|
||||||
|
result_tran['nodes'] = nodes
|
||||||
|
|
||||||
|
result_tran['branches_name'] = list(analysis.branches.keys())
|
||||||
|
branches = {}
|
||||||
|
for i in result_tran['branches_name']:
|
||||||
|
branches[i] = [float(j) for j in analysis.branches[i]]
|
||||||
|
result_tran['branches'] = branches
|
||||||
|
|
||||||
|
self.result['transient'] = result_tran
|
||||||
|
|
||||||
|
def simulation_info_request(self, simtype):
|
||||||
|
return self.result[simtype]
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Simulator_CZ :
|
||||||
def Sim(self, sim_type,properties):
|
def Sim(self, sim_type,properties):
|
||||||
|
|
||||||
parameter = self.Properties_Parse(sim_type,properties)
|
parameter = self.Properties_Parse(sim_type,properties)
|
||||||
print("parameter:\n",parameter)
|
# print("parameter:\n",parameter)
|
||||||
self.simulator = self.circuit.simulator(temperature=25, nominal_temperature=25)
|
self.simulator = self.circuit.simulator(temperature=25, nominal_temperature=25)
|
||||||
# print('simulator:\n',self.simulator)
|
# print('simulator:\n',self.simulator)
|
||||||
if(sim_type == 'transient'):
|
if(sim_type == 'transient'):
|
||||||
|
@ -39,7 +39,7 @@ class Simulator_CZ :
|
||||||
start_time = parameter['start_time'],
|
start_time = parameter['start_time'],
|
||||||
max_time = parameter['max_time'],
|
max_time = parameter['max_time'],
|
||||||
use_initial_condition = parameter['use_initial_condition'])
|
use_initial_condition = parameter['use_initial_condition'])
|
||||||
print(self.analysis)
|
# print(self.analysis)
|
||||||
return self.analysis
|
return self.analysis
|
||||||
elif(sim_type == 'dc' ):
|
elif(sim_type == 'dc' ):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -4,6 +4,10 @@ import tornado.web
|
||||||
from .MongoDB import *
|
from .MongoDB import *
|
||||||
from .simulation import Simulator_CZ
|
from .simulation import Simulator_CZ
|
||||||
from .sim_data_container import Sim_Data_Container
|
from .sim_data_container import Sim_Data_Container
|
||||||
|
from tornado.escape import json_decode, json_encode, utf8
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
# from bokeh.embed import server_document
|
# from bokeh.embed import server_document
|
||||||
# from jinja2 import Environment, FileSystemLoader
|
# from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
@ -22,7 +26,9 @@ class SpiceHandler(AuthBaseHandler):
|
||||||
|
|
||||||
self.write("success")
|
self.write("success")
|
||||||
|
|
||||||
|
|
||||||
class SimulationHandler(AuthBaseHandler):
|
class SimulationHandler(AuthBaseHandler):
|
||||||
|
|
||||||
@tornado.web.authenticated
|
@tornado.web.authenticated
|
||||||
def post(self,*args,**kwargs):
|
def post(self,*args,**kwargs):
|
||||||
sim_type = self.get_argument('sim_type')
|
sim_type = self.get_argument('sim_type')
|
||||||
|
@ -38,12 +44,16 @@ class SimulationHandler(AuthBaseHandler):
|
||||||
simulator = Simulator_CZ()
|
simulator = Simulator_CZ()
|
||||||
simulator.Get_Spice(spice)
|
simulator.Get_Spice(spice)
|
||||||
analysis = simulator.Sim(sim_type,properties)
|
analysis = simulator.Sim(sim_type,properties)
|
||||||
|
|
||||||
print('simulation finished !')
|
print('simulation finished !')
|
||||||
|
|
||||||
|
Container_SimResult.load_analysis(sim_type,analysis)
|
||||||
|
print('data container load data successfully!! ')
|
||||||
|
|
||||||
self.write("success")
|
self.write("success")
|
||||||
|
|
||||||
|
|
||||||
|
# 将properties 从字符串类型解析出来
|
||||||
|
# todo: 转换为json解析
|
||||||
def properties_transform(properties_str):
|
def properties_transform(properties_str):
|
||||||
properties = {}
|
properties = {}
|
||||||
attributes = properties_str.split(";")
|
attributes = properties_str.split(";")
|
||||||
|
@ -55,6 +65,20 @@ def properties_transform(properties_str):
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationInfoRequest_Handler(AuthBaseHandler):
|
||||||
|
@tornado.web.authenticated
|
||||||
|
def post(self,*args,**kwargs):
|
||||||
|
sim_type = self.get_argument('sim_type')
|
||||||
|
|
||||||
|
sim_info = Container_SimResult.simulation_info_request(sim_type)
|
||||||
|
# sim_info = {'ab':1,'cd':2,'ef':'d2','hello':[1,2,3,4,5]}
|
||||||
|
sim_info_json = json.dumps( sim_info )
|
||||||
|
# print('json transform ok !!')
|
||||||
|
self.write( sim_info_json )
|
||||||
|
# self.write(json_decode(sim_info))
|
||||||
|
# self.write("successful")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Schematic_Handler(AuthBaseHandler):
|
class Schematic_Handler(AuthBaseHandler):
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,112 @@
|
||||||
/* 基于bokeh.js库文件
|
/* 基于bokeh.js库文件
|
||||||
使用该文件前请现在html加载相关js文件*/
|
使用该文件前请现在html加载相关js文件*/
|
||||||
|
|
||||||
|
// 仿真结果数据
|
||||||
|
var SimResult ;
|
||||||
|
var Flag_Refresh = false ;
|
||||||
|
|
||||||
|
var color_store = ["blue","brown","cyan","green","orange","pink","purple","red","whitesmoke","yellow"];
|
||||||
|
|
||||||
// create a data source to hold data
|
// create a data source to hold data
|
||||||
var source = new Bokeh.ColumnDataSource({
|
var the_source = new Bokeh.ColumnDataSource({
|
||||||
data: { x: [], y: [] }
|
data: { x: [], y: [], color: [] }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// make a plot with some tools
|
// make a plot with some tools
|
||||||
var plot = Bokeh.Plotting.figure({
|
var plot = Bokeh.Plotting.figure({
|
||||||
title:'Example of Random data',
|
title:'Example of Random data',
|
||||||
tools: "pan,wheel_zoom,box_zoom,reset,save",
|
tools: "pan,wheel_zoom,box_zoom,reset,save",
|
||||||
height: 300,
|
height: 300,
|
||||||
width: 300
|
width: 400,
|
||||||
|
background_fill_color: "#F2F2F7"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function plotPoint() {
|
||||||
|
|
||||||
|
if(Flag_Refresh == true){
|
||||||
|
|
||||||
|
the_source.data.x = [];
|
||||||
|
the_source.data.y = [];
|
||||||
|
the_source.data.color = [];
|
||||||
|
|
||||||
|
|
||||||
|
console.log("Flag_Refresh = true !");
|
||||||
|
var the_nodes_name = SimResult["nodes_name"];
|
||||||
|
|
||||||
|
var the_x = SimResult["time"];
|
||||||
|
for(var i=0; i < the_nodes_name.length; i++){
|
||||||
|
var the_y = SimResult["nodes"][the_nodes_name[i]] ;
|
||||||
|
the_source.data.x.push(the_x);
|
||||||
|
the_source.data.y.push(the_y);
|
||||||
|
the_source.data.color.push(color_store[i%color_store.length]);
|
||||||
|
}
|
||||||
|
the_source.change.emit();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function requestSimInfo(){
|
||||||
|
var data = new Object();
|
||||||
|
var sim_result ;
|
||||||
|
|
||||||
|
data["sim_type"] = 'transient';
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: "/getsiminfo",
|
||||||
|
data: data,
|
||||||
|
async:false, // 必须关闭异步!!!
|
||||||
|
dataType:'json',
|
||||||
|
success: function (siminfo) {
|
||||||
|
console.log("load sim result successfully !!");
|
||||||
|
sim_result = siminfo;
|
||||||
|
},
|
||||||
|
error: function(){
|
||||||
|
alert('failed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sim_result ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Callback_PlotPoint() {
|
||||||
|
|
||||||
|
plotPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Refresh(){
|
||||||
|
SimResult = requestSimInfo();
|
||||||
|
Flag_Refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// add a line with data from the source
|
// add a line with data from the source
|
||||||
plot.line({ field: "x" }, { field: "y" }, {
|
plot.multi_line({field:"x"},{field:"y"},{
|
||||||
source: source,
|
source: the_source,
|
||||||
|
color: {field:"color"},
|
||||||
line_width: 2
|
line_width: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// show the plot, appending it to the end of the current section
|
// show the plot, appending it to the end of the current section
|
||||||
Bokeh.Plotting.show(plot,'#bokeh_01');
|
Bokeh.Plotting.show(plot,'#bokeh_01');
|
||||||
|
|
||||||
function addPoint() {
|
|
||||||
// add data --- all fields must be the same length.
|
|
||||||
source.data.x.push(Math.random())
|
|
||||||
source.data.y.push(Math.random())
|
|
||||||
|
|
||||||
// notify the DataSource of "in-place" changes
|
|
||||||
source.change.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
function Callback_Button() {
|
var RefreshButton = document.createElement("Button");
|
||||||
addPoint();
|
RefreshButton.appendChild(document.createTextNode("Refresh"));
|
||||||
}
|
document.currentScript.parentElement.appendChild(RefreshButton);
|
||||||
|
RefreshButton.addEventListener("click", Callback_Refresh);
|
||||||
|
|
||||||
var addDataButton = document.createElement("Button");
|
var addDataButton = document.createElement("Button");
|
||||||
addDataButton.appendChild(document.createTextNode("Add Some Data!!!"));
|
addDataButton.appendChild(document.createTextNode("Plot"));
|
||||||
document.currentScript.parentElement.appendChild(addDataButton);
|
document.currentScript.parentElement.appendChild(addDataButton);
|
||||||
addDataButton.addEventListener("click", Callback_Button);
|
addDataButton.addEventListener("click", Callback_PlotPoint);
|
||||||
|
|
||||||
addPoint();
|
|
||||||
addPoint();
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// create some data and a ColumnDataSource
|
||||||
|
|
||||||
|
var source = new Bokeh.ColumnDataSource({ data: { x: [], y: [] } });
|
||||||
|
|
||||||
|
|
||||||
|
// make the plot
|
||||||
|
var plot = Bokeh.Plotting.figure({
|
||||||
|
title: "BokehJS Plot",
|
||||||
|
plot_width: 400,
|
||||||
|
plot_height: 400,
|
||||||
|
background_fill_color: "#F2F2F7"
|
||||||
|
});
|
||||||
|
var count = 0 ;
|
||||||
|
|
||||||
|
function Callback_Refresh(){
|
||||||
|
source.data.x = [];
|
||||||
|
source.data.y = [];
|
||||||
|
// var the_x = SimResult["time"];
|
||||||
|
var the_x = [2,4] ;
|
||||||
|
|
||||||
|
// var the_y = SimResult["nodes"][the_nodes_name[i]] ;
|
||||||
|
var the_y = [1+count,3+count];
|
||||||
|
source.data.x.push(the_x);
|
||||||
|
source.data.y.push(the_y);
|
||||||
|
count = count+1;
|
||||||
|
source.change.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
plot.multi_line({field:"x"},{field:"y"},{source:source});
|
||||||
|
// plot.multi_line([[1,2,3],[1,2,3]],[[2,4,6],[7,8,9]]);
|
||||||
|
|
||||||
|
Bokeh.Plotting.show(plot,'#bokeh_01');
|
||||||
|
|
||||||
|
var RefreshButton = document.createElement("Button");
|
||||||
|
RefreshButton.appendChild(document.createTextNode("Refresh"));
|
||||||
|
document.currentScript.parentElement.appendChild(RefreshButton);
|
||||||
|
RefreshButton.addEventListener("click", Callback_Refresh);
|
|
@ -687,7 +687,7 @@ function ExtractSpice_2(circuit){
|
||||||
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
for(var j=0; j<circuit[i]['port_keys'].length; j++){
|
||||||
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
spice += circuit[i]['port'][circuit[i]['port_keys'][j]] + " ";
|
||||||
}
|
}
|
||||||
spice += "PULSE(" + " ";
|
spice += "SIN(" + " ";
|
||||||
spice += circuit[i]['value']['V0'].replace(" ","").replace("V","") + " ";
|
spice += circuit[i]['value']['V0'].replace(" ","").replace("V","") + " ";
|
||||||
spice += circuit[i]['value']['VA'].replace(" ","").replace("V","") + " ";
|
spice += circuit[i]['value']['VA'].replace(" ","").replace("V","") + " ";
|
||||||
spice += circuit[i]['value']['FREQ'].replace(" ","").replace("Hz","") + " ";
|
spice += circuit[i]['value']['FREQ'].replace(" ","").replace("Hz","") + " ";
|
||||||
|
@ -1311,7 +1311,7 @@ function showOutline(graph)
|
||||||
frame.setAttribute('id','bokeh_01');
|
frame.setAttribute('id','bokeh_01');
|
||||||
|
|
||||||
var x = document.createElement('script');
|
var x = document.createElement('script');
|
||||||
x.setAttribute('src','static/spice/bokeh_01.js');
|
x.setAttribute('src','static/spice/show_result.js');
|
||||||
|
|
||||||
frame.appendChild(x);
|
frame.appendChild(x);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue