用python拟合等角螺线的实现示例


Posted in Python onDecember 27, 2019

人类很早就注意到飞蛾扑火这一奇怪的现象,并且自作主张地赋予了飞蛾扑火很多含义,引申出为了理想和追求义无反顾、不畏牺牲的精神。但是,这种引申和比喻,征求过飞蛾的意见吗?

后来,生物学家又提出来昆虫趋光性这一假说来解释飞蛾扑火。不过,这个假说似乎也不成立。如果昆虫真的追逐光明,估计地球上早就没有昆虫了——它们应该齐刷刷整体移民到太阳或月亮上去了。

仔细观察飞蛾扑火,就会发现,昆虫们并不是笔直地飞向光源,而是绕着光源飞行,同时越来越接近光源,最终酿成了“惨案”。这一行为被解释成“失误”似乎更合理一点。既然火烛危险,那么飞蛾为什么要绕着火烛飞行呢?

最新的解释是,飞蛾在夜晚飞行时是依据月光和星光作为参照物进行导航的。星星和月亮离我们非常远,光到了地面上可以看成平行光,当飞蛾的飞行路径保持与光线方向成恒定夹角时,飞蛾就变成了直线飞行,如下图所示。

用python拟合等角螺线的实现示例

然而,当飞蛾遇到了火烛等危险光源时,还是按照以前的飞行方式,路径保持与光线方向成恒定夹角,以为依旧能飞成一条直线,结果悲剧了。此时它的飞行轨迹并不是一条直线,而是一条等角螺旋线,如下图所示。

用python拟合等角螺线的实现示例

可怜的飞蛾!亿万年进化出来的精准导航,在人工光源的干扰下竟如此不堪。

螺线及等角螺线

螺线家族很庞大,比如,阿基米德螺线、费马螺线、等角螺线、双曲螺线、连锁螺线、斐波那契螺线、欧拉螺线等等。等角螺线,又叫对数螺线,螺线家族的一员。

早在2000多年以前,古希腊数学家阿基米德就对螺旋线进行了研究。公元1638年,著名数学家笛卡尔首先描述了对数螺旋线(等角螺旋线),并列出了螺旋线的解析式。这种螺旋线有很多特点,其中最突出的一点就是它的形状,无论你把它放大或缩小它都不会有任何的改变。就像我们不能把角放大或缩小一样。

用python拟合等角螺线的实现示例

用极坐标分析法分析飞蛾扑火的飞行轨迹,可知,轨迹线上任意一点的切线与该点与原点的连线之间的夹角是固定的,这就是等角螺线得名的由来。因为分析过程使用了对数,所以等角螺线又叫对数螺线。我不太会用LaTeX写数学公式,所以就用 python 的方法写出螺线方程。其中,fixed 表示螺线固定角,大于 pi/2 则为顺时针螺线,小于 pi/2 则为逆时针螺线。theta 表示旋转弧度,r 表示距离中心点距离。

r = fixed*np.exp(theta/np.tan(fixed))

等角螺线在生活中也经常见到,比如,鹦鹉螺的花纹、玫瑰花瓣的排列,星系的悬臂,低气压云图等。

用python拟合等角螺线的实现示例

绘制等角螺线

给定中心点和固定角,一个等角螺线就被唯一地确定了。这个螺线可以绕很多圈,可以填满整个宇宙。但很多时候,我们往往只需要观察螺线上的一小部分,这时候就需要两个参数来约定:一个叫作 circle,表示你希望看到多少圈螺线,一个叫作 phase,表示螺线的可见部分向内(顺时针)或向外(逆时针螺线)旋转多少圈。

这是使用 matplotlib 绘制等角螺线的函数,其中固定角参数 fixed 做了一点处理:以度(°)为单位,以零为中心,大于零则为顺时针螺线,小于零则为逆时针螺线

import numpy as np
import matplotlib.pyplot as plt

from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['FangSong']
mpl.rcParams['axes.unicode_minus'] = False

def plotSpiral(core, fixed, phase=0, circle=4):
  """绘制等角螺线
  core		- 等角螺线的中心坐标,tuple类型
  fixed    - 等角螺线的固定角度,单位:度(°)。fixed大于零则为顺时针螺线,小于零则为逆时针螺线
  phase    - 初始相位,单位:圈(360°)。对顺时针螺线,该数值越大,螺线越大,对逆时针螺线则相反
  circle   - 螺线可见部分的圈数,单位:圈(360°)
  """
  
  plt.axis("equal")
  plt.plot([core[0]], [core[1]], c='red', marker='+', markersize=10)
  
  fixed_rad = np.radians(90 + fixed)
  theta = np.linspace(0, circle*2*np.pi, 361) + phase*2*np.pi
  r = fixed_rad*np.exp(theta/np.tan(fixed_rad))
  x = r*np.cos(theta) + core[0]
  y = r*np.sin(theta) - core[1]
  plt.plot(x, y, c='blue')
  
  plt.show()

下图展示了逆时针等角螺线各个参数的意义:

用python拟合等角螺线的实现示例

下图展示了顺时针等角螺线各个参数的意义:

用python拟合等角螺线的实现示例

拟合等角螺线

在台风定位时,需要手动确定台风中心位置,并标识出台风螺线轨迹上的部分点,然后逆合出螺线方程。如下图所示,蓝色十字为台风中心点,5个黄色圆点是手工标注的台风螺线轨迹上的点。

用python拟合等角螺线的实现示例

以下为拟合函数

import numpy as np
from scipy import optimize

def fit_spiral(core, dots):
  """拟合等角螺线,返回定角fixed,初始相位phase"""
  
  fixed_ccw = 0.445*np.pi
  fixed_cw = 0.555*np.pi
  
  # 将dots拆分成x_list和y_list
  x_list, y_list = list(), list()
  for x, y in dots:
    x_list.append(x-core[0])
    y_list.append(y-core[1])
  
  # 计算距离
  x = np.array(x_list)
  y = np.array(y_list)
  r = np.hypot(x,y)
  
  # 按照距离排序
  sort_mask = np.argsort(r)
  x = x[sort_mask]
  y = y[sort_mask]
  r = r[sort_mask]
  
  # 计算角度
  theta = np.arctan(y/x)
  theta[x<0] += np.pi
  
  # 确定顺序(CW-顺时针,CCW-逆时针)
  d = np.diff(theta)
  print(d)
  ccw = d[d>0].size > d[d<0].size
  print('ccw=',ccw)
  
  # 调整角度为升序(CCW)或降序(CW)
  if ccw:
    for i in range(1, theta.size):
      while theta[i] < theta[i-1]:
        theta[i] += 2*np.pi
      
      dtheta = theta[i] - theta[i-1]
      while r[i]/r[i-1] > 1.8*np.exp(dtheta/np.tan(fixed_ccw)):
        theta[i] += 2*np.pi
        dtheta = theta[i] - theta[i-1]
  else:
    for i in range(theta.size-1)[::-1]:
      while theta[i] < theta[i+1]:
        theta[i] += 2*np.pi
      
      dtheta = theta[i+1] - theta[i]
      while r[i+1]/r[i] > 1.8*np.exp(dtheta/np.tan(fixed_cw)):
        theta[i] += 2*np.pi
        dtheta = theta[i+1] - theta[i]
  
  # 定义拟合函数
  def fmax(theta, fixed, phase):
    fixed = np.radians(90 + fixed)
    return fixed*np.exp((theta+phase*2*np.pi)/np.tan(fixed))
  
  try: 
    fita, fitb = optimize.curve_fit(fmax, theta, r, [2-int(ccw), 0], maxfev=10000)
    return fita
  except:
    return None

core = (530, 496)
dots = [(467,538), (448,675), (522,484), (513,451), (811,519)]
result = fit_spiral(core, dots)
if isinstance(result, np.ndarray):
  plotSpiral(core, result[0], phase=result[1], circle=4)
else:
  print(u'拟合失败')

拟合效果如下图:

用python拟合等角螺线的实现示例

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
详解Django框架中用context来解析模板的方法
Jul 20 Python
Django中ORM表的创建和增删改查方法示例
Nov 15 Python
OpenCV2从摄像头获取帧并写入视频文件的方法
Aug 03 Python
Window环境下Scrapy开发环境搭建
Nov 18 Python
python配置grpc环境
Jan 01 Python
Python 复平面绘图实例
Nov 21 Python
Python闭包与装饰器原理及实例解析
Apr 30 Python
将keras的h5模型转换为tensorflow的pb模型操作
May 25 Python
python 解决mysql where in 对列表(list,,array)问题
Jun 06 Python
Python return语句如何实现结果返回调用
Oct 15 Python
Python爬虫抓取论坛关键字过程解析
Oct 19 Python
python之PySide2安装使用及QT Designer UI设计案例教程
Jul 26 Python
PyTorch 对应点相乘、矩阵相乘实例
Dec 27 #Python
pytorch中tensor.expand()和tensor.expand_as()函数详解
Dec 27 #Python
python装饰器相当于函数的调用方式
Dec 27 #Python
Python 实现数组相减示例
Dec 27 #Python
Pandas 解决dataframe的一列进行向下顺移问题
Dec 27 #Python
Pandas实现DataFrame按行求百分数(比例数)
Dec 27 #Python
pandas的相关系数与协方差实例
Dec 27 #Python
You might like
php 中英文语言转换类
2011/09/07 PHP
php面向对象编程self和static的区别
2016/05/08 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
浅谈thinkphp的nginx配置,以及重写隐藏index.php入口文件方法
2019/10/12 PHP
深入理解Javascript闭包 新手版
2010/12/28 Javascript
js注意img图片的onerror事件的分析
2011/01/01 Javascript
JavaScript闭包实例讲解
2014/04/22 Javascript
jquery.mobile 共同布局遇到的问题小结
2015/02/10 Javascript
浅谈jQuery中replace()方法
2015/05/13 Javascript
js兼容火狐显示上传图片预览效果的方法
2015/05/21 Javascript
JS实现图片平面旋转的方法
2016/03/01 Javascript
JS Ajax请求如何防止重复提交
2016/06/13 Javascript
CentOS 安装NodeJS V8.0.0的方法
2017/06/15 NodeJs
AngularJS监听ng-repeat渲染完成的方法
2018/03/20 Javascript
Angular5给组件本身的标签添加样式class的方法
2018/04/07 Javascript
vue 实现数字滚动增加效果的实例代码
2018/07/06 Javascript
Vue2.5学习笔记之如何在项目中使用和配置Vue
2018/09/26 Javascript
基于vue-cli npm run build之后vendor.js文件过大的解决方法
2018/09/27 Javascript
浅析Angular 实现一个repeat指令的方法
2019/07/21 Javascript
[02:10]探秘浦东源深体育馆 DOTA2 Supermajor不见不散
2018/05/17 DOTA
在Python程序中操作文件之flush()方法的使用教程
2015/05/24 Python
深入解读Python解析XML的几种方式
2016/02/16 Python
Python对文件操作知识汇总
2016/05/15 Python
Python的Flask框架中集成CKeditor富文本编辑器的教程
2016/06/13 Python
Python多线程经典问题之乘客做公交车算法实例
2017/03/22 Python
Python读写及备份oracle数据库操作示例
2018/05/17 Python
python日志logging模块使用方法分析
2019/05/23 Python
详解pytorch 0.4.0迁移指南
2019/06/16 Python
Pandas操作CSV文件的读写实现方法
2019/11/13 Python
python构造函数init实例方法解析
2020/01/19 Python
DJI大疆无人机官方商城:全球领先的无人飞行器研发和生产商
2016/12/21 全球购物
Java语言程序设计测试题选择题部分
2014/04/03 面试题
解除劳动合同证明书模板
2014/11/20 职场文书
秋菊打官司观后感
2015/06/03 职场文书
在校学生证明格式
2015/06/24 职场文书
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
2021/07/01 MySQL