我的学记|刘航宇的博客 - 软硬件算法
type: channel
link: https://ee.ac.cn/index.php/category/%E8%BD%AF%E7%A1%AC%E4%BB%B6%E7%AE%97%E6%B3%95/
items: 利用图像处理技术mfc设计细胞识别程序-C++
items: 通讯等不确定性条件下设计无人机之间的安全距离
items: 华为C++算法-识别有效的IP地址和掩码并进行分类统计
items: 算法-反转链表C&Python实现
items: FPGA&Matlab联合开发之滤波器模块（带通滤波器为例）
items: 机器学习代码实现:线性回归与岭回归
items: 联发科2024年数字IC设计验证实习生考题解析
items: 【硬件算法进阶】Verilog实现802.3 CRC-32校验运算电路
items: 【硬件算法】Verilog之FPGA实现信号移相法

利用图像处理技术mfc设计细胞识别程序-C++
type: item
date: 2026-07-24T10:44:00+08:00
description: {mtitle title="目录"/}一、图像处理设计目标1.1 课题与技术指标1.2 任务点二、设计思路三、创建工程及算法分析3.1 预备工作及工程创建3.2 打开 BMP 图片与显示 HSI 值代码分析主要代码3.3 Mark - 细胞标记代码分析主要代码3.4 OnTwoValue() - 二值化代码分析状态标记说明主要代码3.5 OnFillHoles() - 填洞代码分析主要代码3.6 shrink() - 收缩代码分析主要代码3.7 findcenter() - 中心点获取代码分析合并中心点去除多余圆或者错误圆主要代码3.8 count() - 统计代码分析3.9 OnCellprgAll() - 按序执行全部四、错误情况及分析4.1 未声明全局变量信息头4.2 错把指针当作 int 型4.3 软件菜单栏突然丢失4.4 矩形框在鼠标未按下就出现了五、总结参考文献一、图像处理设计目标1.1 课题与技术指标课题： 利用图像处理技术设计细胞识别程序。设计指标：实验 VS2019 MFC 开发平台待识别图像为 24bit 的真彩色细胞图像进行处理要求识别出细胞，并且保证准确度情况下，统计出细胞的个数和大小1.2 任务点完成图像标注：添加 cdib.h、cdib.cpp、添加函数、添加消息响应函数、添加菜单、打开图像完成细胞的判别：持续判断 Maybe 点邻域有无 Mark 点、Sobel 计算边缘、删除孤立边缘、生成黑白图像细胞收缩：利用 stack、vector 获取孔洞坐标、填充孔洞、Edge 处置 0、4 方向、8 方向交替生成边缘细胞中心点信息获取：递归算法、判别局部是否全是边缘、储存全部中心位置错误信息的删除：计算中心点均值、半径、去除半径过小的点、包含圆的剔除、相交过大圆的剔除、信息统计与显示二、设计思路图像处理之细胞识别的主要工作就是识别细胞数目以及选择出指定大小细胞。设计思路如下图所示。同时我们要去除不符合要求的中心点，来确定最终的细胞数目，去除太小和太大的细胞1，并结合实际来修改各种参数，设计合理。图1 系统设计思路（流程图：打开图像 → HSI 转换 → 细胞标记 → 二值化 → 填洞 → 收缩 → 中心点获取 → 错误删除 → 统计输出）三、创建工程及算法分析3.1 预备工作及工程创建（1）VS2019 安装 MFC 与 C++ 开发环境（2）创建 MFC 工程，配置 MFC 应用程序向导图2 创建工程 / 图3 MFC 配置3.2 打开 BMP 图片与显示 HSI 值代码分析（1）在 OnDraw 函数实现显示图片；在 messages 中添加 display() 实现打开一幅图像的功能。在 LoadBmp() 函数中利用 fopen 实现自动打开图片，利用 fread 读取图片信息。（2）通过：查看 → 建立类向导 → 添加 OnMouseMove() 函数，添加代码实现获取所要信息；实现鼠标移动显示 HSI。（3）通过函数 RgbtoHsi 实现 RGB 向 HSI 的转化。RGB → HSI 转换原理：RGB 向 HSI 模型的转换是由一个基于笛卡尔直角坐标系的单位立方体向基于圆柱极坐标的双锥体的转换。基本要求是将 RGB 中的亮度因素分离，将色度分解为色调和饱和度，并用角向量表示色调2。如果直接对 R、G、B 处理，其处理过程中很可能会引起三个量不同程度的变化，这样就会产生色差问题，甚至带来颜色上的失真。HSI 模型的出现，使得在保持色彩无失真的情况下实现图像处理成为可能。图4 HSI 显示效果主要代码// HSI 主要代码示意 void RgbtoHsi(RGB* rgb, HSI* hsi) { // 将 RGB 转换为 HSI 色彩空间 // H: 色调, S: 饱和度, I: 亮度 // 分离亮度因素，保持色彩无失真 }图5 HSI 主要代码3.3 Mark - 细胞标记代码分析确定 Mark 与 mbMark 是通过半径来的，通过计算图像上的某个像素点与细胞内部像素点的欧几里得距离与归一化门限值分别为 0.09 和 0.15 比较：r < 0.09 → Mark（红色，细胞内部）0.09 < r < 0.15 → mbMark（蓝色，可能边界）OnMouseMove 函数里调用 RgbtoHsi(&rgb, &Hsi) 函数，可以在屏幕上显示鼠标所指点的坐标以及 RGB、HSI 和灰度值，通过 HSI 的可以选取合适的阈值来找到细胞以及边界3。边缘提取的方法：先滤波，去除噪声的影响，防止细胞内的噪声的影响之后用 Sobel 算子 求出边界之后画一个 5×5 的矩形，如果没有遇到边界，是噪声，去除边界点是绿色。细胞边界分别用红色、暗红、蓝色和绿色标记出来主要代码// Mark 主要…

通讯等不确定性条件下设计无人机之间的安全距离
type: item
date: 2024-07-16T15:14:41+08:00
description: 引用文章：简介1. 研究问题2. 分离原理介绍3. 安全半径设计4. 仿真及实验验证引用文章：Q. Quan, R. Fu and K. -Y. Cai, "How Far Two UAVs Should Be subject to Communication Uncertainties," in IEEE Transactions on Intelligent Transportation Systems, doi: 10.1109/TITS.2022.3213555.简介近年来，无人机技术的快速发展使得低空空域中无人机的数量爆炸增长。碰撞避免作为无人机应用的关键技术，近年来人们已经进行了大量研究，设计出各种方法使得无人机在飞行过程中与障碍物保持一定安全距离（本文将该距离称为无人机的 安全半径）。然而， 在碰撞避免相关研究中，不确定性往往是难以处理的问题。针对不确定性，主流的方法包括对不确定性进行预测，以及在闭环控制中给予补偿。然而，以上方法很依赖于预测及补偿的精准设计，设计不当将有可能导致控制器失效。本研究受地面交通中车辆间安全距离启发，基于对通信不确定性和无人机控制器性能的假设，提出了 安全半径设计和控制器设计的原则 （本文称为 分离原理 ）。进一步，安全半径具体通常通过经验预先设计，如果设计得过大或过小将分别影响无人机飞行的高效性及安全性。 如何根据无人机模型及通信不确定性确定其安全半径下界仍然是悬而未决的问题 。利用分离原理，本文研究了 设计阶段（无不确定性）和飞行阶段（受不确定性影响）的无人机安全半径设计 。最后，通过仿真和实验表明了所提方法的有效性。1. 研究问题本研究中，无人机与障碍物的运动模型均建模为多旋翼模型，换句话说，我们考虑的障碍物可以等效为另一架多旋翼飞行器。对于多旋翼飞行器而言，其可以获得自身以及障碍物的实时位置和速度。为简单描述起见，本文建模均为二维，类似的建模及分析方法可以扩展到三维情况。我们首先建立多旋翼的具体控制模型如下。其中多旋翼的位置和速度分别表示为 ，速度控制模型建立为一阶惯性环节，其时间常数 与无人机的机动性能相关，控制输入 为期望速度。在此基础上，本文定义一种新的滤波位置模型如下。多旋翼滤波位置的物理意义是根据多旋翼的当前位置、速度及机动能力，对其运动趋势预测。在此基础上，定义多旋翼的安全区域为以滤波位置为圆心的圆形区域，其半径称为安全半径 。对于障碍物，我们类似定义其滤波位置，以及以障碍物滤波位置为圆心的圆形障碍物区域，半径称为障碍物半径 。进一步，我们针对不确定性做了以下2点假设：（1）无人机和障碍物对自身的三维位置及三维速度估计均存在噪声；（2）无人机在获取障碍物状态信息时，存在通信延迟及丢包。该通信网络模型如下图所示。本研究中，丢包模型进一步建模为均值模型，且假设估计噪声、通信延迟、丢包均值模型误差均存在上界且上界已知。其数学定义如下：进一步，本文对无人机的控制器性能做出如下假设：（1）在无不确定性的理想状态下，无人机的控制器可以使无人机和障碍物之间的 真实距离 始终大于给定安全距离；（2）在存在以上不确定性的实际情况中，无人机的控制器可以使无人机和障碍物之间的 估计距离 始终保持给定安全距离。本研究的具体目标是在不确定性上界已知的条件下计算出无人机安全半径的下界。2. 分离原理介绍无人机在理想状态下设计的控制器中给定的安全半径值 ，在实际含有不确定性的环境中将转化为估计安全半径 ；直观上理解，将含有不确定性的无人机与障碍物之间的估计位置误差代替真实位置误差作为反馈时，控制器将难以维持给定的安全半径。本研究中， 分离原理具体研究的是不确定性在满足什么条件时无人机的控制器设计和安全半径设计过程可分离 ，也就是估计安全半径和安全半径相等， 成立。分离原理具体数学描述如下：分离原理中提出的三个条件包括一个充分必要条件(i)以及两个充分条件(ii)和(iii)。其中，条件(i)为理论推导，在实际中难以得到验证，通常可通过条件(ii)和(iii)进行验证。条件(ii)对无人机速度的限制较宽，该式在障碍物主动躲避无人机的条件下容易达成。反之，条件(iii)对无人机速度的限制较苛刻，要求无人机速度严格大于障碍物速度，适用于在障碍物不主动躲避无人机的情况下。以上两种情况的区别如下图所示。3. 安全半径设计根据上述分离原理的提出，在分离原理满足的前提下，基于无人机的安全半径模型和通信网络模型，可以进一步设计 合适大小的无人机安全半径 。如前文所述，安全半径设计过大会增加环境的冗余度，设计过小则无法保证飞行过程的安全。在本研究中，给出了在理想情况下以及实际情况下安全半径的下界，分别如下：4. 仿真及实验验证仿真及实验验证在仿真中，我们针对单障碍物、多非合作障碍物、多合作障碍物设计了三种场景来验…

华为C++算法-识别有效的IP地址和掩码并进行分类统计
type: item
date: 2023-12-11T22:36:00+08:00
description: 问题注意：输入描述：输出描述：示例需要注意的细节思路具体实现代码问题请解析IP地址和对应的掩码，进行分类识别。要求按照A/B/C/D/E类地址归类，不合法的地址和掩码单独归类。所有的IP地址划分为 A,B,C,D,E五类A类地址从1.0.0.0到126.255.255.255;B类地址从128.0.0.0到191.255.255.255;C类地址从192.0.0.0到223.255.255.255;D类地址从224.0.0.0到239.255.255.255；E类地址从240.0.0.0到255.255.255.255私网IP范围是：从10.0.0.0到10.255.255.255从172.16.0.0到172.31.255.255从192.168.0.0到192.168.255.255子网掩码为二进制下前面是连续的1，然后全是0。（例如：255.255.255.32就是一个非法的掩码）（注意二进制下全是1或者全是0均为非法子网掩码）注意：类似于【0...】和【127...】的IP地址不属于上述输入的任意一类，也不属于不合法ip地址，计数时请忽略私有IP地址和A,B,C,D,E类地址是不冲突的输入描述：多行字符串。每行一个IP地址和掩码，用~隔开。输出描述：统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数，之间以空格隔开。示例{message type="success" content="输入：10.70.44.68~255.254.255.01.0.0.1~255.0.0.0192.168.0.2~255.255.255.019..0.~255.255.255.0输出：1 0 1 0 0 2 1说明：10.70.44.68~255.254.255.0的子网掩码非法，19..0.~255.255.255.0的IP地址非法，所以错误IP地址或错误掩码的计数为2；1.0.0.1~255.0.0.0是无误的A类地址；192.168.0.2~255.255.255.0是无误的C类地址且是私有IP；所以最终的结果为1 0 1 0 0 2 1 "/}示例2{message type="success" content="输入：0.201.56.50~255.255.111.255127.201.56.50~255.255.111.255输出：0 0 0 0 0 0 0说明：类似于【0...】和【127...】的IP地址不属于上述输入的任意一类，也不属于不合法ip地址，计数时请忽略 "/}需要注意的细节类似于【0...】和【127...】的IP地址不属于上述输入的任意一类，也不属于不合法ip地址，计数时可以忽略私有IP地址和A,B,C,D,E类地址是不冲突的，也就是说需要同时+1如果子网掩码是非法的，则不再需要查看IP地址全零【0.0.0.0】或者全一【255.255.255.255】的子网掩码也是非法的思路按行读取输入，根据字符‘~’ 将IP地址与子网掩码分开查看子网掩码是否合法。合法，则继续检查IP地址非法，则相应统计项+1，继续下一行的读入查看IP地址是否合法合法，查看IP地址属于哪一类，是否是私有ip地址；相应统计项+1非法，相应统计项+1具体实现判断IP地址是否合法，如果满足下列条件之一即为非法地址数字段数不为4存在空段，即【192..1.0】这种某个段的数字大于255判断子网掩码是否合法，如果满足下列条件之一即为非法掩码不是一个合格的IP地址在二进制下，不满足前面连续是1，然后全是0在二进制下，全为0或全为1如何判断一个掩码地址是不是满足前面连续是1，然后全是0？将掩码地址转换为32位无符号整型，假设这个数为b。如果此时b为0，则为非法掩码将b按位取反后+1。如果此时b为1，则b原来是二进制全1，非法掩码如果b和b-1做按位与运算后为0，则说明是合法掩码，否则为非法掩码代码注意getline函数可以指定分割字符串的字符// 引入输入输出流、字符串、字符串流和向量等头文件 #include<iostream> #include<string> #include<sstream> #include<vector> // 使用标准命名空间 using namespace std; // 定义一个函数，判断一个字符串是否是合法的IP地址 bool judge_ip(string ip){ // 定义一个整数变量，记录IP地址的段数 int j = 0; // 定义一个字符串流对象，用于分割IP地址 istringstream iss(ip); // 定义一个字符串变量，用于存储IP地址的每一段 string seg; // 使用循环，以'.'为分隔符，获取IP地址的每一段 while(getline(iss,seg,'.…

算法-反转链表C&Python实现
type: item
date: 2023-07-22T15:21:41+08:00
description: 描述基础数据结构知识回顾题解C++篇题解Python篇描述给定一个单链表的头结点pHead(该头节点是有值的，比如在下图，它的val是1)，长度为n，反转该链表后，返回新链表的表头。数据范围： 0≤n≤1000要求：空间复杂度 O(1) ，时间复杂度 O(n) 。如当输入链表{1,2,3}时，经反转后，原链表变为{3,2,1}，所以对应的输出为{3,2,1}。以上转换过程如下图所示：基础数据结构知识回顾空间复杂度 O (1) 表示算法执行所需要的临时空间不随着某个变量 n 的大小而变化，即此算法空间复杂度为一个常量，可表示为 O (1)。例如，下面的代码中，变量 i、j、m 所分配的空间都不随着 n 的变化而变化，因此它的空间复杂度是 O (1)。int i = 1; int j = 2; ++i; j++; int m = i + j;时间复杂度 O (n) 表示算法执行的时间与 n 成正比，即此算法时间复杂度为线性阶，可表示为 O (n)。例如，下面的代码中，for 循环里面的代码会执行 n 遍，因此它消耗的时间是随着 n 的变化而变化的，因此这类代码都可以用 O (n) 来表示它的时间复杂度。for (i=1; i<=n; ++i) { j = i; j++; }题解C++篇可以先用一个vector将单链表的指针都存起来，然后再构造链表。此方法简单易懂，代码好些。// 定义一个Solution类 class Solution { public: // 定义一个函数，接收一个链表的头节点指针，返回一个反转后的链表的头节点指针 ListNode* ReverseList(ListNode* pHead) { // 如果头节点指针为空，直接返回空指针 if (!pHead) return nullptr; // 定义一个vector，用于存储链表中的每个节点指针 vector<ListNode*> v; // 遍历链表，将每个节点指针放入vector中 while (pHead) { v.push_back(pHead); pHead = pHead->next; } // 反转vector，也可以逆向遍历 reverse(v.begin(), v.end()); // 取出vector中的第一个元素，作为反转后的链表的头节点指针 ListNode *head = v[0]; // 定义一个当前节点指针，初始化为头节点指针 ListNode *cur = head; // 从第二个元素开始遍历vector，构造反转后的链表 for (int i=1; i<v.size(); ++i) { // 当前节点的下一个指针指向下一个节点 cur->next = v[i]; // 当前节点后移 cur = cur->next; } // 切记最后一个节点的下一个指针指向nullptr cur->next = nullptr; // 返回反转后的链表的头节点指针 return head; } };初始化：3个指针1）pre指针指向已经反转好的链表的最后一个节点，最开始没有反转，所以指向nullptr2）cur指针指向待反转链表的第一个节点，最开始第一个节点待反转，所以指向head3）nex指针指向待反转链表的第二个节点，目的是保存链表，因为cur改变指向后，后面的链表则失效了，所以需要保存接下来，循环执行以下三个操作1）nex = cur->next, 保存作用2）cur->next = pre 未反转链表的第一个节点的下个指针指向已反转链表的最后一个节点3）pre = cur， cur = nex; 指针后移，操作下一个未反转链表的第一个节点循环条件，当然是cur != nullptr循环结束后，cur当然为nullptr，所以返回pre，即为反转后的头结点这里以1->2->3->4->5 举例：// 定义一个Solution类 class Solution { public: // 定义一个函数，接收一个链表的头节点指针，返回一个反转后的链表的头节点指针 ListNode* ReverseList(ListNode* pHead) { // 定义一个前驱节点指针，初始化为nullptr ListNode *pre = nullptr; // 定义一个当前节点指针，初始化为头节点指针 ListNode *cur = pHead; // 定义一个后继节点指针，初始化为nullptr ListNode *nex = nullptr; // 遍历链表，反转每个节点的指向 while (cur) { // 记录当前节点的下一个节点 nex = cur->next; // 将当前节点的下一个指针指向前驱节点 cur->next = pre; //…

FPGA&Matlab联合开发之滤波器模块（带通滤波器为例）
type: item
date: 2023-05-21T21:56:11+08:00
description: 在通信或者信号处理中，数字滤波器是非常重要的模块，前面有关博文中提到FIR滤波器的一步步Verilog设计，如https://ee.ac.cn/index.php/archives/511.html本文以带通滤波器为例，利用Matlab进行高效开发{mtitle title="目录"/}MATLAB生成低通滤波器设计步骤：Modelsim仿真上述文件MATLAB生成低通滤波器设计步骤：（1）在MATLAB命令窗口中输入“filterDesigner”或“fdatool”出现如下对话框设置FIR滤波器为和需要的阶数滤波器，选择窗函数的类型为海明窗函数，海明窗函数可以得到旁瓣更小的效果，能量更加集中在主瓣中设置带通滤波器的上下截至频率分别为4MHz 和 5MHz（2）量化输入输出，点击工作栏左边的量化选项，即“set quantization parameters”选项，选择定点，设置输入字长为8，其他选择默认，如下图示：（3）根据自己需求，细化一些配置。这里不难探索设置完成后，点击Targets中Generate HDL，选择生成Verilog 代码，设置路径，MATLAB即可生成设计好的滤波器Verilog HDL 代码以及测试文件：（4）根据需求，配置输出.v文件的全局信号、测试文件，点击生成，生成后，Matlab主页面会提示.v生成的文件路径Modelsim仿真上述文件可以看到输入信号在4MHZ~5MHZ备保留，设计无误。需要注意一点，一般Modelsim仿真输出波形都是离散的01信号，这里需要配置一下，在上图被选中的信号中，在左侧右键鼠标。右击,format,analog(automatic);右击,radix,decimal;这两个步骤完成之后，就出现上图模拟信号的效果

机器学习代码实现:线性回归与岭回归
type: item
date: 2023-05-15T23:05:35+08:00
description: 1.线性回归模型线性回归模型是最简单的一种线性模型，模型的形式就是：$y=W^T x+b$我们可以通过对原本的输入向量x扩增一个为1的维度将参数W和b统一成一个参数W，即模型变成了$y=W^T x$这里的W是原本两个参数合并之后的而其损失函数的形式是残差平方损失RSS$L=\frac{1}{2 m} \sum_{i=1}^m\left(W^T x_i-y_i\right)^2=\frac{1}{2 m}\left(W^T X-y\right)^T\left(W^T X-y\right)$我们很容易就可以通过求导得到线性回归模型的关于W的梯度$\nabla_W L=\frac{1}{m} \sum_{i=1}^m\left(W^T x_i-y_i\right) x_i=\frac{1}{m} X^T\left(W^T X-y\right)$这样一来我们就可以通过梯度下降的方式来训练参数W，可以用下面的公式表示$W:=W-\alpha \frac{1}{m} X^T\left(W^T X-y\right)$但实际上线性模型的参数W可以直接求解出，即：$W=\left(X^T X\right)^{-1} X^T y$2.线性回归的编程实现具体代码中的参数的形式可能和上面的公式推导略有区别，我们实现了一个LinearRegression的类，包含fit，predict和loss三个主要的方法，fit方法就是求解线性模型的过程，这里我们直接使用了正规方程来解class LinearRegression: def fit(self, X: np.ndarray, y: np.ndarray) -> float: N, D = X.shape # 将每个样本的特征增加一个维度，用1表示，使得bias和weight可以一起计算 # 这里在输入的样本矩阵X末尾增加一列来给每个样本的特征向量增加一个维度 # 现在X变成了N*(D+1)维的矩阵了 expand_X = np.column_stack((X, np.ones((N, 1)))) self.w = np.matmul(np.matmul(np.linalg.inv(np.matmul(expand_X.T, expand_X)), expand_X.T), y) return self.loss(X, y)predict实际上就是将输入的矩阵X放到模型中进行计算得到对应的结果，loss给出了损失函数的计算方式：def loss(self, X: np.ndarray, y: np.ndarray): """ 线性回归模型使用的是RSS损失函数 :param X:需要预测的特征矩阵X，维度是N*D :param y:标签label :return: """ delta = y - self.predict(X) total_loss = np.sum(delta ** 2) / X.shape[0] return total_loss3.岭回归Ridge Regression与代码实现岭回归实际上就是一种使用了正则项的线性回归模型，也就是在损失函数上加上了正则项来控制参数的规模，即：$L=\frac{1}{2 m} \sum_{i=1}^m\left(W^T x_i-y_i\right)^2+\lambda\|W\|_2=\frac{1}{2 m}\left(W^T X-y\right)^T\left(W^T X-y\right)+\lambda W^T W$因此最终的模型的正规方程就变成了：$W=\left(X^T X+\lambda I\right)^{-1} X^T y$这里的\lambda是待定的正则项参数，可以根据情况选定，岭回归模型训练的具体代码如下class RidgeRegression: def fit(self, X: np.ndarray, y: np.ndarray): N, D = X.shape I = np.identity(D + 1) I[D][D] = 0 expand_X = np.column_stack((X, np.ones((N, 1)))) self.W = np.matmul(np.matmul(np.linalg.inv(np.matmul(expand_X.T, expand_X) + self.reg * I), expand_X.T), y) return self.loss(X, y)4.数据集实验这里使用了随机生成的二位数据点来对线性模型进行测试，测试结果如下：线性模型测试结果岭回归也使用同样的代码进行测试。

联发科2024年数字IC设计验证实习生考题解析
type: item
date: 2023-04-23T15:35:00+08:00
description: {message type="success" content="总体而言难度中等偏上，如有错误欢迎指正，考察感觉更像是考察嵌入式工程师（有STM32、FPGA基础就很轻松）：有数电、模电、python、verilog、C语言、SOC系统等基础知识，可以看到其实很对口电子信息类专业如电子信息、微电子、通信工程、电子科学、集成电路等专业，没有考察模集如果考模集大部分人要G，数集也没考，可能太底层了与工业界需求有偏差，数集在笔试面试中我认为如果考，可能考时序与功耗部分。这里的Round-Robin算法很值得学习。"/}{mtitle title="目录"/}1、（20分）逻辑化简：2、（5分）ASIC flow 中综合工具的作用是什么？综合的时候需要SDC文件进行约束，请列举3条SDC的语法。3、（10分）智力题4、（10分）选择参与过的任一个项目，简述项目内容以及流程，讲述您在项目中承担的任务，挑一项你认为难的地方并阐述解决方案。5、（5分）用python写一个冒泡排序的函数以及测试程序。6、（15分）用Verilog 写一个 Round Robin 仲裁器。模块端口如下：7、（15分）关于DMA寄存器配置，DMA寄存器（地址 0x81050010）表：8、（20分）二阶带通滤波器，利用RC组件搭建，通带范围 1kHz~30kHz ，两个电阻 R 均为10kΩ ，问两个电容容值多少？1、（20分）逻辑化简：(1)列出真值表(2)列出其卡诺图(3)写出Z的最简表达式答：卡诺图：卡诺图画完后勾1就完事了提示：约束项的一般形式为：与或式 = 0 （如果不是此种形式，化为此种形式）；如此题的BC = 0；或者AB +CD = 0；ABC + CD = 0；等等。BC=0（即B=1，且C=1）对应的格子画X。2、（5分）ASIC flow 中综合工具的作用是什么？综合的时候需要SDC文件进行约束，请列举3条SDC的语法。答：ASIC flow 中综合工具的作用是将RTL级的硬件描述语言转换为与特定工艺库相匹配的门级网表，同时进行优化以满足时序、面积和功耗等约束。综合的时候需要SDC文件进行约束，SDC文件是一种基于Tcl的格式，用于指定设计的时序约束34。SDC文件中的常用时序约束语法有：create_clock -name <clock_name> -period <clock_period> [get_ports <clock_port>] 用于创建时钟源并指定时钟周期。 set_input_delay -clock <clock_name> <delay_value> [get_ports <input_port>] 用于指定输入端口相对于时钟源的延迟。 set_output_delay -clock <clock_name> <delay_value> [get_ports <output_port>] 用于指定输出端口相对于时钟源的延迟。 set_clock_uncertainty -setup <setup_value> -hold <hold_value> <clock_name> 用于指定时钟源的不确定性，包括建立时间和保持时间。 set_false_path -from [get_ports <source_port>] -to [get_ports <destination_port>] 用于指定不需要进行时序分析的路径。 set_multicycle_path -setup -from [get_clocks <source_clock>] -to [get_clocks <destination_clock>] <cycle_number> 用于指定多周期路径，即源时钟和目标时钟之间有多个周期的时间差。3、（10分）智力题（1）2 12 1112 3112 132112 ，下一个数？给理由；答：第一个数是2，第二个数是12，表示前一个数有1个2；第三个数是1112，表示前一个数有1个1和1个2；以此类推。所以，下一个数是1113122112，表示前一个数有1个1，1个3，2个1和2个2（2）有一个小偷费劲力气进入到了银行的金库里。在金库里他找到了一百个箱子，每一个箱子里都装满了金币。不过，只有一个箱子里装的是真的金币，剩下的99个箱子里都是假的。真假金币的外形和质感完全一样，任何人都无法通过肉眼分辨出来。它们只有一个区别：真金币每一个重量为101克，而假金币的重量是100克。在金库里有一个电子秤，它可以准确地测量出任何物品的重量，精确到克。但很不幸的是，这个电子秤和银行的报警系统相连接，只要被使用一次就会立刻失效。请问，小偷怎么做才能只使用一次电子秤就找到装着真金币的箱子呢?答：小偷可以这样做：从第一个箱子里拿出1…

【硬件算法进阶】Verilog实现802.3 CRC-32校验运算电路
type: item
date: 2023-04-12T17:31:00+08:00
description: 循环冗余校验（Cyclic Redundancy Check，CRC）是通信中常用的差错检测编码方式，其基本工作原理是根据输入的信息位（信息码元），按照给定的生成多项式产生校验位（校验码元），并一起传送到接收端。在接收端，接收电路按照相同的规则对接收数据进行计算并生成本地的校验位，然后与收到的校验位进行对比，如果二者不同，则说明传输过程中发生了错误，否则说明传输是正确的。带有CRC校验结果的数据帧结构如表1-2所示。CRC检验位生成与检测工作包括以下基本步骤。图1-6是一个并行CRC-32校验运算电路。图中的d［7：0］是输入的用户数据，它是按照字节的方式输入的。load_ini是在对一个新的数据包开始校验计算之前对电路进行初始化的控制信号，经过初始化后，电路内部32比特寄存器的值改变为全1。calc是电路运算指示信号，在整个数据帧输入和CRC校验结果输出的过程中其都应该保持有效（高电平有效）。d_valid为1时表示当前输入的是需要进行校验运算的有效数据。crc［7：0］是电路输出的CRC校验运算结果，它是按照字节方式，在有效数据输入完成后开始输出的，一共有4个有效字节。crc_reg［31：0］是内部寄存器的值，具体使用时不需要该输出。并行计算的思想，输入数据S要并行输入到G(x)系数为1的支路中，输入数据从输入端按高到低逐bit输入，就可以实现。假如被除数是2位的数据S[1:0]=01，多项式是10011，x4 +x+1。在CRC校验里面，习惯省略最高位的1，多项式用0011表示。那么S除以0011的模二运算数字电路结构为：其中d1~ d4是寄存器输入；q1~q4是寄存器输出。寄存器需要赋初值，一般赋全1或全0。d1=S[1]^q4;d2= S[1]^ q1^q4;d3=q2;d4=q3。经过一次移位后：q1=d1= S[1]^q4;q2= d2= S[1]^ q1^q4;q3= d3=q2;q4= d4=q3。此时有：d1=S[0]^q3;d2= S[0]^ S[1]^ q4^q3;d3= S[1]^ q1^q4;d4= q2。令c[3:0]={q4,q3,q2,q1}，d[3:0]={d4,d3,d2,d1}，那么d就是最终的运算结果表达式，如下d[3]=c[1];d[2]= S[1]^ c[0]^c[3];d[1]= S[0]^ S[1]^ c[3]^ c[2];d[0]= S[0]^ c[2]。令c的初值为0，则01对0011的模二除法的余数为0011。再比如多项式为x5 +x3 +x+1，简记式为01011，其数字电路结构为：输入数据S要全部输入完，寄存器得到的结果才是最后的结果。同理可推导出其他多项式和输入数据的情况。对于循环检验，这里举个例子，如果数据是10bit*100个包，则每次输入10bit得到校验码后，该检验码为下次数据计算时寄存器D的初值，如此反复计算得到最后的检验码添加到整个数据后面即可，而不需要每个数据包后面都添加检验码。下面是以太网循环冗余校验电路的设计代码：module crc32_8023( clk, reset, d, load_init, calc, d_valid, crc_reg, crc ); input clk; input reset; input [7:0] d; input load_init; input calc; input d_valid; output reg [31:0] crc_reg; output reg [7:0] crc; wire [2:0] ctl; wire [31:0] next_crc; wire [31:0] i; assign i = crc_reg; assign ctl = {load_init,calc,d_valid}; always @(posedge clk or posedge reset) begin if(reset) crc_reg <= 32'hffffffff; else begin case (ctl) //{load_init,calc,d_vaild} 3'b000,3'b010: begin crc_reg <= crc_reg; crc <= crc;end 3'b001: begin crc_reg <= {crc_reg[23:0],8'hff}; crc <= ~{crc_reg[16],crc_reg[17],crc_reg[18],crc_reg[19],crc_reg[20],crc_reg[21],crc_reg[22],crc_reg[23]}; //crc <= ~ crc_reg[16:23]; end 3'b011: begin crc_reg <= next_crc[31:0]…

【硬件算法】Verilog之FPGA实现信号移相法
type: item
date: 2023-04-06T16:37:47+08:00
description: 实现信号移相可以用FPGA控制信号0-360度连续可调，对于高频信号（1GHZ以上）超出了FPGA工作频率还有一种办法是FPGA-》DA-》射频前端-》移相器-》阻抗匹配-》天线。本案例直接采用FPGA对数字中频信号处理（kHZ、MHZ）本质是边沿检测与分频现象：代码：/* Function : Phase Shift Interface : clk_fre---unit(MHZ) din_fre---unit(KHz) phase_angle---unit(0-360 Angle) Date: 2023/04/05 Description: Phase shift is carried out on the input square wave. The phase Angle unit is Angle (0-360), or the input can be greater than 360. The system clock unit is MHz and the input signal clock is KHz. */ module PhaseShift( input clk, //clk input rst_n, //rest input [7:0] clk_fre, //system clock frequency,MHZ input [15:0] din_fre, //input signal clock frequency,KHZ input [8:0] phase_angle, //phase shift angle input din, //input signal output reg dout //output signal ); reg [31:0] posedge_counter; reg [31:0] negedge_counter; reg [31:0] delay_counter; reg in_posedge_flg; reg in_negedge_flg; reg out_posedge_flg; reg out_negedge_flg; reg old_din; reg init_data=1'b1; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin posedge_counter <= 1'b0; negedge_counter <= 1'b0; in_posedge_flg <= 1'b0; in_negedge_flg <= 1'b0; out_posedge_flg <= 1'b0; out_negedge_flg <= 1'b0; end else begin if(~old_din & din) in_posedge_flg = 1'b1; if(old_din & ~din) in_negedge_flg = 1'b1; old_din <= din; if(init_data) begin delay_counter <= ((1000000000)/din_fre*clk_fre)/360*(phase_angle%360)/1000000; dout <= din ; init_data <= 1'b0; end if(in_posedge_flg && posedge_counter <= delay_counter) begin posedge_counter <= posedge_counter + 1'b1 ; out_posedge_flg <= 1'b0; end else begin posedge_counter <= 1'b0 ; in_posedge_flg <= 1'b0 ; if(~out_posedge_flg) begin dout <= 1'b1 ; out_posedge_flg <= 1'b1 ; end end if (in_negedge_flg && negedge_counter <= delay_counter) begin negedge_counter <= negedge_counter + 1'b1 ; out_negedge_flg <= 1'b0 ; end else begin negedge_counter <= 1'b0 ; in_negedge_flg <= 1'b0 ; if(~out_negedge_flg) begin dout <= 1'b0 ; out_negedge_flg <= 1'b1; end end end end endmodule测试代码：`timescale 100ps/10ps // module te…