一篇论文讲透Cache优化

Linux阅码场 2023-09-13 08:01

本文转自知乎,本篇主要分享访存的基本原理、面临的主要问题和解法等相关内容。


原文链接:https://zhuanlan.zhihu.com/p/608663298














《What Every Programmer Should Know About Memory》是Ulrich Drepper大佬的一篇神作,洋洋洒洒100多页,基本上涵盖了当时(2007年)关于访存原理和优化的所有问题。即使今天的CPU又有了进一步的发展,但是依然没有跳出这篇文章的探讨范围。只要是讨论访存优化的文章,基本上都会引用这篇论文。


这篇文章也是常读常新的,不同出发点和不同阶段的同学看这篇文章都会有自己的收获。刚入职的时候读了一遍,初窥门径,最近团队的论文分享又读了一遍,有了进一步的理解,这里简单梳理了一下这篇文章自己感兴趣的知识点,初步解答了访存的基本原理,访存面临的主要问题和解法,希望对大家有所帮助。更重要的是,希望能激起大家阅读这篇论文的兴趣。


一 原理


1.1 Cache架构


图1


图2


●浅灰色代表一个Processor,代表一个CPU的物理封装,通过总线和内存相连。


●深灰色代表一个物理Core:


每个Core中有两个Hyper-Thread,常见于Intel的CPU,每个H-Thread对上抽象出一个Core,但并没有物理上的拓展,硬件级别进行时间片并发。优势在于,当一个H-Thread执行内存Stall的指令时,可以切换成另一个H-Thread,并不阻塞。


每个Core有一个L1d和一个L1i。两个H-Thread共享通过一个L1指令和数据Cache。


●L2和L3被多个Core共享。


真实场景:


图3


1个物理CPU,里面有4个core,每个core有两个H-Thread。对上层一共暴露142=8个CPU。


图4


图5


L1的Data和Instruction Cache被同一个Core的两个H-Thread共用。


图6


图7


L2和L3都是Unified类型,可以同时存指令和数据。L3被同一个CPU封装里的所有Core共享,和论文所述一致。但是L2有点不一样,只被同一个Core的两个H-Thread共享,不跨Core共享。


1.2 Cache速度差距


图8


图9


1.3 Cache实现细节


1.3.1 Cache的Key


图10


●T和S一起,唯一标识一个CacheLine,将Cache的组织想象成一个二维数组,通过两个角标T和S定位。


●Offset标识CacheLine里的具体数据位置。一个CacheLine通常是64Byte,所以需要6bit的Offset来定位里面的每个Byte。


1.3.2 Associative Cache


●全路组相连:最朴素的思想,没有Set位,Cache用一维数组的方式组织。查询时直接通过Tag拿到数据。但是当Cache较大时,需要大量的Comp原件,成本高。


图10


●直接组相连。一个Set里面只有一个CacheLine,给定Set值可以唯一选择(MUX)出一个Tag。


图11


●多路组相连。一个Set里面有多个CacheLine,给定Set值可以选择出多个Tag,再通过Tag,拿到数据。


图12


下图是各种组相连的性能数据:


●Cache越大CacheMiss越小


●组数的提升有利于CacheMiss的减少


图13


1.4 Cache实验


1.4.1 实验设计


图14


在内存中开辟一块连续的内存初始化成结构体数组,每个结构体如上图所示。有两个变化点:


●指针n(如下图所示):


依次指向下一个item,顺序访问。


随机指向一个item,随机访问。


●填充数据pad:用于增加减少两个item的内存距离。


图15


1.4.2 实验结果与分析


NPAD=0顺序读


图16


上图是NPAD=0的顺序访问,实际上就是顺序遍历一个数组:


●总体耗时曲线都比较低。最大也就9个Cycle,这是因为顺序访问会触发CPU硬件预取,减少了CacheMiss。


●有3个较为明显的台阶。分别对应L1,L2和Memory。不是有预取么?为啥还有有差异?这是因为访问数据时还没有完全预取上来,会有一定的Memory Stall,但这个Stall时间远远小于Cache Miss的时间。


不同NPAD的顺序读


图17


NPAD的增加,意味着顺序访问的步长增加:


●NPAD=0就是前面的图3.10,在这张图里基本上是一条直线。


●在L1 Cache内,NPAD的差异基本对性能没有影响,不涉及任何的预取。


●在L2Cache内,NPAD=0除外的3条线基本在一起,并高于NPAD=0的用时。这和CacheLine相关,CacheLine的Cache的基本单位,通常是64Byte:


当NPAD=0时,sizeof(struct_l)=8Byte,一个CacheLine可以装8个Struct元素。一次预取可以支持8个元素的访问。


当NPAD=7时,sizeof(struct_l)=64Byte,一个CacheLine只能装1个Struct元素。一次预取只能支持1个元素的访问。


当NPAD>7时类似。


一方面,因为每次预取通常只是减少MemoryStall,无法完全消除,平均每次访问所需要的预取次数越多,耗时越多。另一方面,更多的预取也可能占用更多的内存带宽,降低速率。


●超出L2后需要访问内存,4条线的差异很大,主要有三个原因:


Prefetch无法完全消除Memory Stall。被访问的数据虽然被预取,但是在访问时还没有完全加载到Cache中。这个原因可以解释NPAD>=7的3条线高于NPAD=0,但是无法解释NPAD7,15,31的差异。


PageBoundaries的影响。一个物理页通常是4KB,在物理页边界时无法预取,因为PageFault需要操作系统来调度,CPU做不了。当NPAD越大,达到PageBoundaries所需要的元素个数越少,每次PageBoundaries开销均摊下来也就越大。


TLB表Miss。假设有N个TLB表entry,平均访问了N*4K大小后,会触发一次TLB表Miss。如果NPAD越大,达到TLBMiss所需要的元素个数越少,每次TLB表Miss开销均摊下来也就越大。


触发TLB表Miss的场景


图18


●On Cache Line表示一个数组元素的大小为64Byte,也就是一个CacheLine大小,也是图3.11中的NPAD=7。


●On Page表示一个数组元素大小为4K,也就是一个物理页大小,每次指针跳跃会跨越一个Page。


●计算Working Set Size的逻辑不太一样:


OnCacheLine的逻辑是计算真实消耗的内存,一个数组元素消耗的真实内存是64B,WorkingSetSize也是64B。


OnPage的逻辑是指计算一个Page个中的CacheLine大小。一个元素占用了一个Page的大小(4K),但是只算一个CacheLine的大小(64B)。


也就是说,同样是64B的WorkingSize,OnCacheLine消耗真实内存64B,OnPage消耗真实内存是4K。


为啥做这么奇怪的规定?因为数组元素的大小只是决定顺序访问的Stride,每次访问的只有第一个指针,只访问一个CacheLine。


●可以看到从2^13开始OnPage飙高,这意味着2^12刚好可以装载TLB中,也就是2^12/2^6=64个Page(如前面所述,一个Page在WorkingSize中只算64Byte)可以推算出这台机器的TLB表有64个entry。


●作者特别强调了这个实验进行了内存锁定,不会有Page Fault的影响。


●虽然Stride是一个Page,但是每次只是访问一个CacheLine,为什么Cache没有生效?L2的key是物理地址,需要先经过TLB的转换,所以失效。L1通常是依照逻辑地址,但是载入L1之前需要先载入到L2,所以也受TLB限制。


●超过64*4K=2^18Byte就会触发TLB Miss,TLB Miss的开销是很大的。这也解释了图3.11的NPAD=31为啥在顺序访问主存用时为300多Cycle,这台机器的理论主存访问为240个Cycle。


随机读


图19


●在L1内,随机读和顺序读没有本质差别。


●超出L1后,顺序读和随机读逐渐拉开差距,顺序读基本上是一条水平线,开销很小。


二 实践


2.1 绕开Cache


Cache被无关数据占据称为Cache污染,我们需要尽可能减少Cache污染,提高Cache利用率。


一种经典的Cache污染场景就是写数据。对于写数据,CPU的通常行为是只修改Cache中的数据,标为脏数据,并不急于写入内存。当被写脏的CacheLine被淘汰时(或定时刷内存时)进行真正的落内存。这通常是有效的,比如对临时变量的反复读写,可以一直将这个临时变量装载Cache中,最后只落一次内存。


但也存在另外一种场景,就是写完数据后很长一段时间并不会用到,此时采用“写回”的Cache模式就很浪费,Cache住的脏数据占据了Cache,但实际上并不会被用到。此时可以考虑使用“写穿”的模式,“写穿”不是默认行为,需要调用特定的API,称为Non-temporal接口。


“写穿”需要进行内存访问,所以很慢,但是现代CPU有“write-combining”机制可以解决这个问题。设计实验如下:


图20


分配一个二维数组,每一行的数据在物理内存上连续,每列数据在物理内存上不连续(也就是按行存)。左边是行优先遍历,右边是列优先遍历。


图21


遍历耗时如上图所示,在行优先的场景下,Non-temporal的性能和Normal的性能一样。Non-temporal需要直接写到内存,为什么速度和Normal这种写Cache的一样?


这获益于CPU的“write-combining”机制。CPU有特殊的硬件,会积攒属于同一个CacheLine的写内存数据,直到收到的写入数据不属于这个CacheLine,将之前积攒的数据“批”写入到内存。然后积攒新来的这个CacheLine。


行优先时,写入的数据物理上连续,所以触发“write-combining”,有提速。列优先时,写入的数据物理上不连续,无法“write-combining”,所以写穿会更慢。


有的CPU还提供类“读穿”的功能,配合combining机制,也可以做到既不退性能,也不污染Cache。


此外,这个实验还告诉我们一个道理,尽可能优化算法变成顺序访问,现代CPU有很多优化顺序访问的机制。


2.2 优化L1 Data访问


2.2.1 算法优化


主要是调整算法,提升代码的时间和空间局部性。以矩阵乘法为例:


图22


图23


根据前面的论述,最里面循环的mul1是行优先遍历,访存友好,mul2是列优先遍历,访存不友好,有优化空间。


根据数学变化,调整代码如下:


图24


图25


首先对mul2进行了矩阵转置运算,用一块临时内存tmp存下来。然后使用tmp矩阵和mul1进行运算。mul1和tmp都是行优先遍历。前面做转置的时候,mul2也是行优先遍历。整个算法都是行优先,访存友好。效果很好,提速了76%。


图26


转置算法消耗了额外的内存,我们希望可以不消耗额外内存进行优化,如下:


图27


SM通过宏定义,代表一个CacheLine可以装下的double个数。将一个大矩阵拆分成了长宽为SM的小矩阵进行分治计算。小矩阵中非连续访问的内存距离不超过一个CacheLine的大小。效果略好过转置方案。


图28


2.2.2 数据结构优化


2.2.2.1 结构体内部对齐


图29


对如上结构体,使用pahole分析出具体的内存布局:


图30


●结构体内部按照操作系统位数对齐,32bit系统按照4Byte对齐,64bit系统按照8Byte对齐。


●最右边的注释表示数据的起始位置,和占用的数据大小,比如第一个成员int a,在结构体偏移为0的地方开始,占用了4Byte。


●按照8Byte对齐,所以在int a之后需要填充4个Byte进行对齐,这里产生了1和hole,大小为4Byte。


●一个CacheLine是64Byte,在long int数组结束后使用完了一个CacheLine的大小,下面的成员只能分配到下一个CacheLine中。


一个显然的优化是调整成员b的位置,将其放在成员a后面,这样有两个好处:


●消除了因为对齐产生的空洞。


●整个结构体的大小刚好可以装进一个CacheLine。


除此之外,为了尽可能避免跨CacheLine访问,还需要:


●尽可能把经常用到的结构体元素放在最前面。


●访问结构体时,如果没有特别的业务逻辑需要,尽可能顺序访问结构体里的元素。


2.2.2.2 结构体外部对齐


在满足上述结构体优化后依然是不够的,一个结构体大小即使在一个CacheLine大小内,但如果起始位没有CacheLine对齐,依然会跨CacheLine访问。所以,还需尽可能做到CacheLine对齐。


Malloc分配出来的结构体是8(32bit系统)或者16Byte(64bit系统)对齐的。也就是说Malloc出来的对象在64bit系统中的起始地址一定是16的倍数,用十六进制表示,结尾一定是0,简单实验一下:


printf("address t: %x\n",malloc(sizeof(st)));printf("address c: %x\n",malloc(sizeof(char)));printf("address x: %x\n",malloc(sizeof(int)));printf("address y: %x\n",malloc(sizeof(long)));


输出:


图31


按照16Byte外部对齐可能跨CacheLine,进而导致性能问题。如下,一个结构体的size为32Byte,Malloc可能把它放在地址48上(16Byte对齐)。但这跨CacheLine了,需要加载两个CacheLine才能读取这个数据。


图32


直接使用接口指定对齐字节


图33


void * x2;posix_memalign(&x2,64,sizeof(int));printf("address x2: %x\n",x2);void * x3;posix_memalign(&x3,64,sizeof(long));printf("address x3: %x\n",x3);return 0;


结果如下,地址一定是64的倍数,也就是6个0结尾。


图34


在声明时指定对齐字节


如果是零时变量怎么对齐呢?


图35


struct _st st3 __attribute((aligned(64)));char c3 __attribute((aligned(64)));printf("address st3: %x\n",&st3); printf("address c3: %x\n",&c3); 


图36


在定义处指定对齐字节


上述两种方法都有一个问题,如果是数组的话,只能对齐第一个数据:


struct _st st3[4] __attribute((aligned(64)));printf("address st3: %x\n",&st3[0]); printf("address st3: %x\n",&st3[1]); 


第二个元素没有64byte对齐。


图36


解法是在定义出指定对齐字节。


图37


typedef struct _st{    int a;    long fill[7];    int b;} __attribute((aligned(64))) st;
struct _st st3[4];printf("address st3: %x\n",&st3[0]); printf("address st3: %x\n",&st3[1]);


输出如下,每个元素都是对齐的。


图38


CacheLine对齐不是没有代价的,会产生大量空洞,消耗更多的内存。


未对齐较之于对齐后的性能回退如下图,未对齐的耗时都会增加,在Cache大小内的耗时增加更大。Random在L2中没有对齐的时间增加较少,这是因为随机访问本来的耗时基数较大,对齐与否的影响层度减弱。


图39


2.2.2.3 结构体的拆分


如下图,通常我们会按照业务逻辑封装对象。


图40


根据使用成员的频率进行拆分,有利于提升性能。比如,上面的结构体中的price和paid经常用到,buyer和buyer_id不常用到,拆分成两个独立的结构体,对于price和paid组成的新结构体而言,有效数据密度更大,Cache的效果也越好。但这样的拆分会引入代码的负载度,要根据实际情况进行判断。


2.2.2.4 避免触发conflict misses


现代CPU都采用多路组相连,在没有占满整个Cache的情况下,由于占满了一个set,导致的Cache的淘汰。


图41


●实验的目标是验证conflict miss。L1的Key是逻辑地址,L2是物理地址,我们无法控制物理地址的访问,所以只能验证L1的Conflict miss。构造一个前文多次提到的链表,每个节点的NPAD=15,节点总大小是64Byte,一个CacheLine大小。按照一定的Stride进行多次遍历。


●X坐标表示访问的Stride距离,也是链表节点的距离,比如说距离为2,就是相隔两个链表节点,64*2Byte。Y坐标表示链表的总长度。Z表示耗时,单位是CPU Cycles。


●水平面是3个Cycles,刚好是L1的访存速度。


●此CPU是8路组相连,地址按照4096Byte(64距离* 64B的CacheLine)取模选择Cache Set。所以,距离是64的倍数,每次访问链表节点都会落入同一个Cache Set,当List的长度超过8,CacheSet一定会满,进而把之前的CacheLine挤掉。再一次遍历时,无法命中,还需要再一次加载Cache。


2.3 其他Cache优化


2.3.1 优化L1 Instruction访问


主要有3个优化方向:


●减少代码体积。但这需要和unloop和inline优化做好权衡,因为unloop和inline会增加代码体积。


●应该减少代码空洞。主要是减少代码中的jump指令,顺序执行的预取友好的。


●如有可能,对代码本身进行对齐,避免跨CacheLine。


具体做法有:


●使用-Os编译选项优化CodeSize。会关闭掉影响CodeSize的优化项,比如inline和unloop,具体谁更快,需要测试。


●inline可能加剧代码空洞,如下图,如果代码块B不是经常走到,inline后会增加A和C之间的代码距离。


图42


●分支判断失败的开销很大,一方面是L1i的CacheMiss,另一方面还需要重新decode指令。消除的方式有两种:


两次编译,第一次收集分支统计信息,第二次正式编译利用统计信息选择概率更大的分支。


手动指定预测分支:


//接口long __builtin_expect(long EXP, long C);
//宏定义#define unlikely(expr) __builtin_expect(!!(expr), 0)#define likely(expr) __builtin_expect(!!(expr), 1)
//使用if (likely(a > 1))


●代码对齐。通常有3中对齐场景:


函数对齐


分支对齐


循环对齐


函数和分支对齐直接jump到对齐代码块即可,没有什么开销。但循环的代码对齐不一样,loop代码块通常是紧接着其他的顺序代码后面的,要对齐只有两种办法:


●插入无效指令占位


●显示jump一次


这两种方式都是有开销的,所以,只有当循环次数很大时才有必要循环对齐。


图43


2.3.2 L2 优化


L2Cache(在文中是最后一个Level的Cache)的优化和L1基本一致,但是有两个点比较特殊:


●如果Miss,开销更大。L1Cache不住,还可以L2Cache,性能损失有限。L2Miss就要访问内存了,开销很大。


●L2会被多个Core共享。可以利用的Cache不及预期。在涉及L2敏感算法时,需要用L2Size处于共享的核数。如果是Linux系统,在/sys/devices/system/cpu/cpu*/cache中的shared_cpu_map查看。


2.3.3 TLB优化


避免跨页访问,尽可能将Code和Data聚集在一个Page范围内集中访问。但ASLR(AddressSpaceLayoutRandomization)机制无法避免代码的跨页访问。如果代码加载到固定地址,将很容易受到攻击,所以操作系统加载代码时会进行随机处理。


2.4 预取优化


2.4.1 硬件预取


一个core通常会有8到16个硬件预取原件,会对CacheMiss进行监控,如果miss的CacheLine的Stride是定长,且累积miss次数超过阈值,触发硬件预取。通常预取原件都是部署在L2和更高层级的Cache上,由于L2会被共享,所以预取原件很快就会被消耗完。


前文已经提到过,硬件预取不能跨页。通常硬件预取的Stride不会超过512B,一个物理页是4K,如果Stride超过512B,预取8次就跨页了,不合理。


如果内存带宽被打满。可以考虑关闭掉硬件预取,但是这是CPU级别生效。可以将低优先级线程绑定在的定的CPU上,并关闭其硬件预取功能,减少内存带宽压力。


2.4.2 软件预取


图44


●T0,T1,T2分别将CacheLine加载到L1,L2,L3中,如果加载到L1中,L2和L3也会被加载。使用预取指令时需要考虑WorkSet大小,如果太大,不应该直接使用T0,而是考虑更合适的T1和T2。


●NTA,尽可能避免Cache污染进行预取。也就是前文提到的non-temporal操作。


●随机访问的软件预取效果如下,有一定的提升。


图45


2.4.3 Helper Thread预取


H-Thread会共用L1 Cache,容易造成Cache污染等问题,论文提到了一种解决办法,使用Helper-Thread专门进行prefetch。属于同一个Core的两个H-Thread作为一组,一个用于用于处理业务逻辑,另一个专门用于辅助预取数据。可以使用NUMA库绑定线程到特定的H-Thread上实现。


Helper-Thread方法的效果如下,收益明显,但是也有自己的问题:


●Helper线程和主线程的同步需要额外逻辑和开销。


●Helper线程本来可以用来做其他的计算任务,两种方式需要权衡。


图46


Linux阅码场 专业的Linux技术社区和Linux操作系统学习平台,内容涉及Linux内核,Linux内存管理,Linux进程管理,Linux文件系统和IO,Linux性能调优,Linux设备驱动以及Linux虚拟化和云计算等各方各面.
评论
  • 近日,搭载紫光展锐W517芯片平台的INMO GO2由影目科技正式推出。作为全球首款专为商务场景设计的智能翻译眼镜,INMO GO2 以“快、准、稳”三大核心优势,突破传统翻译产品局限,为全球商务人士带来高效、自然、稳定的跨语言交流体验。 INMO GO2内置的W517芯片,是紫光展锐4G旗舰级智能穿戴平台,采用四核处理器,具有高性能、低功耗的优势,内置超微高集成技术,采用先进工艺,计算能力相比同档位竞品提升4倍,强大的性能提供更加多样化的应用场景。【视频见P盘链接】 依托“
    紫光展锐 2024-12-11 11:50 47浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 66浏览
  • 智能汽车可替换LED前照灯控制运行的原理涉及多个方面,包括自适应前照灯系统(AFS)的工作原理、传感器的应用、步进电机的控制以及模糊控制策略等。当下时代的智能汽车灯光控制系统通过车载网关控制单元集中控制,表现特殊点的有特斯拉,仅通过前车身控制器,整个系统就包括了灯光旋转开关、车灯变光开关、左LED前照灯总成、右LED前照灯总成、转向柱电子控制单元、CAN数据总线接口、组合仪表控制单元、车载网关控制单元等器件。变光开关、转向开关和辅助操作系统一般连为一体,开关之间通过内部线束和转向柱装置连接为多,
    lauguo2013 2024-12-10 15:53 81浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 49浏览
  • 我的一台很多年前人家不要了的九十年代SONY台式组合音响,接手时只有CD功能不行了,因为不需要,也就没修,只使用收音机、磁带机和外接信号功能就够了。最近五年在外地,就断电闲置,没使用了。今年9月回到家里,就一个劲儿地忙着收拾家当,忙了一个多月,太多事啦!修了电气,清理了闲置不用了的电器和电子,就是一个劲儿地扔扔扔!几十年的“工匠式”收留收藏,只能断舍离,拆解不过来的了。一天,忽然感觉室内有股臭味,用鼻子的嗅觉功能朝着臭味重的方向寻找,觉得应该就是这台组合音响?怎么会呢?这无机物的东西不会腐臭吧?
    自做自受 2024-12-10 16:34 136浏览
  • 概述 通过前面的研究学习,已经可以在CycloneVGX器件中成功实现完整的TDC(或者说完整的TDL,即延时线),测试结果也比较满足,解决了超大BIN尺寸以及大量0尺寸BIN的问题,但是还是存在一些之前系列器件还未遇到的问题,这些问题将在本文中进行详细描述介绍。 在五代Cyclone器件内部系统时钟受限的情况下,意味着大量逻辑资源将被浪费在于实现较大长度的TDL上面。是否可以找到方法可以对此前TDL的长度进行优化呢?本文还将探讨这个问题。TDC前段BIN颗粒堵塞问题分析 将延时链在逻辑中实现后
    coyoo 2024-12-10 13:28 101浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 74浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 70浏览
  • 全球知名半导体制造商ROHM Co., Ltd.(以下简称“罗姆”)宣布与Taiwan Semiconductor Manufacturing Company Limited(以下简称“台积公司”)就车载氮化镓功率器件的开发和量产事宜建立战略合作伙伴关系。通过该合作关系,双方将致力于将罗姆的氮化镓器件开发技术与台积公司业界先进的GaN-on-Silicon工艺技术优势结合起来,满足市场对高耐压和高频特性优异的功率元器件日益增长的需求。氮化镓功率器件目前主要被用于AC适配器和服务器电源等消费电子和
    电子资讯报 2024-12-10 17:09 84浏览
  •         在有电流流过的导线周围会感生出磁场,再用霍尔器件检测由电流感生的磁场,即可测出产生这个磁场的电流的量值。由此就可以构成霍尔电流、电压传感器。因为霍尔器件的输出电压与加在它上面的磁感应强度以及流过其中的工作电流的乘积成比例,是一个具有乘法器功能的器件,并且可与各种逻辑电路直接接口,还可以直接驱动各种性质的负载。因为霍尔器件的应用原理简单,信号处理方便,器件本身又具有一系列的du特优点,所以在变频器中也发挥了非常重要的作用。  &nb
    锦正茂科技 2024-12-10 12:57 76浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-10 16:13 105浏览
  • 【萤火工场CEM5826-M11测评】OLED显示雷达数据本文结合之前关于串口打印雷达监测数据的研究,进一步扩展至 OLED 屏幕显示。该项目整体分为两部分: 一、框架显示; 二、数据采集与填充显示。为了减小 MCU 负担,采用 局部刷新 的方案。1. 显示框架所需库函数 Wire.h 、Adafruit_GFX.h 、Adafruit_SSD1306.h . 代码#include #include #include #include "logo_128x64.h"#include "logo_
    无垠的广袤 2024-12-10 14:03 69浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦