2025-09-30 10:34:29    3    0    0

(一)单元视图标识符和实例母体标识符

简述:

  • Cell View Identifier(单元视图标识符):定义了一个独立的、完整的设计模块本身。它是“蓝图”或“模板”的ID。
  • Instance Master Identifier(实例母体标识符):定义了一个被引用的、具体的母体对象。它是“根据蓝图制造出来的那个具体零件”的ID。

Cell View Identifier(单元视图标识符)

  • 这指的是一个完整的设计“单元”在库中的唯一身份。它通常由三部分(在某些工具中是两部分)组成:
    • Library: 库名
    • Cell: 单元名
    • View: 视图名
  • 例如: myLib / inverter / schematic,又例如:myLib / inverter / layout
  • 它的作用是:
    • 唯一地标识一个设计文件。当你说“打开 myLib 库下的 inverter 单元的 layout 视图”时,工具就是通过这个标识符来找到并打开那个具体的版图或电路图文件的。
    • 它代表的是一个可编辑的源文件。你可以直接打开、修改并保存它。
  • 一个形象的比喻:- myLib/inverter/layout 就像是一张 “反相器的建筑设计蓝图” 。这张蓝图本身存放在“myLib”这个档案库中。

Instance Master Identifier(实例母体标识符)

这指的是在一个设计中被实例化(引用)的那个目标对象的身份。

当你在一个上层设计(比如 top_level 的版图)中,放置一个子单元(比如 inverter)时,你创建的是一个 “实例”。这个实例本身并不是一个独立的文件,它只是一个指针,指向它所代表的那个底层单元。

这个指针所指向的目标,就是 Instance Master。

它的标识符和 Cell View Identifier 是完全一样的! 也是 Library/Cell/View。

例如:
在你的顶层版图 myLib/top_level/layout 中,你放置了一个反相器。这个反相器实例所指向的 Master 就是 myLib/inverter/layout。

它的作用是:

告诉工具:“我这个实例,是依据哪个蓝

2025-09-30 10:24:23    3    0    0

1、快捷键

1.1 截图:

  • welink截图: ctrl+alt+s截图后, 可以固定在屏幕上;
  • 微信截图: alt+A
  • linux在终端中拷贝和粘贴:
    • 复制:ctrl+insertctrl+shift+C;
    • 粘贴:shift+insertctrl+shift+V;
  • VNC以外粘贴到vncviewer中:
    • 从VNC以外粘贴到vncviewer中去, 需要打开vncconfig才行, 关闭掉vncconfig就不行(难道是bug?), vncconfig路径在/usr/bin下面(可以输入vnc然后tab查看)。
    • 需要从外部粘贴时,在终端中输入vncconfig &, 使其脱离终端后台运行并最小化弹出来的vncconfig设置框, 然后就可以粘贴外部clipboard上的内容了。

1.2 文件:

1.2.1 文件操作

  • 希望每次打开文件夹后, 不是新开一个窗口(窗口太多了, 很乱), 可以这样操作:
    • 随便打开一个文件夹, 选择Edit->Preferences->tab中选择Behavior->勾选Always open in browser windows.
  • 希望每次使用gedit打开文件, 不产生副本(如run.sh, 可能会产生run.sh~这样的副本), 可以这样操作:
    • 随意使用gedit打开一个文件, 选择Edit->Preferences->tab中选择Editor->取消勾选Create a backup copy of files before saving

1.2.2. 文件查找

  • 查找当前路径./dbcmd下某某写的case(递归查找文件,而不是目录名):
    • 直接查找, 可能查找到目录名:find . -name "file.txt"
    • 输出到a.log中去:find ./dbcmd -type f -name "*libo.tar.gz" > a.log
    • 判断数量:find ./dbcmd -type f -name "*libo.tar.gz" | wc -l
  • 仅查找当前文件夹中,文件名包含keyword的文件, 不包含文件夹:
    • find . -type f -name "*
2025-07-09 22:24:36    1    0    0

某个源文件多次包含同一个头文件

某个源文件多次包含同一个头文件时,如果头文件中有定义语句,那么不管是什么东西的定义,都可能会产生重定义错误。这种情况是很常见的问题,通常可以使用宏定义保护避免:

  1. #ifndef A_H
  2. #define A_H
  3. /* 这里写真正的头文件 */
  4. #endif

使用#program once也可以,二者区别参考#program once 和 #ifndef

多个源文件包含了同一个头文件

错误原因

但是多个源文件包含同一个头文件,宏定义或者#program once也无法进行避免了,一个本人真实遇到的例子是:。

m_settings.h中:

  1. #ifndef _M_SETTINGS_H
  2. #define _M_SETTINGS_H
  3. ...
  4. namespace setting_ns {
  5. int aa = 10;
  6. QStringList splitArgs(const QString &s, int idx){
  7. // splitArgs函数的定义
  8. }
  9. // 这里因为aa和splitArgs的定义在头文件内,要么改成const和inline,要么将定义放到.cpp中以避免可能的重定义报错
  10. }
  11. #endif

qsetting_obj.h中,包含了m_settings.h:

  1. ···
  2. #include "header/m_settings.h"

很不幸,在main.cpp中,我又同时include包含了qsetting_obj.hm_settings.h,导致变量aasplitArgsmultiple definition of重定义报错,哪怕这里套上命名空间都没用,因为是重复包含导致的和自身重复,而不是和外部的别的符号重复。

按道理来说,使用 #ifdef 等条件编译语句避免头文件在同环境被重复包含,由于#ifndef ...宏定义的保护,只会include一次m_settings.h
但是, 请注意"同环境"这个限定,include虽然只是是简单的将文件复制进cpp吗,当多个cpp源文件包含了同一个头文件时,如果头文件中有某个局部变量或者非内联(inline)函

2023-03-31 18:27:54    62    0    0

1、问题

常见点云存储方式有pcd、ply、txt、bin文件等。kitti数据集的点云是bin格式的,而pcl的数据格式为pcd格式。在使用点云库进行开发时,一般需要将bin格式的点云数据转为pcd格式。网上有很多介绍点云格式如何转换的博客,但是很多的bin2pcd函数的写法都存在小问题,这里记录下我发现的问题并给出解决办法。

2、PointXYZI的内存设计

首先介绍下比较PCL中常见的PointXYZI点类型。
PointXYZI是一个简单的XYZ坐标加intensity的point类型,理想情况下,这4个变量将新建单独一个结构体,并且满足存储对齐,然而由于PCL的大部分操作会把data[4]元素设置成0或1(用于变换),不能让intensity与XYZ在同一个结构体中。因为如果这样的话其内容将会被覆盖。
例如两个点的点积会把他们的第4个元素设置成0, 否则该点积没有意义,等等。因此,对于兼容存储对齐用3个额外的浮点数来填补intensity,这样在存储方面效率较低但是符合存储对齐要求,运行效率较高。

PointXYZI结构体源代码如下:

  1. // PointXYZI占32个字节,8个浮点数的空间,但是只有四个有效,其余的为填充
  2. struct PointXYZI {
  3. union {
  4. float data[4];
  5. struct {
  6. float x;
  7. float y;
  8. float z;
  9. }
  10. }
  11. union {
  12. struct {
  13. float intensity;
  14. }
  15. float data_c[4];
  16. }
  17. }

3、问题写法一

3.1 问题发现

方法一生成的pcd文件中,可以正常可视化,但是由于最后一个点存在x=0,y=0,z=0,intensity=0的情况,生成深度图时,会出现崩溃问题。

对于使用ascll编码的pcd文件是可以用记事本打开的, 我们打开导致崩溃的pcd文件,可以发现最后一个点是0 0 0 0,这将导致创建深度图时

2022-12-02 15:43:57    49    0    0

1、左值右值

1.1 左值

  • 放在等式左边,可以取地址并且有名字的变量。比如:
    • 函数名和变量名
    • 返回左值引用的函数调用
    • 前置自增减表达式++i、--i
    • 由赋值表达式或赋值运算符连接的表达式(a=b,a+=b等)
    • 解引用表达式*p
    • 字符串字面值"abcd"
  1. int a= 4; //a是左值,4 作为普通字面量是右值

1.2 右值

  • 不能取地址的没有名字的东西就是右值,一般放在等式右边。C++11以后,右值又分为纯右值和将亡值。

1.2.1 纯右值

  • 运算表达式产生的临时变量、不和对象关联的原始字面量、非引用返回的临时变量、lambda表达式等都是纯右值。例如:
    • 除字符串字面值外的字面值
    • 返回非引用类型的函数调用
    • 后置自增减表达式i++、i--
    • 算术表达式(a+b,a*b, a&&b,a==b等)
    • 取地址表达式等(&a)

1.2.2 将亡值

  • 将亡值是指C++11新增的和右值引用相关的表达式,通常指将要被移动的对象、T&&函数的返回值、std::move函数的返回值、转换为T&&类型转换函数的返回值。将亡值可以理解为即将要销毁的值,通过“盗取”其它变量内存空间的方式获取的值,在确保其它变量不再被使用或即将被销毁时,可以避免内存空间的释放和分配,延长变量值的生命周期,常用来完成移动构造或者移动赋值的特殊任务。
  1. 1 class A {
  2. 2 xxx;
  3. 3 };
  4. 4 A a;
  5. 5 auto c = std::move(a); // std::move(a)是将亡值
  6. 6 auto d = static_cast<A&&>(a); // static_cast<A&&>(a)是将亡值

3、左(右)值引用

左值引用就是对左值进行引用的类型,右值引用就是对右值进行引用的类型。都是别名,必须立即初始化。

  1. type &name = exp; // 左值引用
  2. type &&name = exp; // 右值引用

std::move函数强制把左值转换为右值。

  1. int a = 4;
  2. int &&b = a; // error, a是左值
  3. int &&c = std::move(a); // ok

4

2022-12-01 17:50:45    37    0    0

问题

反射,即Reflection,是很多高级编程语言的一种十分强大的特性,比如Java,可以于运行时加载、探知、使用编译期间完全未知的classes。而C++是天然不支持反射的,但是可以通过一些特殊手段实现类似反射的效果,本文对使用字符串创建对象,稍作探讨。

目标

我们要实现的目标是要通过字符串创建对象,即下面的代码:

  1. ClassT* obj = FactoryCreate("ClassT");

但是我们要知道,这并不是完全意义上的反射,因为不能取到对象的属性和值,所以只是伪反射。

实现

  • 基本思路就是,声明要继承的基类BaseClass,BaseClass就是给用户继承使用类,并且其可以声明为任意类型,并通过宏定义REGISTER进行工厂模式注册构造函数。
  • 工厂Factory中通过map关联字符串和构造函数。最后,我们就可以通过类名字符串,在map中找到相应的构造函数,从而获取到(或者构建)字符串对应的用户自定义类的对象。
  1. //
  2. // Created by libo on 2022/11/30.
  3. //
  4. #include <map>
  5. #include <string>
  6. #include <iostream>
  7. #define REGISTER(className) \
  8. className* objectCreator##className(){ \
  9. return new (className); \
  10. } \
  11. RegisterAction g_creatorRegister##className( \
  12. #className, (constrFuncPtr)objectCreator##c
2022-11-02 15:04:45    106    0    0

1、CMake基础

1.1、问题引入

  • CMake工具,只需要开发者提供头文件路径、库路径、编译参数等基本参数,就能快速生成Makefilevcproj文件等,可以做到再改动很小的情况下,满足跨平台项目的快速构建要求。由于CMake的简洁易用特性,我们通常会基于CMake构建工程,并引入第三方库进行开发工作。本文主要记录和学习CMake是如何引入第三方库的。

1.2、使用的CMake简单流程

  • 编写cmake配置文件CMakeLists.txt
    通常CMakeLists.txt放在项目顶层目录,根据需要也可在子目录放置。
  • CMakeLists.txt文件所在目录创建一个build文件夹,然后cd进入目录。
    不建目录理论上是可行的,但是生成的中间文件不易清理,另外build目录名词也是可以自定义的。
  • 执行cmake .. 生成makefile
  • 执行makemake install进行编译和安装。
    • 注意,进行make install需要CMakeLists.txt中定义了install相关规则、路径、文件等才行。
    • windows下,如果使用mingw的话编译工具为mingw32-make.exeinstall安装则为mingw32-make.exe install,如果使用msvc的话编译工具为MSBuild.exe,命令MSBuild.exe XXX.vcxproj)

1.3、CMake的部分常用命令

  • 构建准备(描述性命令)
    • 指定使用该CMakeList.txt文件需要的cmake最低版本,例如:
      cmake_minimum_required(VERSION 3.5)
    • 指定项目信息, 如项目名字,项目使用的语言等,例如:
      • project(calculator)project(MultipleObjectTracking LANGUAGES CXX CUDA)
      • project会影响PROJECT_SOURCE_DIR(第一个project所在的CMakelist.txt所在的文件的目录)的值。
    • 设置属性,比如:
      • 通用的属性可以放在单独的文件中如ToolChain.cmake,然后可以用includ
2022-09-15 16:40:12    29    0    0

1、雷达成像技术

  • 成像类型
    • 一维:距离成像
    • 二维:一维方位、一维距离或者二维方位
    • 三维成像:二维方位加距离
  • 成像频段
    • 太赫兹频段 其横跨电子学到光学的电磁波频段,因而其成像方法也涵括了雷达和光学成像的内容
      • 高频段基于光学方法,需要大口径的成像元件,阻碍了便携性
      • 低频端基于微波方式、以SAR为主
    • 光学频段
    • 微波频段
  • 成像区域
    • 根据雷达和目标之间的距离区分
      • 远场 辐射源与辐射电场测量处的距离很远,可以考虑平面波前
        • r>4D2/lamda
      • 近场
        • 此时辐射源与辐射电场测量处的距离很远,要考虑球面波前
        • 目标中心点与边缘处的回波相位差大于pi/8
        • 目标中心点与边缘处的回波经脉压后不在同一距离门
        • 近场成像处理中,距离公式不能够进行近似处理
    • 电磁散射理论区分
      • 瑞利区(目标尺寸远远小于雷达波长)
      • 谐振区(目标尺寸于雷达波长处于一个数量级)
      • 光学区(目标尺寸远远大于雷达波长)
    • 根据辐射测量点与天线之间的距离(天线辐射的电磁场可分为三个区域)
      • 感应近场区
        • 离天线最近 不向外辐射能量
          • 射频识别(RFID)
          • 近场通信(NFC)
      • 辐射近场区(菲涅尔区)
        • 该区间属于典型辐射区,电磁场较强
          • 近场目标的远场RCS测量
          • 自动目标识别
          • 近场SAR成像
      • 远场区(夫琅禾费区)
        • 电磁场强较弱,属于弱场
        • 大多数通信设备
        • SAR
  • 成像体制
    • 合成孔径雷达(SAR)
    • 逆合成孔径雷达(ISAR)
    • 圆周合成孔径雷达(CSAR)
    • 干涉合成孔径雷达(InSAR)
    • 层析合成孔径雷达(TomoSAR)
    • 毫米波全息成像
    • 编码孔径成像(CAI)
    • 阵列成像(实孔径)
      • 平面扫
      • 柱面扫
  • 雷达体制
    • 单发单收(SISO)
    • 单发多收(SIMO)
    • 多发多收(MIMO)
  • 成像算法
    • 黄金标准
      • 后向投影算法(BP)
        • 基本方法:将回波数据在时域相干叠加,算法简单明了,成像质量高,适用范围广,但是计算复杂度高,时间慢。
    • 经典SAR算法(适用于许多实孔径阵列成像平面扫方式)
      • 距离-多普勒算法(RD)
        • 算法简单
2022-09-08 21:27:38    121    0    0

1、基本安装

  • pcl安装参考:Windows下配置安装PCL开发环境
  • 安装CLion和CMake,其中CMake version大于2.8.3,PCL中用到了高版本的一些宏定义,低版本不兼容。

  • 首先下载PCL-1.12.1-AllInOne-msvc2019-win64.exe 和 pcl-1.12.1-pdb-msvc2019-win64.zip,(参考2.7出现的bug,这里建议可以不要使用该版本,否则需要打开AVX开关)

    • 其中,All in one安装包,PCL提供了配置为Visual Studio的32位和64位下的该安装包,该包包含类PCL中所使用全部第三方编译包,除了QT编译包。
    • 而All in one包对应的PDB文件包,该包用于后期单步调试时使用。
  • 下载完成后,首先在D:\PCL 1.12.0下安装all in one包,并选择添加环境变量。
    title
  • 完成安装以后需要去:D:\PCL 1.12.0\3rdParty\OpenNI2 查看一下OpenNI有没有安装到这个文件夹。因为默认安装的路径是C盘,如果发现文件夹里只有一个NI的安装包的话,就打开安装程序:点击Remove,重新安装并选择路径为:D:\PCL 1.12.0\3rdParty\OpenNI2
  • 然后,将下载的PDB文件,解压到:D:\PCL 1.12.0\bin 文件夹下。
    title
  • 最后,添加如下的环境变量:
  1. %PCL_ROOT%\3rdParty\FLANN\bin
  2. %PCL_ROOT%\3rdParty\VTK\bin
  3. %OPENNI2_REDIST64%
  4. %OPENNI2_LIB64%
  5. %OPENNI2_INCLUDE64%
  • 后续我们打算在CLion+msvc进行开发,CMakeLists.txt如下:
  1. cmake_minimum_required(VERSION 3.23)
  2. project(pclRegister)
  3. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
  4. set(PCL_ROOT "E:\\PCL 1.12.1") # 不要用中文的引号
  5. find_package(PCL 1.12 REQUIRED)
2022-09-05 15:26:49    73    0    0

由于CLion基于CMake构建项目,需要重新编译OpenCV源码。

建议

网上很多人编译过程会出现很多错误,我这里使用"科学上网",全程很顺利,建议科学上网!

过程

准备工作

  • 蒸汽大脑(jetbrains)教育账号:
    • yangping@stu.scu.edu.cn
    • scu614b.
  • 准备OpenCV源码,官网下载即可。
  • 安装CLion,需要破解或者使用教育邮箱。
  • 安装mingw,下载支持C++11多线程的posix版本,参考文末链接。
    安装完后,设置CLion的工具链。

  • 安装CMake,需要安装cmake.gui

普通版本编译

  • 在OpenCV目录下新建mingw的build目录minGW-build,用来保存make生成的一系列文件
  • 打开cmake.gui图形化操作界面,选择opencv源码目录和新建的minGW-build目录,然后选择tools菜单,点击configure。这过程可能会出问题,所以建议科学上网!
  • configure结束之后,开始generate,生成makefile文件。
  • 如果一切顺利的话,进入到mingw_build目录下(-j4代表使用四个线程加速编译)
  1. mingw32-make -j4
  • 结束后,运行:
  1. mingw32-make install
  • 最后,将{opencv_homedir}/opencv/MinGW-build/install/x64/mingw/bin加入环境变量中的path中。
  • 测试程序:
    • main.cpp
  1. #include <iostream>
  2. #include <opencv2/core/core.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. using namespace std;
  5. using namespace cv;
  6. int main() {
  7. cv::Mat img = imread("C:\\Users\\lenovo\\Pictures\\Saved Pictures\\20170329112146_5CR4n.jpeg");
  8. if (img.empty()) {