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号,后端更新
|
||||
|
||||
* 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'/spice',spice.SpiceHandler),
|
||||
(r'/simulation',spice.SimulationHandler),
|
||||
(r'/getsiminfo',spice.SimulationInfoRequest_Handler),
|
||||
]
|
||||
settings = dict(
|
||||
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 :
|
||||
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):
|
||||
self.analysis = analysis
|
||||
|
||||
def load_analysis(self, simtype, 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):
|
||||
|
||||
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)
|
||||
# print('simulator:\n',self.simulator)
|
||||
if(sim_type == 'transient'):
|
||||
|
@ -39,7 +39,7 @@ class Simulator_CZ :
|
|||
start_time = parameter['start_time'],
|
||||
max_time = parameter['max_time'],
|
||||
use_initial_condition = parameter['use_initial_condition'])
|
||||
print(self.analysis)
|
||||
# print(self.analysis)
|
||||
return self.analysis
|
||||
elif(sim_type == 'dc' ):
|
||||
pass
|
||||
|
|
|
@ -4,6 +4,10 @@ import tornado.web
|
|||
from .MongoDB import *
|
||||
from .simulation import Simulator_CZ
|
||||
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 jinja2 import Environment, FileSystemLoader
|
||||
|
||||
|
@ -22,7 +26,9 @@ class SpiceHandler(AuthBaseHandler):
|
|||
|
||||
self.write("success")
|
||||
|
||||
|
||||
class SimulationHandler(AuthBaseHandler):
|
||||
|
||||
@tornado.web.authenticated
|
||||
def post(self,*args,**kwargs):
|
||||
sim_type = self.get_argument('sim_type')
|
||||
|
@ -38,12 +44,16 @@ class SimulationHandler(AuthBaseHandler):
|
|||
simulator = Simulator_CZ()
|
||||
simulator.Get_Spice(spice)
|
||||
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")
|
||||
|
||||
|
||||
# 将properties 从字符串类型解析出来
|
||||
# todo: 转换为json解析
|
||||
def properties_transform(properties_str):
|
||||
properties = {}
|
||||
attributes = properties_str.split(";")
|
||||
|
@ -55,6 +65,20 @@ def properties_transform(properties_str):
|
|||
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):
|
||||
|
||||
|
|
|
@ -1,48 +1,112 @@
|
|||
/* 基于bokeh.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
|
||||
var source = new Bokeh.ColumnDataSource({
|
||||
data: { x: [], y: [] }
|
||||
var the_source = new Bokeh.ColumnDataSource({
|
||||
data: { x: [], y: [], color: [] }
|
||||
});
|
||||
|
||||
|
||||
|
||||
// make a plot with some tools
|
||||
var plot = Bokeh.Plotting.figure({
|
||||
title:'Example of Random data',
|
||||
tools: "pan,wheel_zoom,box_zoom,reset,save",
|
||||
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
|
||||
plot.line({ field: "x" }, { field: "y" }, {
|
||||
source: source,
|
||||
plot.multi_line({field:"x"},{field:"y"},{
|
||||
source: the_source,
|
||||
color: {field:"color"},
|
||||
line_width: 2
|
||||
});
|
||||
|
||||
|
||||
|
||||
// show the plot, appending it to the end of the current section
|
||||
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() {
|
||||
addPoint();
|
||||
}
|
||||
var RefreshButton = document.createElement("Button");
|
||||
RefreshButton.appendChild(document.createTextNode("Refresh"));
|
||||
document.currentScript.parentElement.appendChild(RefreshButton);
|
||||
RefreshButton.addEventListener("click", Callback_Refresh);
|
||||
|
||||
var addDataButton = document.createElement("Button");
|
||||
addDataButton.appendChild(document.createTextNode("Add Some Data!!!"));
|
||||
addDataButton.appendChild(document.createTextNode("Plot"));
|
||||
document.currentScript.parentElement.appendChild(addDataButton);
|
||||
addDataButton.addEventListener("click", Callback_Button);
|
||||
|
||||
addPoint();
|
||||
addPoint();
|
||||
addDataButton.addEventListener("click", Callback_PlotPoint);
|
||||
|
|
|
@ -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++){
|
||||
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']['VA'].replace(" ","").replace("V","") + " ";
|
||||
spice += circuit[i]['value']['FREQ'].replace(" ","").replace("Hz","") + " ";
|
||||
|
@ -1311,7 +1311,7 @@ function showOutline(graph)
|
|||
frame.setAttribute('id','bokeh_01');
|
||||
|
||||
var x = document.createElement('script');
|
||||
x.setAttribute('src','static/spice/bokeh_01.js');
|
||||
x.setAttribute('src','static/spice/show_result.js');
|
||||
|
||||
frame.appendChild(x);
|
||||
|
||||
|
|
Loading…
Reference in New Issue