diff --git a/README.md b/README.md index bba6a22..7c2ef49 100644 --- a/README.md +++ b/README.md @@ -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封装一个通用的结果显示的“示波器”,向服务器后端发送请求,接收相关数据,并展示结果。 diff --git a/app.py b/app.py index 2c7136a..2a2e6b0 100644 --- a/app.py +++ b/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, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性 diff --git a/b3v3_1check.log b/b3v3_1check.log new file mode 100644 index 0000000..0b93d3a --- /dev/null +++ b/b3v3_1check.log @@ -0,0 +1,3 @@ +BSIM3V3.1 Parameter Check +Model = cmosp_180nm +W = 2e-05, L = 1e-06 diff --git a/doc/schematic7.png b/doc/schematic7.png new file mode 100644 index 0000000..2d1d2c1 Binary files /dev/null and b/doc/schematic7.png differ diff --git a/handler/__pycache__/sim_data_container.cpython-36.pyc b/handler/__pycache__/sim_data_container.cpython-36.pyc new file mode 100644 index 0000000..89c0ee1 Binary files /dev/null and b/handler/__pycache__/sim_data_container.cpython-36.pyc differ diff --git a/handler/__pycache__/simulation.cpython-36.pyc b/handler/__pycache__/simulation.cpython-36.pyc index 7c46d4f..e692fc9 100644 Binary files a/handler/__pycache__/simulation.cpython-36.pyc and b/handler/__pycache__/simulation.cpython-36.pyc differ diff --git a/handler/__pycache__/spice.cpython-36.pyc b/handler/__pycache__/spice.cpython-36.pyc index c5628ff..a9aa356 100644 Binary files a/handler/__pycache__/spice.cpython-36.pyc and b/handler/__pycache__/spice.cpython-36.pyc differ diff --git a/handler/sim_data_container.py b/handler/sim_data_container.py index 1fb0ab9..26cc968 100644 --- a/handler/sim_data_container.py +++ b/handler/sim_data_container.py @@ -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 - \ No newline at end of file + 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] diff --git a/handler/simulation.py b/handler/simulation.py index 2b2d386..34ff8ea 100644 --- a/handler/simulation.py +++ b/handler/simulation.py @@ -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 diff --git a/handler/spice.py b/handler/spice.py index 07cc520..98eef15 100644 --- a/handler/spice.py +++ b/handler/spice.py @@ -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): diff --git a/static/spice/show_result.js b/static/spice/show_result.js index 0a8fdeb..9084537 100644 --- a/static/spice/show_result.js +++ b/static/spice/show_result.js @@ -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); diff --git a/static/spice/show_result2.js b/static/spice/show_result2.js new file mode 100644 index 0000000..49e147b --- /dev/null +++ b/static/spice/show_result2.js @@ -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); \ No newline at end of file diff --git a/template/schematic/schematic.html b/template/schematic/schematic.html index 629c623..249ad10 100644 --- a/template/schematic/schematic.html +++ b/template/schematic/schematic.html @@ -687,7 +687,7 @@ function ExtractSpice_2(circuit){ for(var j=0; j