【PyQt】PyQt的缺陷及意外退出的可能原因

news2024/9/27 19:19:26

1 背景

最近在软件项目中比较深入的用到了 Qt GraphicsView Framework。PyQt 作为 Qt 的非官方Python绑定库(Qt的官方Python绑定库是PySide)总是出现很多意外崩溃/Bug,并且很难调试和追踪。

2 问题

软件项目中需要自定义 QGraphicsItem ,该图元能在某些条件下 改变自己的几何形状,比如从三角形变成五角星。改变形状倒是没有任何难点,无非就是改变它的 path,再 drawPath 即可。

但是在利用重新实现的旋转和缩放交互(改变图元的几何形状)后,再从 scene 中删除该图元(使用scene.removeItem()函数)时,程序就会直接崩溃或者卡死,PyCharm调试窗口没有任何的输出和提示,用try...except将可疑代码包裹起来也无法调试,也是直接崩溃退出。

3 线索

最后在互联网上搜索了许久,也翻看 Qt 文档很久,才查到一些蛛丝马迹。

在 Qt 文档中,有 QGraphicsItem的 boundingRect() 函数,该函数说明中有如下一段话:

If you want to change the item's bounding rectangle, you must first call prepareGeometryChange(). This notifies the scene of the imminent change, so that it can update its item geometry index; otherwise, the scene will be unaware of the item's new geometry, and the results are undefined (typically, rendering artifacts are left within the view).

翻译过来就是:

若想改变图元的边界矩形,必须首先调用 prepareGeometryChange() 函数。该函数会通知 scene 即将来临的改变,所以 scene 能够更新它的图元几何索引(?没看到Qt 哪里讲到什么 item geometry index,看到的朋友评论里告诉我);否则,scene 将无法知道图元的新几何形状,此时结果是无法预料的(一种典型的结果就是:渲染的残影(伪影)会被遗留在视图 view 中)。

这里面提到:若想改变图元的边界矩形,必须首先调用 prepareGeometryChange() 函数。说明程序崩溃的原因,可能就是未调用 prepareGeometryChange() 函数。

该函数的用法如下(Qt官方文档代码):

 void CircleItem::setRadius(qreal newRadius)
 {
     if (radius != newRadius) {
         prepareGeometryChange();
         radius = newRadius;
     }
 }

用了此函数,并没有解决问题,最后的最后(苦苦摸索两个星期),最后发现了一个解决方案,但具体原因不明。

解决方案:

设置QGraphicsScene的属性itemIndexMethod 为 NoIndex。

案例代码如下,其中GvScene为自定义的Scene,为了修改Scene默认背景色。 

class GvScene(QGraphicsScene):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setBackgroundBrush(QColor(10,10,10))    # 背景色
        self.setSceneRect(0, 0, 1920, 1080)          # 区域大小
        self.setItemIndexMethod(QGraphicsScene.NoIndex)     # 特别关键

Qt官方文档对其描述:

itemIndexMethod : ItemIndexMethod

This property holds the item indexing method.

QGraphicsScene applies an indexing algorithm to the scene, to speed up item discovery functions like items() and itemAt(). Indexing is most efficient for static scenes (i.e., where items don't move around). For dynamic scenes, or scenes with many animated items, the index bookkeeping can outweight the fast lookup speeds.

For the common case, the default index method BspTreeIndex works fine. If your scene uses many animations and you are experiencing slowness, you can disable indexing by calling setItemIndexMethod(NoIndex).

Access functions:

QGraphicsScene::ItemIndexMethod

itemIndexMethod() const

void

setItemIndexMethod(QGraphicsScene::ItemIndexMethod method)

See also bspTreeDepth.

ItemIndexMethod 的说明:

enum QGraphicsScene::ItemIndexMethod

This enum describes the indexing algorithms QGraphicsScene provides for managing positional information about items on the scene.

Constant

Value

Description

QGraphicsScene::BspTreeIndex

0

A Binary Space Partitioning tree is applied. All QGraphicsScene's item location algorithms are of an order close to logarithmic complexity, by making use of binary search. Adding, moving and removing items is logarithmic. This approach is best for static scenes (i.e., scenes where most items do not move).

QGraphicsScene::NoIndex

-1

No index is applied. Item location is of linear complexity, as all items on the scene are searched. Adding, moving and removing items, however, is done in constant time. This approach is ideal for dynamic scenes, where many items are added, moved or removed continuously.

翻译如下:

此枚举变量描述的是 QGraphicsScene 为管理Scene中的图元的位置信息而提供的索引算法。

BspTreeIndex:使用二叉空间剖分树(BSP树)作为索引。所有的QGraphicsScene的图元的定位算法通过使用二分查找可接近对数级复杂度(即O(logN))。增加、移动、删除图元也是对数级。这个方法最适合静态的scene(scene内的图元不移动)。

NoIndex:不使用索引。图元定位是线性复杂度,因为要检索scene中的所有图元。但是增加、移动和删除图元立刻就可完成。这个方法是动态的scene的理想方法,动态的scene经常需要连续的增加、移动和删除大量的图元。

看上面的官方文档说明,确实是应该使用 NoIndex,但是为何默认使用 BspTreeIndex 时,程序会直接崩溃呢?原因不明。

4 教训

在找到 解决方案:

设置QGraphicsScene的属性itemIndexMethod 为 NoIndex

之前,我搜索了很多文章资料,有很多可能导致程序崩溃的原因,于是我逐一做了修改,但都没有起到关键性的作用(没有阻止程序崩溃),但也可能有作用,记录如下。

4.1 自定义图元的boundingRect

在官方文档中,官方特意强调 boundingRect  要包含 Pen 的宽度的一半。

Make sure to constrain all painting inside the boundaries of boundingRect() to avoid rendering artifacts (as QGraphicsView does not clip the painter for you). In particular, when QPainter renders the outline of a shape using an assigned QPen, half of the outline will be drawn outside, and half inside, the shape you're rendering (e.g., with a pen width of 2 units, you must draw outlines 1 unit inside boundingRect()). QGraphicsItem does not support use of cosmetic pens with a non-zero width.

必须确保将所有的绘制的东西都包含在boundingRect() 内,这样可以避免出现残影(因为 QGraphicsView 并不会自动替你裁剪图形)。

特别要强调的是,当 QPainter 使用被设置的QPen来渲染几何形状(shape)的轮廓(outline)时,轮廓的一半将被画到几何形状(shape)的里面,一半会在几何形状(shape)的外面(举例来说,如果设置了2单位宽度的画笔,那么你必须在图元的 boudingRect()函数中画出1像素的轮廓来)。

QGraphicsItem不支持使用非零宽度的修饰画笔。

引自Qt5官方文档。

其含义见图即明:

如图,红色矩形框  即为  shape ,即图元的逻辑几何形状;灰色矩形中空框 即为 outline ,也就是图元的 shape 的轮廓。

 我之前偷懒直接用 自定义图元的path.boundingRect作为 图元的 boundingRect。后来改成了:

    
def boundingRect(self):
    path = self.Path        # 此处path为图元的path
    pathRect = path.boundingRect()
    itemRect = pathRect.adjusted(-2, -2, 2, 2)    # 这里的2根据你的画笔宽度而定
                                     # 至少为画笔宽度的1/2,也可偷懒直接用画笔宽度
    return itemRect

# adjusted()的4个参数依次加到 QRect的四个坐标值上。
# adjusted(-2, -2, 2, 2)表示矩形的左上角点向左和向上各移动2像素,
# 右下角点向右和向下各移动2像素,
# 矩形长度增长4,高度增长4

注意: adjusted() 函数暗藏风险,切勿错误理解 adjusted()函数,adjusted()函数详细解释见此文。

4.2 自定义图元几何结构变化前调用prepareGeometryChange()

前文提到prepareGeometryChange()函数的作用,此处不再赘述。

在这里说明,prepareGeometryChange()函数最好放置在 改变图元几何结构的函数的内部第一行最妥当。

4.3 自定义图元的paint()函数

自定义图元在paint()函数中绘制自身。paint()函数的三个参数:painter, qstyleopt, widget,根据我实操得知,painter 是同一个自定义图元类的所有对象 共用的 ! widget 也是 同一个自定义图元类的所有对象 共用的 !

比如,你创建了一个自定义图元:苹果图元类 AppleItem,然后在Scene上添加10个苹果(对象)。此时,这10个苹果(对象)的 paint()函数中的 painter 都是同一个(可以在paint函数中print(painter)查看),这10个苹果(对象)的widget也是同一个。

既然是大家共用同一个painter,那不得乱了套。所以最好在 paint 函数中,设置 painter 前,先调用 painter.save() ,将当前的 painter 状态暂存起来,等着此次用完再恢复 painter.restore()。

You can at any time save the QPainter's state by calling the save() function which saves all the available settings on an internal stack. The restore() function pops them back.

如果 paint 中出现 for 循环, for循环中不断的setPen和setBrush(),那就更加需要调用 save()和 restore()。

虽然 Qt5 文档中,不需要显式的调用 save和restore,但是非要直接调用它,肯定不会错。

这样,大家各不耽误,就像借别人电脑,先把别人正在处理的文件保存好,再使用电脑做自己的事情,用完电脑,再把别人的文件都重新恢复,别人可以继续处理他的文件。

    def paint(self, painter, qstyleopt, widget):
        painter.save()                # 暂存当前状态
        painter.setPen(YourPen)       # 处理自己的事情
        painter.setBrush(YourBrush)
        painter.drawPath(path)
        painter.restore()             # 恢复开始的状态

5 其它收获

在解决该问题的过程中,收获到一篇文章,讲到 PyQt 的缺陷和避免BUG的经验,是这篇文章启发了我,特转载如下。

这篇文章可能是外网文章,由机器翻译过来的,无所谓,可以看懂其意思。适合研究较深入的人了解。

以下为原文,转载自:

关于python:避免PyQt崩溃/挂起的好的做法是什么?https://www.codenong.com/11945183/


<转载文章开始>

关于python:避免PyQt崩溃/挂起的好的做法是什么?


What are good practices for avoiding crashes / hangs in PyQt?

我同时喜欢python和Qt,但是对我来说很明显Qt并不是在设计时就考虑到python的。 有很多方法可以使PyQt / PySide应用程序崩溃,即使使用适当的工具,也很难调试很多方法。

我想知道:使用PyQt和PySide时避免崩溃和锁定的良好实践是什么? 从常规的编程技巧和支持模块到高度特定的解决方法和应避免的错误,这些都可以。

 相关讨论

  • 嘿,我已经看到您发布了很多有关pyqt的信息,我想知道您是否可以解决这个问题:/ stackoverflow.com/questions/57298291/


通用编程实践

  • 如果必须使用多线程代码,则永远不要从非GUI线程访问GUI。总是通过发出信号或其他线程安全机制将消息发送到GUI线程。
  • 注意"模型/查看任何内容"。 TableView,TreeView等。它们很难正确编程,并且任何错误都会导致无法跟踪的崩溃。使用模型测试可帮助确保模型内部一致。
  • 了解Qt对象管理与Python对象管理交互的方式以及可能出错的情况。参见http://python-camelot.s3.amazonaws.com/gpl/release/pyqt/doc/advanced/development.html

    • 没有父级的Qt对象由Python拥有;只有Python可以删除它们。
    • 带有父对象的Qt对象归Qt所有,如果删除了它们的父对象,则Qt将删除它们。
    • 示例:带有PyQt4的核心转储
  • QObject通常不应引用其父代或其任何祖先(可以使用弱引用)。这将最多导致内存泄漏,并偶尔导致崩溃。
  • 请注意Qt自动删除对象的情况。如果未通知python包装器删除了C ++对象,则对其进行访问将导致崩溃。由于PyQt和PySide在跟踪Qt对象方面遇到困难,因此可以通过许多不同的方式发生这种情况。

    • 复合控件,例如QScrollArea及其滚动条,QSpinBox及其QLineEdit等。(Pyside没有此问题)
    • 删除QObject会自动删除其所有子级(不过PyQt通常会正确处理此子级)。
    • 从QTreeWidget中删除项目将导致所有关联的小部件(通过QTreeWidget.setItemWidget设置)被删除。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27

      # Example:
      from PyQt4 import QtGui, QtCore
      app = QtGui.QApplication([])

      # Create a QScrollArea, get a reference to one of its scroll bars.
      w = QtGui.QWidget()
      sa = QtGui.QScrollArea(w)
      sb = sa.horizontalScrollBar()

      # Later on, we delete the top-level widget because it was removed from the
      # GUI and is no longer needed
      del w

      # At this point, Qt has automatically deleted all three widgets.
      # PyQt knows that the QScrollArea is gone and will raise an exception if
      # you try to access it:
      sa.parent()
      Traceback (most recent call last):
        File"<stdin>", line 1, in <module>
      RuntimeError: underlying C/C++ object has been deleted

      # However, PyQt does not know that the scroll bar has also been deleted.
      # Since any attempt to access the deleted object will probably cause a
      # crash, this object is 'toxic'; remove all references to it to avoid
      # any accidents
      sb.parent()
      # Segmentation fault (core dumped)

具体的解决方法/错误

  • 在不先调用prepareGeometryChange()的情况下更改QGraphicsItems的边界可能会导致崩溃
  • 在QGraphicsItem.paint()内部引发异常可能导致崩溃。始终在paint()中捕获异常并显示一条消息,而不是让异常继续进行。
  • QGraphicsItems永远不要保留对其生活的QGraphicsView的引用。(可以使用弱引用)。
  • 重复使用QTimer.singleShot可能会导致锁定。
  • 避免将QGraphicsView与QGLWidget一起使用。

避免出口崩溃的实践

  • 不属于QGraphicsScene的QGraphicsItem可能导致退出时崩溃。
  • 引用其父级或任何祖先的QObject可能导致退出崩溃。
  • 没有父级的QGraphicsScene可能导致退出崩溃。
  • 避免退出崩溃的最简单方法是在python开始收集Qt对象之前调用os._exit()。但是,这可能很危险,因为程序的某些部分可能依赖于正确的退出处理才能正确运行(例如,终止日志文件或正确关闭设备句柄)。至少,应该在调用os._exit()之前手动调用atexit回调。

 相关讨论

  • 您对QObject层次结构提出的几项主张值得高度质疑。与PyQt或PySide本身的问题相比,它们听起来更像是程序错误的程序-但是很难看到真实的例子。您给出的唯一特定示例完全是人工的-为什么创建QScrollArea然后立即将其丢弃?您是否向PyQt和/或PySide的维护者提出了这些问题?如果您没有,在这里记录它们似乎毫无意义。
  • 您是正确的,其中许多问题是程序设计错误的结果,而不是pyqt / pyside错误(我无意暗示)。但是,我在此列表中提出的每个问题都至少来自我在自己的应用程序中遇到的一个实际错误。他们中的许多人花费了数小时的调试才能解决,因此需要像这样的综合清单。我举的例子是人为的,是的,但这仅仅是因为我简化了它。不难想象会导致崩溃的实际情况。
  • 我为您的部分添加了一些有关删除C ++对象的额外示例...但是,我仍然觉得总体而言,使用ScrollWidget来完成它是一个糟糕的示例,因为这永远不会发生。我认为应该完全重新编辑它,以简单地显示python和c ++所有权ob对象之间的区别。
  • 该示例并非旨在涉及对象所有权-删除Qt对象有很多合理的理由。关键是PyQt和PySide在跟踪其Qt对象方面并不完美。如果出现问题,将导致崩溃。更大的一点是,如果我们了解导致这些崩溃的原因,则可以通过更仔细的编程实践完全避免它们。


仅供参考,我将PyQt的作者对路加的回答发表评论:"这是垃圾。"

我认为这很重要,因为有人可以跳到这篇文章,并对所有这些(不存在的)"问题"感到困惑。

 相关讨论

  • 作为一般建议,很多建议都具有误导性。它的确突出了一些重要的问题,但是许多建议的"解决方案"实际上比他们试图解决的所谓问题更糟。
  • 其可编辑;欢迎您修复它。这些是我多年来修复与PyQt相关的分段错误的观察结果。我肯定那里列出的许多项目已经修复,或者有更复杂的原因,而我从未完全意识到。


补充一点:

如果必须在基于qt的程序中使用线程,则实际上必须禁用自动垃圾收集器并在主线程上进行手动收集(如http://pydev.blogspot.com.br/2014/03/should- python-garbage-collector-be.html)-请注意,即使确保对象没有循环也应该这样做(通过循环,基本上可以使对象处于活动状态,直到python循环垃圾收集器崩溃为止,但是有时,如果您有例外情况,则可能会使某个帧保持活动状态,因此,在这种情况下,您的对象可能仍保持活动状态的时间比您预期的长)。在这种情况下,垃圾收集器可能会撞到在辅助线程中,这可能导致qt发生段错误(必须始终将qt小部件收集在主线程中)。

 相关讨论

  • 啊,我什至从未考虑过G??C!
  • 这里唯一要注意的是,如果您在带有qt小部件的python中创建循环,则gc.collect()仍然有可能崩溃(因为删除顺序可能会出错-可能会出现段错误-这可以认为是PySide中的错误,不幸的是并不罕见)。


<转载文章结束> 

<全文结束>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/139842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初识Cocos Creator

1.1 Cocos 不同时期与产品刚接触Cocos家族的时候&#xff0c;会有很多个Cocos的版本与分支&#xff0c;比如Cocos2d, Cocos2d-x, Cocos Creator 1.x, Cocos Creator 2.x, Cocos Cretor3D, Cocos Creator 3.x, CocosDashboard, 等我们先把Cocos 的主要产品脉络梳理一遍。对啦&am…

人体reid数据集

mars数据集 参考&#xff1a;https://blog.csdn.net/qq_34132310/article/details/83869605 整个Mars数据的大小大概有6.3G。 bbox_train文件夹中&#xff0c;有625个子文件夹&#xff08;代表着625个行人id&#xff09;&#xff0c;共包含了8298个小段轨迹&#xff08;track…

联合证券|战略新兴产业火了,高增长低估值股曝光

导读&#xff1a;2022年&#xff0c;A股商场值得记载的前史性大事件不断。这一年&#xff0c;A股商场上市公司数量正式打破5000家&#xff0c;战略新兴产业上市公司数量打破2500家&#xff0c;占比初次打破50%大关。这一年&#xff0c;A股商场顶住杂乱的外部环境因素&#xff0…

Pytorch介绍与基本使用

前言Pytorch是torch的python版本&#xff0c;是由Facebook开源的神经网络框架&#xff0c;专门针对 GPU 加速的深度神经网络&#xff08;DNN&#xff09;编程&#xff0c;根据我在网上的了解&#xff0c;相比于Tensorflow&#xff0c;Pytorch简介易用。一、为什么选择Pytorch简…

在VBA里使用range(cells(),cells()) ,一个容易出错的点:需要注意 range() 和cells() 前都指定好sheet名!

1 问题 在VBA里使用range(cells(),cells()) 发现处了下面这个状况 当前sheet就是sh1时&#xff0c;代码正常运行当前sheet不是sh1时&#xff0c;有一行代码报错 arr3 sh1.Range(Cells(4, 3), Cells(16, 8))为什么会这样呢&#xff1f;Sub test1001()Dim sh1 As ObjectSet s…

足球视频AI(二)——球员与球的目标检测

一、基础概念 1.1 识别目标&#xff1a; 1&#xff09;固定机位的视频中球员逐帧识别 2&#xff09;固定机位的视频中球逐帧识别 3&#xff09;位置换算与记录 1.2 实现思路 1&#xff0c;利用OpenCV的相邻帧差异识别移动物体 2&#xff0c;利用YOLO7的机器学习识别对象&…

LNPS递送辅料,DOPE,4004-05-1,二油酰磷脂酰乙醇胺

LNPS递送辅料&#xff0c;DOPE&#xff0c;4004-05-1&#xff0c;二油酰磷脂酰乙醇胺 中文名称 &#xff1a;1,2-二油酰-sn-甘油-3-磷酸乙醇胺 中文别称 &#xff1a;二油酰磷脂酰乙醇胺 英 文 名 &#xff1a;DOPE 英文别称 &#xff1a;1,2-Dioleoyl-sn-glycero-3-phospho…

数据仓库介绍

数据仓库数据仓库的概念数据仓库的主要特征数据仓库的主流开发语言-sql结构化数据sql语句数据仓库的概念 数据仓库&#xff08;英语&#xff1a;Data Warehouse&#xff0c;简称数仓、DW&#xff09;,是一个用于存储、分析、报告的数据系统。 数据仓库的目的是构建面向分析的集…

一、MyBatis-Plus简介

文章目录一、MyBatis-Plus简介1、简介2、特性3、支持数据库4、框架结构5、代码及文档地址【尚硅谷】MyBatisPlus教程-讲师&#xff1a;杨博超 失败&#xff0c;是正因你在距成功一步之遥的时候停住了脚步。 一、MyBatis-Plus简介 1、简介 MyBatis-Plus&#xff08;简称 MP&am…

吴恩达【神经网络和深度学习】Week2——神经网络基础

文章目录1、Logistic Regression as a Neural Network1.1、Binary Classification1.1.1、Introduction1.1.2、Notations1.2、Logistic Regression1.3、Logistic Regression Cost Function1.4、Gradient Descent1.5、Derivatives&#xff08;导数&#xff09;1.6、More derivati…

基于支持向量回归(SVR)和PROSAIL模拟光谱数据的叶面积指数反演

前言本博客利用PROSAIL模型模拟出MODIS的光谱数据和LAI&#xff0c;然后采用支持向量回归&#xff08;SVR&#xff09;方法建立NDVI与LAI 的回归模型&#xff0c;用于LAI的反演。训练和测试数据的拟合效果还是比较好的&#xff0c;这表明SVR在模拟的光谱数据与LAI回归方面的可行…

NXP EMDA学习(2):串口eDMA接收和发送流程详解

在单片机中&#xff0c;最基础的一个驱动就是串口&#xff0c;本文就以NXP中串口eDMA的收发为例&#xff0c;通过分析源代码来理解eDMA的执行过程。 参考代码&#xff1a;Kinetis K64 Sub-Family SDK 2.11中的uart_edma_transfer.c 文章目录1 串口基本初始化2 DMAMUX初始化3 初…

Go语言 WaitGroup 源码知多少

前面的文章我们写协程的时候有用到 WaitGroup 我们的写法大概是这样的 func main() {...dothing()wg : sync.WaitGroup{}// 控制 多个子协程的声明周期wg.Add(xx)for i : 0; i < xx; i {go func(ctx context.Context) {defer wg.Done()...dothing()}(ctx)}...dothing()// …

【Android春招】Android基础

一、填空题 1&#xff0e;Android是基于__ 的移动端开源操作系统。 Linux 2&#xff0e;Android系统是由__公司推出的。 谷歌 3&#xff0e;Android 11对应的API编号是__。 30 4&#xff0e;App除了在手机上运行&#xff0c;还能在电脑的__上运行。 模拟器&#xff08;AVD&…

Pytorch SoftMax回归

目录 数据集 从零实现 简单实现 数据集 导入所需库 torchvision计算机视觉所用torch的库 %matplotlib inline import torch import torchvision from torch.utils import data from torchvision import transforms from d2l import torch as d2l # 用SVG清晰度高 d2l.use_…

华为交换机OSPF对接思科交换机EIGRP,牛逼配置!

简介 思科交换机OSPF分别与华为交换机OSPF以及思科交换机EIGRP进行路由交互&#xff0c;间接实现华为交换机OSPF对接思科交换机EIGRP的功能。 配置注意事项 该案例适用于支持OSPF的华为交换机。该案例仅提供OSPF对接EIGRP的基本配置。思科交换机与华为交换机对接替换时&…

固定资产年结操作步骤 及常见问题处理:AJAB 关闭资产年度报错问题处理

目录 第一步、打开新的资产会计年度 TCODE &#xff1a; AJRW 第二步、 关闭资产年度 TCODE&#xff1a;AJAB 三、结果校验 四、 常见问题 分析 第一步、打开新的资产会计年度 TCODE &#xff1a; AJRW 输入公司编码&#xff0c;输入新的资产会计年度 先测试运行&a…

【计算机网络-数据链路层】差错控制(检错编码、纠错编码)

文章目录1 检错编码——奇偶校验码1.1 奇偶校验码1.2 相关例题2 检错编码——循环冗余码&#xff08;CRC&#xff09;2.1 发送端——生成冗余码2.2 接收端——检错2.3 相关例题3 纠错编码——海明码3.1 确定海明码的位数3.2 确定校验位的分布3.3 对校验码进行分组3.4 求出校验码…

LCHub:中国企业数字化门槛持续降低,数字化转型成本下降达80%

12月27日,钉钉联合中国信息通信研究院发布《“小快轻准”持续降低数字化转型门槛》研究报告(以下简称“报告”)。报告指出,中国企业数字化门槛正持续降低,数字化转型成本已降低80%;以钉钉为代表的数字平台,为中小企业提供了一条普惠、敏捷、低成本的数字化转型新路径;中国…

一种可远程监控的无线压力传感器

压力是工业生产中的重要参数之一&#xff0c;压力传感器是工业实践中最为常用的一种传感器。无线压力传感器TSM-04P是一款外接电源供电、具有无线通讯功能的高精度智能测压设备&#xff0c;采用4G通信方式&#xff0c;可选太阳能供电或电源供电。内置扩散硅传感器&#xff0c;能…