add the simulation result plot

main
ColsonZhang 2021-03-20 15:45:00 +08:00
parent 3b6d299816
commit c90af4e313
13 changed files with 199 additions and 31 deletions

View File

@ -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
View File

@ -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, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性

3
b3v3_1check.log Normal file
View File

@ -0,0 +1,3 @@
BSIM3V3.1 Parameter Check
Model = cmosp_180nm
W = 2e-05, L = 1e-06

BIN
doc/schematic7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

View File

@ -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]

View File

@ -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

View File

@ -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):

View File

@ -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);

View File

@ -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);

View File

@ -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);