分类 未分类 下的文章

忽然想起这个命题, 在若干年以前, 军训的时候教官说我们班上40多人里必然有两个人同一天过生日, 还说没看过我们的生日, 感觉跟魔术一样. 让大家验证了一下, 居然有两组人的生日都在同一天. 而在之前公司里面20多个人, 也有同一天过生日的. 那么究竟一组人群里重复生日的概率是多少呢? 想验证一下.
用node.js来验证, 验证10万组:

const testTimes = 100000
const yearLength = 365

function main(){
  var doubledBirthdaysArrayLengths = []
  for(let i = 0; i < testTimes; i++){
    doubledBirthdaysArrayLengths.push(doubledLength())
  }
  console.log("一组人群中有相同生日的概率是多少?")
  console.log("有重复生日的人群的人数: ")
  console.log(doubledBirthdaysArrayLengths)
  console.log('生日重复的一组中最多人数: ', Math.max(...doubledBirthdaysArrayLengths))
  console.log('生日重复的一组中最少人数: ', Math.min(...doubledBirthdaysArrayLengths))
  console.log('生日重复的一组中平均人数: ', average(doubledBirthdaysArrayLengths))
  distribute(doubledBirthdaysArrayLengths)
}
function distribute(arr){
  let peopleNumsofGroups = [] //一组中的人数为数组下标, 数组值为此组人数出现的次数.
  for(let i = 0; i < yearLength; i+=1){
    peopleNumsofGroups.push(0)
  }
  for(let a of arr){
    peopleNumsofGroups[a]++
  }
  // console.log('Distribute: ', days)
  console.log('重复生日人群, 某一人数出现的次数:')
  printArrayInTable(peopleNumsofGroups, 0)
  let probes = [], sum = average(peopleNumsofGroups) * peopleNumsofGroups.length
  for(let i = 0; i < yearLength; i+=1){
    if(i == 0){
      probes[i] = peopleNumsofGroups[i]/sum * 100
    }else{
      probes[i] = peopleNumsofGroups[i]/sum * 100 + probes[i - 1]
    }
  }
  console.log('概率:')
  printArrayInTable(probes, 2)
}
function printArrayInTable(arr, fixDigits){
  console.log('\t[0]\t[1]\t[2]\t[3]\t[4]\t[5]\t[6]\t[7]\t[8]\t[9]')
  for(let row = 0; row < yearLength / 10 + 1; row+=1){
    let out = '[' + row + ']\t' 
    for(let col = 0; col < 10; col+=1){
      let index = row*10 + col
      if(index >= yearLength){
        return
      }
      out += arr[row*10 + col].toFixed(fixDigits) + '\t'
    }
    console.log(out)
  }
}
function average(arr){
  let sum = 0
  for(let a of arr){
    sum += a
  }
  return sum / arr.length
}

function doubledLength(){
  let birthdays = []
  for(let i = 0; i < yearLength + 1; i+=1){
    var birthday = parseInt(Math.random()*yearLength)
    if(findDouble(birthday, birthdays)){
      birthdays.push(birthday)
      // console.log("birthdays: ", birthdays)
      return birthdays.length
    }
    birthdays.push(birthday)
  }
  return birthdays.length
}

function findDouble(obj, arr){
  for(let a of arr){
    if(a == obj){
      return true
    }
  }
  return false
}

main()

输出结果如下:

一组人群中有相同生日的概率是多少?
有重复生日的人群的人数: 
[
  19, 22, 14,  3, 13, 25, 10, 24, 56,  5, 15, 27,
  25, 18, 27, 19, 22, 38, 21, 41,  9, 13, 37, 36,
  28, 25, 22, 29, 11, 23, 19, 14, 13, 16, 32, 26,
   8, 19,  7, 36,  6, 22, 18, 23, 20, 33, 32, 21,
  64, 22, 48, 43,  5, 16, 14,  7, 19, 32, 15, 16,
  15, 33, 58, 19, 26, 18, 45, 31,  4,  5, 30, 26,
  14, 19, 31, 14,  6,  9, 27, 12, 47, 51,  7, 21,
  16, 42, 66, 15, 28, 32, 18, 10, 12, 14, 10, 16,
  23, 15, 23,  8,
  ... 99900 more items
]
生日重复的一组中最多人数:  84
生日重复的一组中最少人数:  2
生日重复的一组中平均人数:  24.60991
重复生日人群, 某一人数出现的次数:
        [0]     [1]     [2]     [3]     [4]     [5]     [6]     [7]     [8]     [9]
[0]     0       0       279     577     842     1006    1334    1520    1873    1949
[1]     2223    2441    2627    2684    2975    2878    3110    3148    3229    3227
[2]     3269    3199    3180    3195    2974    3076    3014    2846    2747    2650
[3]     2624    2440    2327    2111    2096    1863    1807    1647    1564    1399
[4]     1271    1162    1023    996     884     773     738     642     575     541
[5]     460     394     384     325     277     247     203     173     143     148
[6]     111     97      79      71      55      53      41      36      31      18
[7]     24      16      9       16      4       5       7       2       6       6
[8]     1       0       1       0       2       0       0       0       0       0
[9]     0       0       0       0       0       0       0       0       0       0
[10]    0       0       0       0       0       0       0       0       0       0
[11]    0       0       0       0       0       0       0       0       0       0
[12]    0       0       0       0       0       0       0       0       0       0
[13]    0       0       0       0       0       0       0       0       0       0
[14]    0       0       0       0       0       0       0       0       0       0
[15]    0       0       0       0       0       0       0       0       0       0
[16]    0       0       0       0       0       0       0       0       0       0
[17]    0       0       0       0       0       0       0       0       0       0
[18]    0       0       0       0       0       0       0       0       0       0
[19]    0       0       0       0       0       0       0       0       0       0
[20]    0       0       0       0       0       0       0       0       0       0
[21]    0       0       0       0       0       0       0       0       0       0
[22]    0       0       0       0       0       0       0       0       0       0
[23]    0       0       0       0       0       0       0       0       0       0
[24]    0       0       0       0       0       0       0       0       0       0
[25]    0       0       0       0       0       0       0       0       0       0
[26]    0       0       0       0       0       0       0       0       0       0
[27]    0       0       0       0       0       0       0       0       0       0
[28]    0       0       0       0       0       0       0       0       0       0
[29]    0       0       0       0       0       0       0       0       0       0
[30]    0       0       0       0       0       0       0       0       0       0
[31]    0       0       0       0       0       0       0       0       0       0
[32]    0       0       0       0       0       0       0       0       0       0
[33]    0       0       0       0       0       0       0       0       0       0
[34]    0       0       0       0       0       0       0       0       0       0
[35]    0       0       0       0       0       0       0       0       0       0
概率:
        [0]     [1]     [2]     [3]     [4]     [5]     [6]     [7]     [8]     [9]
[0]     0.00    0.00    0.28    0.86    1.70    2.70    4.04    5.56    7.43    9.38
[1]     11.60   14.04   16.67   19.36   22.33   25.21   28.32   31.47   34.70   37.92
[2]     41.19   44.39   47.57   50.77   53.74   56.81   59.83   62.67   65.42   68.07
[3]     70.70   73.14   75.46   77.57   79.67   81.53   83.34   84.99   86.55   87.95
[4]     89.22   90.38   91.41   92.40   93.29   94.06   94.80   95.44   96.01   96.56
[5]     97.02   97.41   97.79   98.12   98.40   98.64   98.85   99.02   99.16   99.31
[6]     99.42   99.52   99.60   99.67   99.72   99.78   99.82   99.85   99.88   99.90
[7]     99.93   99.94   99.95   99.97   99.97   99.98   99.98   99.98   99.99   100.00
[8]     100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[9]     100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[10]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[11]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[12]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[13]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[14]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[15]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[16]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[17]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[18]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[19]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[20]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[21]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[22]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[23]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[24]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[25]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[26]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[27]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[28]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[29]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[30]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[31]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[32]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[33]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[34]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00
[35]    100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00  100.00

可以看到, 班上有40个人的时候, 有重复生日的概率已经高达90%左右了. 按中国班级的规定, 小学标准是45人,有94%的概率有两人同一天过生日. 初高中是50人, 概率则高达97%.如果把两个班放在一起, 概率就是100%了.

名称 说明 频段 组网
LoRaWAN 低功耗广域网, 公里级范围内组建的独立网络 470M/868M/913M等
NBIoT 5G标准之一, 附带在运营商基站上实现的低功耗物联网 800M/900M/1800M
IEEE 802.15.4 相当于IPV6无线物联网的物理层PHY和数据链路层MAC
Zigbee 基于IEEE 802.15.4的低功耗物联协议, 可软件升级至6LoWPAN,似乎会被后者取代 868M/915M/2.4G 星型,mesh
6LoWPAN IPV6标准之一, 基于IEEE 802.15.4, 是IP层和MAC层之间的适配层 868M/915M/2.4G Mesh
Thread 基于6LowPAN的互联协议 Mesh
蓝牙 有基础蓝牙和BLE蓝牙两种,距离比较短 2.4G 星型, Mesh
NFC 可通过无源的NFC标签提供信息 13.56M 1对1
WIFI 这个我们都熟悉, 用于物联网的一般都是2.4G 2.4G, 5.8G 星型
HomeKit 苹果的物联网接入协议, 将配件接入iOS终端
HarmonyOS Connect 华为的物联网接入协议

之前的文章

windows批处理bat根据查找字符串结果做不同处理
bat设置当前目录为path路径的方式
windows批处理batch调用新进程/窗口,不阻塞当前进程的继续执行
windows batch语法参考资料

简单描述

  • %1 %2 %3 ...代表.bat的第1/2/3...个输入参数
  • 条件判断括号中的变量是先替换为值再执行的, 如
    set var1=xxx
    set var2=ABC
    if %var1% == xxx (
    set var2=DEF
    echo %var2%
    )

    将输出ABC而不是DEF

微信小程序和支付宝小程序对比

这儿有一个对比: https://blog.csdn.net/qq_32279193/article/details/109130401

在阿里提供的小程序开发平台中, 基于mPaaS的小程序开发中, 有uni-appremax两个选项.

其中uni-app是dcloud制作的基于vue的跨平台小程序发布, remax是基于react构建跨平台小程序的工具

支付宝小程序开发工具下载和介绍

基于 阿里的mPaaS https://help.aliyun.com/document_detail/49549.html
需要下载IDE
https://help.aliyun.com/document_detail/67444.html
https://help.aliyun.com/document_detail/172408.html

关于 uni-app

uni-app要做的是对小程序的一次开发到处运行. Dcloud做的, 理念我很喜欢, 就是官网有点儿山寨.
uni-app的项目结构和node项目/vue-cli创建的项目非常像, 都有package.json, node_modules/, 以及src/下的main.js, app.vue, 编译后都会生成到dist/目录.
然而并非支持vue的库或者其他npm库在这儿都可以用. 比如vuetify就用不了. 怎么判断能不能用,哪些能用, 在uni-app的论坛里讲到:
https://ask.dcloud.net.cn/article/35489
总之, vuetify必须得换成其他实现方式了.
uni-app又基于了另一个mpvue工具. mpvue是将vue移植到小程序平台上运行的库. megalo是另一个类似功能的库. 似乎uni-app都有支持.

病症分类

  • 膨出: 纤维环上起个包, 但髓核没有突破出来
  • 突出: 纤维环已破, 但髓核起来的包没有掉出来
  • 脱出: 突出基础上, 髓核掉了一块出来, 但还和纤维环里面的髓核保持一些连接
  • 游离: 脱出的髓核完全断裂, 在椎管里乱跑, 最后会附着在不知道什么地方
    一般都是左边或者右边起个包

引起症状

  • 坐骨神经痛. 坐骨神经被压迫所致
  • 下肢麻木. 不同轻重情况不同. 最多可麻到脚趾尖尖
  • 晨起疼痛加重,运动或过段时间减轻: 据百度百科某网友回答, 是因为晚上血液循环能力降低, 突出位置产生水肿, 晨起后血液循环回复, 消除了水肿.

治疗方法

  • 激素类: 促进水肿吸收, 减少对神经的压迫
  • 手术类: 切除髓核, 也分为多种手术方式
  • 理疗类: 按摩/针灸/正确坐姿/硬板卧床30天
  • 运动类: 桥/大小燕飞
  • 自体吸收: 有研究发现有少部分患者突出的髓核被吸收. 医生排除了突出的髓核被纳回的可能, 主要考虑是免疫系统将突出的髓核作为抗原消灭了.参考

原文https://pyserial.readthedocs.io/en/latest/tools.html
安装pyserial

python -m pip install pyserial

使用Miniterm工具

python -m serial.tools.miniterm COM5 115200

cmd命令行窗口支持ESC颜色

python -m serial.tools.miniterm COM5 115200 -f direct

远程不能直接使用vscode idf插件的命令行, 需要打开idf插件的配置,将其中的path等信息改成bat运行一下.
示例如下:

set path=D:\r\esp\.espressif\tools\xtensa-esp32-elf\esp-2021r2-8.4.0\xtensa-esp32-elf\bin;D:\r\esp\.espressif\tools\xtensa-esp32s2-elf\esp-2021r2-8.4.0\xtensa-esp32s2-elf\bin;D:\r\esp\.espressif\tools\xtensa-esp32s3-elf\esp-2021r2-8.4.0\xtensa-esp32s3-elf\bin;D:\r\esp\.espressif\tools\riscv32-esp-elf\esp-2021r2-8.4.0\riscv32-esp-elf\bin;D:\r\esp\.espressif\tools\esp32ulp-elf\2.28.51-esp-20191205\esp32ulp-elf-binutils\bin;D:\r\esp\.espressif\tools\esp32s2ulp-elf\2.28.51-esp-20191205\esp32s2ulp-elf-binutils\bin ;D:\r\esp\.espressif\tools\cmake\3.20.3\bin;D:\r\esp\.espressif\tools\openocd-esp32\v0.10.0-esp32-20211111\openocd-esp32\bin;D:\r\esp\.espressif\tools\ninja\1.10.2;D:\r\esp\.espressif\tools\idf-exe\1.0.3;D:\r\esp\.espressif\tools\ccache\4.3\ccache-4.3-windows-64;D:\r\esp\.espressif\tools\dfu-util\0.9\dfu-util-0.9-win64;D:\r\esp\.espressif\tools\idf-git\2.30.1\cmd\;D:\r\esp\.espressif\python_env\idf4.4_py3.8_env\Scripts\;%PATH%
set IDF_PATH=d:\r\esp\esp-idf\
set IDF_TOOLS_PATH=D:\r\esp\.espressif
Set OPENOCD_SCRIPTS=D:\\r\\esp\\.espressif\\tools\\openocd-esp32\\v0.10.0-esp32-20211111/openocd-esp32/share/openocd/scripts
set IDF_CCACHE_ENABLE=1

还有一种方式是在esp-idf下有一些export.bat/.sh文件, 是用于配置idf环境的,不过可能需要修改.

通过 SSHFS windows manager可以挂载远程硬盘. 参考文章

项目地址: https://github.com/tencentyun/qcloud-iot-esp-wifi/tree/master/qcloud-iot-esp8266-demo
文档地址: https://cloud.tencent.com/document/product/1081/48370
8266项目的SDK又是基于腾讯的C SDK抽取的, C SDK地址: https://github.com/tencentyun/qcloud-iot-explorer-sdk-embedded-c

要修改的和供调用的

8266项目目录下components/qcloud_iot/qcloud_iot_c_sdk/includes中的几个文件是要修改的参数和调用的api放置的地方.
还有三元组信息在 components/qcloud_iot/qcloud_iot_c_sdk/platform下的HAL_Device_freertos.c文件中. 居然不是在头文件里定义, 感觉挺糟糕的.

要调用的API: qcloud_iot_export.h

这个qcloud_iot_export.h文件实际上include了所有在exports目录里面的.h文件. 所有的接口API在其中描述.

参数修改 qcloud_iot_export_variables.h

MQTT的心跳时间240s建议改为200s. 默认240s与服务器端太一致了, 设备时钟慢一点就会被服务器踢出.

/* default MQTT keep alive interval (unit: ms) */
#define QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL (200 * 1000)  // 原设置: 240*1000

参数修改 HAL_Device_freertos.c


#ifdef DEBUG_DEV_INFO_USED
/* product Id  */
static char sg_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "PRODUCT_ID"; // 修改

/* device name */
static char sg_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "YOUR_DEV_NAME"; // 根据mac生成的话, 需要在代码中动态修改 . 似乎应该在HAL_SetDevInfo()调用前或者干脆就在这个函数里修改

/* device secret of PSK device */
static char sg_device_secret[MAX_SIZE_OF_DEVICE_SECRET + 1] = "YOUR_IOT_PSK";

/* region */
static char sg_region[MAX_SIZE_OF_PRODUCT_REGION + 1] = "ap-guangzhou";

#ifdef GATEWAY_ENABLED
/* sub-device product id  */
static char sg_sub_device_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "PRODUCT_ID";
/* sub-device device name */
static char sg_sub_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "YOUR_SUB_DEV_NAME";
#endif

#ifdef DEV_DYN_REG_ENABLED
/* product secret for device dynamic Registration  */
static char sg_product_secret[MAX_SIZE_OF_PRODUCT_SECRET + 1] = "YOUR_PRODUCT_SECRET";  // 动态验证需要改这儿
#endif

编译文件修改component.mk

如果在main目录下自定义了新的文件夹用于放源码, 需要将这个文件夹加入编译路径 ,在component.mk中, 如增加一行:

COMPONENT_SRCDIRS += ./lamploop

主流程

samples目录下有4个demo程序, 实际上是根据sdkconfig里面的配置选择不同的demo进行编译. 以data_template_light的主流程示例如下:

main.c中的app_main()创建qcloud_demo_task任务
-->演示获取WIFI信息
-->联网
-->设置时间服务器
-->调用主逻辑qcloud_iot_explorer_demo
-->qcloud_iot_explorer_demo在samples/data_template_light/light_data_template_sample.c中定义
-->初始化连接信息_setup_connect_init_params
-->构建物模型也就是所谓的数据模板IOT_Template_Construct
-->初始化数据模板_init_data_template
-->注册模板属性_register_data_template_property
-->注册模板动作_register_data_template_action
-->获取系统信息_get_sys_info, 并上报IOT_Template_Report_SysInfo_Sync
-->获取数据状态IOT_Template_GetStatus_sync
-->处理下行数据逻辑deal_down_stream_user_logic
-->使能ota任务enable_ota_task
-->初始化报告时钟
-->倒计时10秒
-->进入task的死循环
  -->断开连接(!IOT_Template_IsConnected)超过20秒直接跳出死循环
  -->判断固件在下载is_fw_downloading, 睡0.5秒后,进入下次循环
  -->收到控制消息sg_control_msg_arrived
    -->进入控制信令处理deal_down_stream_user_logic
    -->回复服务器IOT_Template_ControlReply
  -->构造变化属性的报告deal_up_stream_user_logic(pReportDataList, &ReportCount)
    -->如果属性有变化, 则构造报告数组IOT_Template_JSON_ConstructReportArray
    -->上传报告数组IOT_Template_Report
  -->如果开启了事件处理, 则进行事件处理.
  -->睡到1秒
-->如果各种原因跳出了循环(看到的原因只有断开连接)
-->关闭ota任务
-->销毁模板

根据乐鑫v3.1模板加入qcloud_iot模块的方式

下面基于乐鑫的v3.1example/project_template项目基础上, 增加qcloud_iot功能
为解说方便, 将qcloud-iot-esp8266-demo项目称之为qcloud项目, 将将project_template项目称之为template项目

复制

  1. 要将qcloud项目components\qcloud_iot\qcloud_iot_c_sdk目录复制到template项目的components\qcloud_iot_c_sdk,去掉一级目录qcloud_iot.
  2. components\component.mk复制过来
  3. sdkconfig复制过来, 或者进入make menuconfig手动修改. 主要要改component config-->SSL-->mbedTLS下的内容:
  • (2560) TLS maximum OUTPUT message content length
  • (2560) TLS maximum INPUT message content length
  • TLS Protocol Role (Client)--->
    在`TLS Key Exchange Methods`下修改:
  • [*] Enable pre-shared-key ciphersuites
  • [*] Enable PSK based ciphersuite modes
  • [ ] Enable DHE-PSK based ciphersuite modes
  • [ ] Enable ECDHE-PSK based ciphersuite modes
  • [*] Enable RSA-PSK based ciphersuite modes
  • [*] Enable RSA-only based ciphersuite modes
  • [ ] Enable DHE-RSA based ciphersuite modes

深入文档

要深入了解文档,还是要看C-SDK项目的示例而不是8266-C-SDK的项目示例
qcloud-iot-explorer-sdk-embedded-c
视频教程

OTA分片下载例程更新

https://git.code.tencent.com/hubertxxu/qcloud_iot_explorer_esp8266