另一种方式实现手机上绘制根轨迹。并且在手机上绘制螺旋桨性能曲线。
在手机上绘制根轨迹
上一次写的easyAuto,好倒是挺好的,但是有一个问题:仅仅有安卓的版本,没有iOS版本。这样一来,有很多用户无法得到方便。因此,要么自己买一套iOS的设备,要么换一种方式:网页实现。
网页绘制的好处有很多,可以实现真正的跨平台,每一次代码的更新用户并不需要任何的升级这些,因此好处太多了。没能开发iOS程序一直是我的遗憾,这样也算是一种弥补。现在的前端技术很火,bootcdn上面一大堆js库,都很有意思,没事浏览浏览上面的目录,说不定能发现宝贝。
在上次的文章里我们详细的讨论了算法,又是多项式又是矩阵什么的,比较麻烦。网上找到的轮子有
- math.js库,比较强大,但是矩阵不能求特征值
- numerical.js库,很久没有更新了,矩阵能够求特征值,还有样条插值函数
- polynomial.js,比较简陋,就是用来表示多项式的 即使有这些低层次的轮子,要移植我曾经的一大堆专门的数值代码也是非常麻烦的。手写就不说了,自己想想都觉得多。我在网上看到了几种方案:
- emscripten-qt直接移植Qt程序,这个项目已经没有维护了,不可能能移植QtCharts模块
- Qt+WebAssembly,看了几个demo,效果很差
- 在网页里面直接运行apk,也没有看见理想的方案
- 用emscripten移植数值算法的代码,但是自己本来就完全不会javascript,这样自己也会更麻烦
那也没有实现的办法呢?我想到了WolframAlpha,试了试,可以画根轨迹,当然这个问题可以结束了,所有手机要想画根轨迹直接访问WolframAlpha不就完了?!但是还是要自己写程序,看了看有没有WolframAlpha的API,还真有,那就好说。通过API访问https://api.wolframalpha.com/v2/query?input=root+locus+for+transfer+function+(s%5E2%2B3)%2F(s%5E3%2B5)&format=image&output=JSON&appid=DEMO可以得到一个这样的json:
{
"queryresult": {
"success": true,
"error": false,
"numpods": 2,
"datatypes": "ControlSystem",
"timedout": "",
"timedoutpods": "",
"timing": 2.244,
"parsetiming": 1.397,
"parsetimedout": false,
"recalculate": "",
"id": "MSPa3194185g424ef9ic5i8b000031903e0de369bii3",
"host": "http://www4d.wolframalpha.com",
"server": "15",
"related": "http://www4d.wolframalpha.com/api/v2/relatedQueries.jsp?id=MSPa3195185g424ef9ic5i8b00002hd488g9fggigd5f3827527191664667052",
"version": "2.6",
"pods": [
{
"title": "Input interpretation",
"scanner": "Identity",
"id": "Input",
"position": 100,
"error": false,
"numsubpods": 1,
"subpods": [
{
"title": "",
"img": {
"src": "http://www4d.wolframalpha.com/Calculate/MSP/MSP3196185g424ef9ic5i8b00000e5afg304gfd51fb?MSPStoreType=image/gif&s=15",
"alt": "root locus plot | transfer function (3 + s^2)/(5 + s^3)",
"title": "root locus plot | transfer function (3 + s^2)/(5 + s^3)",
"width": 314,
"height": 55
}
}
]
},
{
"title": "Root locus plot",
"scanner": "ControlSystems",
"id": "RootLocusPlot",
"position": 200,
"error": false,
"numsubpods": 1,
"subpods": [
{
"title": "",
"img": {
"src": "http://www4d.wolframalpha.com/Calculate/MSP/MSP3197185g424ef9ic5i8b0000445b174i6b48h4ea?MSPStoreType=image/gif&s=15",
"alt": "\n(shown for gain between 0 and 10)",
"title": "\n(shown for gain between 0 and 10)",
"width": 300,
"height": 318
}
}
],
"states": [
{
"name": "Increase range",
"input": "RootLocusPlot__Increase range"
},
{
"name": "Decrease range",
"input": "RootLocusPlot__Decrease range"
}
]
}
]
}
}
这样只用通过javascript进行http的get请求就能行了。理论很美满,显示很骨感,试了大半天,总是会遇到Access-Control-Allow-Origin的问题。上谷歌去查各种方案,都说WolframAlpha的API不能通过javascript访问,要么用服务端代码,要么用proxy,好像没有解决方案。但是,在网上查javascript跨域的问题,也是得到了一大堆奇奇怪怪的解决方法,我最终实现了跨域访问:
var str1 = document.getElementById("num").value;
var str2 = document.getElementById("den").value;
var querystr = "https://api.wolframalpha.com/v2/query?input=root+locus+for+transfer+function+(" +
encodeURIComponent(str1) + encodeURIComponent(")/(") + encodeURIComponent(str2) +
")&format=image&output=JSON&appid=XXXX&callback=?";
$.ajax({
type: 'GET',
url: querystr ,
//是否使用缓存
cache:false,
//数据类型,这里我用的是json
dataType: "json",
crossDomain: true,
//必要的时候需要用JSON.stringify() 将JSON对象转换成字符串
//data: JSON.strigify({key:value}),
//data : ""
//请求成功的回调函数 success:
success : function(data){
document.getElementById("res1").src = data.queryresult.pods[0].subpods[0].img.src;
document.getElementById("res2").src = data.queryresult.pods[1].subpods[0].img.src;
}
});
不知道实现了跨域访问的原因到底是在URL里面加了”&callback=?”还是设置了crossDomain为true的原因。这样就实现了在网页上绘制根轨迹。不过这个网页的使用体验肯定没有安卓版的easyAuto好,一个是输入格式更为严格,第二个是速度太慢。就这个访问速度,我相信即使是javascript代码也能做到更快把图画出来,不过我是真的不想再去用javascript写数值的代码了。
螺旋桨性能查询网页
做这个的原因和上一个一样,想实现彻底的跨平台。之前把demoProp的所有数据全部导入到了一个sqlite文件中,加上索引一共40+MB,正好在网上看到了sql.js项目,这个是emscripten把sqlite直接翻译过来的结果,想试一试,于是把数据库和网页挂在网上,试了试发现访问速度太慢了。而且一不注意,手机用了200+MB的流量,血淋淋的教训啊。我明白这个的意思了:用http请求把url的数据库先下载下来,然后再在内存中运行sql语句。这个代价相比PHP+MySQL的代价的确太大了。我把索引全部删除,数据库的大小还是20+MB,没办法,想了想一般在无人机我们关注的是静拉力,于是删除了所有动拉力数据,仅保留静拉力数据,这下只有600+KB了。再把一些无关的字段删去,sqlite对sql的支持太差,删除字段还需要这样写:
create table temp as select propName,RPM,PWR,Thrust from propellers;
drop table propellers;
alter table temp rename to propellers;
这样数据库只剩300KB了。当然,也可以把所有数据以文本形式保存在网站上,具体对于某个螺旋桨,只需要读取具体的一个数据就行,不过处理文件肯定没有sql语句来得方便。
关于图表的绘制,我使用的是ECharts3.而UI的绘制则是使用jQuery Mobile,都是直接挂的bootcdn,希望服务器不要宕机。jQuery Mobile的空间要想更好地适应移动端,需要加上如下代码:
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">