作为射频工程师的你,是不是对EVM的计算方法也感点兴趣?

原创 加油射频工程师 2023-11-22 11:39

来看看,你需不需要这门接收机设计课程吧(已更新七次)

如有需要,现在仍然可以报名。


(1)

在EVM是个什么东东喽?,有说过,EVM衡量的是星座图上理想点和实测点偏移量的大小。

虽说,有这样一个公式,但是光看公式,总是觉得云里雾里的。

最近,因为在琢磨用ADS进行系统仿真的事,然后一步一步下来,发现在ADS的AEL文件里,藏着很多宝藏。

昨天说过,在射频层面仿真EVM的时候,在ADS里面发现两种仿真计算的方法。

一种是在dds文件上,以constellation()函数为基础,一个一个写公式,然后出来EVM的计算结果。

另一种,是在dds文件上,直接调用const_evm()函数来计算EVM的值。

我大概过了一下两种方法的流程,大致差不多。

但是,昨天在仿真的时候,发现当我把Symbol_rate从24.3KHz调整到150KHz,并且输入功率设小的时候,两者仿真出来的结果差很多。

没办法,只能仔细地去看const_evm()函数里面的具体细节。

(2)

先把这个程序贴出来。

defun const_evm(vfund_ideal, vfund_dist, u_symbol_rate,     u_sample_delay, u_rotation, u_transient_duration, u_path_delay){
if ( vfund_ideal == NULL || vfund_dist == NULL ) return;
decl symbol_rate = u_symbol_rate == NULL ? 0 : u_symbol_rate; decl transient_duration = u_transient_duration == NULL ? 0 : u_transient_duration; decl tran_time = 0; if ( transient_duration ) // skip integer number of symbols tran_time = ceil(mag(transient_duration)*symbol_rate)/symbol_rate; decl sample_delay = u_sample_delay == NULL ? best_delay_1d(vfund_ideal,symbol_rate,tran_time) : u_sample_delay;
decl rotation = u_rotation == NULL ? 0 : u_rotation; decl Path_Delay_default = delay_path(vfund_ideal,vfund_dist); decl path_delay = u_path_delay == NULL ? Path_Delay_default[0] : u_path_delay; // This is a better default than 0.
vfund_ideal = vfund_ideal*exp(j*rotation); vfund_dist = vfund_dist*exp(j*rotation); decl vfund_ideal_real = real(vfund_ideal); decl vfund_ideal_imag = imag(vfund_ideal); decl vfund_dist_real = real(vfund_dist); decl vfund_dist_imag = imag(vfund_dist); decl time_values = indep(vfund_ideal); decl time_step = time_values[1]-time_values[0]; decl i; decl numPts_i=9; decl min_time_offset = -0.5*time_step; decl time_offset; decl best_evm_rms = 1000; // initialized as an arbitrary large number decl evm_rms_this_trial; decl evm_percent; decl best_mean_phase_delta; decl best_vfund_C_dist; decl best_evm;
// Ideal trajectory decl ideal_trajectory = vs(vfund_ideal_imag, vfund_ideal_real);
// set interpolation points decl start_time = sample_delay; // removed + tran_time; decl stop_time = max(indep(vfund_ideal)); decl incr = NULL; if (symbol_rate) incr = 1/symbol_rate;
// Ideal constellation decl vfund_C_ideal_real = interp(vfund_ideal_real, start_time, stop_time, incr); decl vfund_C_ideal_imag = interp(vfund_ideal_imag, start_time, stop_time, incr); decl vfund_C_ideal = vfund_C_ideal_real+j*vfund_C_ideal_imag; decl vfund_C_ideal_rms = sqrt(mean(mag(vfund_C_ideal)**2)); vfund_C_ideal = vfund_C_ideal/vfund_C_ideal_rms; decl ideal_constellation = vs(imag(vfund_C_ideal), real(vfund_C_ideal)); set_attr(ideal_constellation,"TraceType","Scatter");
for (i=0; i { time_offset = min_time_offset + i*time_step/8; decl vfund_C_dist_real = interp(vfund_dist_real, start_time+path_delay+time_offset, stop_time, incr); // this length may change with i. decl vfund_C_dist_imag = interp(vfund_dist_imag, start_time+path_delay+time_offset, stop_time, incr); // this length may change with i. decl vfund_C_dist = vfund_C_dist_real +j*vfund_C_dist_imag;
decl sn = min([sweep_size(vfund_C_dist_real), sweep_size(vfund_C_ideal_real)]);
// phase compensation decl mean_phase_delta = __phase_delta_calc(vfund_C_ideal[0::sn-1], vfund_C_dist[0::sn-1]); vfund_C_dist = (vfund_C_dist)*exp(-j*mean_phase_delta);
// scaling decl scaling = sqrt(mean(mag(vfund_C_dist[0::sn-1])**2)); // Previously divided this by RMS value of ideal constellation, but this is now 1. vfund_C_dist = vfund_C_dist/scaling;
// EVM decl evm = mag(vfund_C_dist[0::sn-1]-vfund_C_ideal[0::sn-1]);
// EVM_percent evm_rms_this_trial = sqrt(mean(evm**2)); // This could be divided by the RMS value of the ideal constellation, but this is now 1. if (evm_rms_this_trial < best_evm_rms) { best_evm = evm; best_evm_rms = evm_rms_this_trial; best_mean_phase_delta = mean_phase_delta; best_vfund_C_dist = vfund_C_dist*scaling; // undoing the scaling to generate the distorted constellation } evm_percent = 100*best_evm_rms; // has to be calculated inside the loop because sn could change from one iteration to the next. }
// distorted compensated trajectory (phase compensation only) vfund_dist=vfund_dist*exp(-j*best_mean_phase_delta); decl dist_trajectory = vs(imag(vfund_dist),real(vfund_dist));
decl distorted_constellation = vs(imag(best_vfund_C_dist), real(best_vfund_C_dist)); set_attr(distorted_constellation,"TraceType","Scatter");
return list(ideal_constellation, ideal_trajectory, distorted_constellation, dist_trajectory, best_evm, evm_percent);} //fun - const_evm

看上去很长也很难懂,对不对?我也是鼓足很大的勇气,才对着电脑开始研读的。

但是等看完了以后,发现,以后不能自己吓自己。这个程序看上去很长,但是其实只要懂点英文,然后有点数学基础,基本都能看懂。

对于我来说,这上面最大的不懂点,可能就是这条语句。但是现在有AI,分分钟给你解释的清清楚楚。

decl symbol_rate = u_symbol_rate == NULL ? 0 : u_symbol_rate;

比如说,上面这条语句,chatgpt是这样给我解释的。

简单理解,就是把u_symbol_rate的值,赋给symbol_rate。

接着,我们一条条看一下const_evm()中的语句哈!

(3)


if ( vfund_ideal == NULL || vfund_dist == NULL )   return;
decl symbol_rate = u_symbol_rate == NULL ? 0 : u_symbol_rate; decl transient_duration = u_transient_duration == NULL ? 0 : u_transient_duration; decl tran_time = 0; if ( transient_duration ) // skip integer number of symbols tran_time = ceil(mag(transient_duration)*symbol_rate)/symbol_rate; decl sample_delay = u_sample_delay == NULL ? best_delay_1d(vfund_ideal,symbol_rate,tran_time) : u_sample_delay;
decl rotation = u_rotation == NULL ? 0 : u_rotation; decl Path_Delay_default = delay_path(vfund_ideal,vfund_dist); decl path_delay = u_path_delay == NULL ? Path_Delay_default[0] : u_path_delay; // This is a better default than 0.

decl,从ADS的help文件可知,是define a variable的意思。

在dds文件中,使用const_evm的时候,会给参数,如下图所示。

所以,上面的语句,主要就是把用户给的参数传递给函数内部。

注意一下,这里有个delay_path()这个函数。为啥提醒注意呢?前面不是说,发现两种仿真计算下,结果有时候会不一样么?其中一个因素就是这个。
在const_evm中,计算失真信号的星座图的时候,把链路的延时考虑进去的;但是另一种计算过程中,则没有。

(4)
 vfund_ideal = vfund_ideal*exp(j*rotation); vfund_dist = vfund_dist*exp(j*rotation); decl vfund_ideal_real = real(vfund_ideal); decl vfund_ideal_imag = imag(vfund_ideal); decl vfund_dist_real = real(vfund_dist); decl vfund_dist_imag = imag(vfund_dist);

在const_evm()的参数中,第一个参数,是理想的信号;第二个参数,是经过射频链路后的信号,暂且把它称为失真信号。


上面的语句,主要是把理想信号(vfund_ideal)和失真信号(vfund_dist)都旋转一个角度,这个角度也是在const_evm()的参数中定义。然后取出旋转后信号的实部和虚部。


可以看到,这个旋转对理想信号和失真信号是同时有效的。所以,还没搞清楚,这个参数的主要的作用是啥。不过呢,这个参数主要是影响星座图的旋转角度,和EVM的值,倒是没啥关系。


(5)

  decl time_values = indep(vfund_ideal);  decl time_step = time_values[1]-time_values[0];    decl i;  decl numPts_i=9;  decl min_time_offset = -0.5*time_step;  decl time_offset;  decl best_evm_rms = 1000;  // initialized as an arbitrary large number  decl evm_rms_this_trial;  decl evm_percent;  decl best_mean_phase_delta;  decl best_vfund_C_dist;  decl best_evm;

因为仿真结果是基于envelope仿真器的,有Tstep设置。所以上面的第一和第二句,就是从信号中恢复出这个Tstep。

接下来的语句,是定义各种各样的变量。


(6)

    // Ideal trajectory    decl ideal_trajectory = vs(vfund_ideal_imag, vfund_ideal_real);

这个语句厉害了,没看到这个语句的时候,我觉得,把星座图画出来好难啊!等我看到这个语句的时候,一下子无言,就这么一句话!当然,这里还不是星座图,是符号变化的轨迹。不过离星座图就差一行代码!


不过,我个人觉得这里有个小bug。

因为仿真过程中发现,在dds文件上,想把理想信号的星座图和轨迹放在一张图上的话,轨迹变成一个很小的点。

从代码来看,应该是因为计算星座图的时候,归一化了,但是看计算轨迹的时候,则没有。

再说回上面的语句。

看help文件,vs()是这么解释的。

看上去不太直观哈,但是从最终绘制的结果来看,大概就是在二维矩形坐标上,画出dependent随independent变化的曲线。

(7)

 // set interpolation points    decl start_time = sample_delay;                                 // removed + tran_time;    decl stop_time = max(indep(vfund_ideal));    decl incr = NULL;    if (symbol_rate)    incr = 1/symbol_rate;
// Ideal constellation decl vfund_C_ideal_real = interp(vfund_ideal_real, start_time, stop_time, incr); decl vfund_C_ideal_imag = interp(vfund_ideal_imag, start_time, stop_time, incr); decl vfund_C_ideal = vfund_C_ideal_real+j*vfund_C_ideal_imag; decl vfund_C_ideal_rms = sqrt(mean(mag(vfund_C_ideal)**2)); vfund_C_ideal = vfund_C_ideal/vfund_C_ideal_rms; decl ideal_constellation = vs(imag(vfund_C_ideal), real(vfund_C_ideal)); set_attr(ideal_constellation,"TraceType","Scatter");


在help文件中,interp()的解释是这样的。

信号的时间间隔原来是Tstep,这个我在原理图中设置的是1/(4*symbolrate),在程序中,做了个线性插值,使得信号的时间间隔变为1/symbolrate。


然后对理想信号进行归一化,并用vs()画出在二维坐标系上,虚部和实部的关系。并且用set_attr()来设置图形的表现形式,让其以点状的形式显示,从而显示成星座图,而不是轨迹。


(8)

 for (i=0; i// Loop to find minimum EVM  {    time_offset = min_time_offset + i*time_step/8;    decl vfund_C_dist_real = interp(vfund_dist_real, start_time+path_delay+time_offset, stop_time, incr);    // this length may change with i.    decl vfund_C_dist_imag = interp(vfund_dist_imag, start_time+path_delay+time_offset, stop_time, incr);    // this length may change with i.    decl vfund_C_dist = vfund_C_dist_real +j*vfund_C_dist_imag;
decl sn = min([sweep_size(vfund_C_dist_real), sweep_size(vfund_C_ideal_real)]); // phase compensation decl mean_phase_delta = __phase_delta_calc(vfund_C_ideal[0::sn-1], vfund_C_dist[0::sn-1]); vfund_C_dist = (vfund_C_dist)*exp(-j*mean_phase_delta); // scaling decl scaling = sqrt(mean(mag(vfund_C_dist[0::sn-1])**2)); // Previously divided this by RMS value of ideal constellation, but this is now 1. vfund_C_dist = vfund_C_dist/scaling; // EVM decl evm = mag(vfund_C_dist[0::sn-1]-vfund_C_ideal[0::sn-1]);
// EVM_percent evm_rms_this_trial = sqrt(mean(evm**2)); // This could be divided by the RMS value of the ideal constellation, but this is now 1. if (evm_rms_this_trial < best_evm_rms) { best_evm = evm; best_evm_rms = evm_rms_this_trial; best_mean_phase_delta = mean_phase_delta; best_vfund_C_dist = vfund_C_dist*scaling; // undoing the scaling to generate the distorted constellation } evm_percent = 100*best_evm_rms; // has to be calculated inside the loop because sn could change from one iteration to the next. }

这个for语句,是代码里面做了一个循环,以time_step/8为步进,来找出最合适的采样点,使得EVM最小。


 // phase compensation    decl mean_phase_delta = __phase_delta_calc(vfund_C_ideal[0::sn-1], vfund_C_dist[0::sn-1]);    vfund_C_dist =  (vfund_C_dist)*exp(-j*mean_phase_delta);        // scaling    decl scaling = sqrt(mean(mag(vfund_C_dist[0::sn-1])**2));   // Previously divided this by RMS value of ideal constellation, but this is now 1.    vfund_C_dist = vfund_C_dist/scaling;

这四个语句,分别是进行相位补偿和幅度归一化。



// EVM decl evm = mag(vfund_C_dist[0::sn-1]-vfund_C_ideal[0::sn-1]);

这个呢,就是开始计算EVM呢,即理想矢量点和实测矢量点之间的误差的幅值。


(9)

    // distorted compensated trajectory (phase compensation only)    vfund_dist=vfund_dist*exp(-j*best_mean_phase_delta);    decl dist_trajectory = vs(imag(vfund_dist),real(vfund_dist));
decl distorted_constellation = vs(imag(best_vfund_C_dist), real(best_vfund_C_dist)); set_attr(distorted_constellation,"TraceType","Scatter"); return list(ideal_constellation, ideal_trajectory, distorted_constellation, dist_trajectory, best_evm, evm_percent);


最后,就是计算失真信号的星座图和变化轨迹啦!

(10)

终于讲完了!


如果想和我进一步交流的话,欢迎关注个人微信号,注明:公司(如方便的话)+工作性质(如研发,调试,销售等)。



评论 (0)
  • 贞光科技代理品牌紫光国芯的车规级LPDDR4内存正成为智能驾驶舱的核心选择。在汽车电子国产化浪潮中,其产品以宽温域稳定工作能力、优异电磁兼容性和超长使用寿命赢得市场认可。紫光国芯不仅确保供应链安全可控,还提供专业本地技术支持。面向未来,紫光国芯正研发LPDDR5车规级产品,将以更高带宽、更低功耗支持汽车智能化发展。随着智能网联汽车的迅猛发展,智能驾驶舱作为人机交互的核心载体,对处理器和存储器的性能与可靠性提出了更高要求。在汽车电子国产化浪潮中,贞光科技代理品牌紫光国芯的车规级LPDDR4内存凭借
    贞光科技 2025-04-28 16:52 289浏览
  • 你是不是也有在公共场合被偷看手机或笔电的经验呢?科技时代下,不少现代人的各式机密数据都在手机、平板或是笔电等可携式的3C产品上处理,若是经常性地需要在公共场合使用,不管是工作上的机密文件,或是重要的个人信息等,民众都有防窃防盗意识,为了避免他人窥探内容,都会选择使用「防窥保护贴片」,以防止数据外泄。现今市面上「防窥保护贴」、「防窥片」、「屏幕防窥膜」等产品就是这种目的下产物 (以下简称防窥片)!防窥片功能与常见问题解析首先,防窥片最主要的功能就是用来防止他人窥视屏幕上的隐私信息,它是利用百叶窗的
    百佳泰测试实验室 2025-04-30 13:28 407浏览
  • 随着电子元器件的快速发展,导致各种常见的贴片电阻元器件也越来越小,给我们分辨也就变得越来越难,下面就由smt贴片加工厂_安徽英特丽就来告诉大家如何分辨的SMT贴片元器件。先来看看贴片电感和贴片电容的区分:(1)看颜色(黑色)——一般黑色都是贴片电感。贴片电容只有勇于精密设备中的贴片钽电容才是黑色的,其他普通贴片电容基本都不是黑色的。(2)看型号标码——贴片电感以L开头,贴片电容以C开头。从外形是圆形初步判断应为电感,测量两端电阻为零点几欧,则为电感。(3)检测——贴片电感一般阻值小,更没有“充放
    贴片加工小安 2025-04-29 14:59 257浏览
  • 4月22日下午,备受瞩目的飞凌嵌入式「2025嵌入式及边缘AI技术论坛」在深圳深铁皇冠假日酒店盛大举行,此次活动邀请到了200余位嵌入式技术领域的技术专家、企业代表和工程师用户,共享嵌入式及边缘AI技术的盛宴!1、精彩纷呈的展区产品及方案展区是本场活动的第一场重头戏,从硬件产品到软件系统,从企业级应用到高校教学应用,都吸引了现场来宾的驻足观看和交流讨论。全产品矩阵展区展示了飞凌嵌入式丰富的产品线,从嵌入式板卡到工控机,从进口芯片平台到全国产平台,无不体现出飞凌嵌入式在嵌入式主控设备研发设计方面的
    飞凌嵌入式 2025-04-28 14:43 174浏览
  • 文/郭楚妤编辑/cc孙聪颖‍越来越多的企业开始蚕食动力电池市场,行业“去宁王化”态势逐渐明显。随着这种趋势的加强,打开新的市场对于宁德时代而言至关重要。“我们不希望被定义为电池的制造者,而是希望把自己称作新能源产业的开拓者。”4月21日,在宁德时代举行的“超级科技日”发布会上,宁德时代掌门人曾毓群如是说。随着宁德时代核心新品骁遥双核电池的发布,其搭载的“电电增程”技术也走进业界视野。除此之外,经过近3年试水,宁德时代在换电业务上重资加码。曾毓群认为换电是一个重资产、高投入、长周期的产业,涉及的利
    华尔街科技眼 2025-04-28 21:55 182浏览
  • 文/Leon编辑/cc孙聪颖‍2023年,厨电行业在相对平稳的市场环境中迎来温和复苏,看似为行业增长积蓄势能。带着对市场向好的预期,2024 年初,老板电器副董事长兼总经理任富佳为企业定下双位数增长目标。然而现实与预期相悖,过去一年,这家老牌厨电企业不仅未能达成业绩目标,曾提出的“三年再造一个老板电器”愿景,也因市场下行压力面临落空风险。作为“企二代”管理者,任富佳在掌舵企业穿越市场周期的过程中,正面临着前所未有的挑战。4月29日,老板电器(002508.SZ)发布了2024年年度报告及2025
    华尔街科技眼 2025-04-30 12:40 241浏览
  • 浪潮之上:智能时代的觉醒    近日参加了一场课题的答辩,这是医疗人工智能揭榜挂帅的国家项目的地区考场,参与者众多,围绕着医疗健康的主题,八仙过海各显神通,百花齐放。   中国大地正在发生着激动人心的场景:深圳前海深港人工智能算力中心高速运转的液冷服务器,武汉马路上自动驾驶出租车穿行的智慧道路,机器人参与北京的马拉松竞赛。从中央到地方,人工智能相关政策和消息如雨后春笋般不断出台,数字中国的建设图景正在智能浪潮中徐徐展开,战略布局如同围棋
    广州铁金刚 2025-04-30 15:24 235浏览
  • 一、gao效冷却与控温机制‌1、‌冷媒流动设计‌采用低压液氮(或液氦)通过毛细管路导入蒸发器,蒸汽喷射至样品腔实现快速冷却,冷却效率高(室温至80K约20分钟,至4.2K约30分钟)。通过控温仪动态调节蒸发器加热功率,结合温度传感器(如PT100铂电阻或Cernox磁场不敏感传感器),实现±0.01K的高精度温度稳定性。2、‌宽温区覆盖与扩展性‌标准温区为80K-325K,通过降压选件可将下限延伸至65K(液氮模式)或4K(液氦模式)。可选配475K高温模块,满足材料在ji端温度下的性能测试需求
    锦正茂科技 2025-04-30 13:08 306浏览
  • 在智能硬件设备趋向微型化的背景下,语音芯片方案厂商针对小体积设备开发了多款超小型语音芯片方案,其中WTV系列和WT2003H系列凭借其QFN封装设计、高性能与高集成度,成为微型设备语音方案的理想选择。以下从封装特性、功能优势及典型应用场景三个方面进行详细介绍。一、超小体积封装:QFN技术的核心优势WTV系列与WT2003H系列均提供QFN封装(如QFN32,尺寸为4×4mm),这种封装形式具有以下特点:体积紧凑:QFN封装通过减少引脚间距和优化内部结构,显著缩小芯片体积,适用于智能门铃、穿戴设备
    广州唯创电子 2025-04-30 09:02 290浏览
  • 网约车,真的“饱和”了?近日,网约车市场的 “饱和” 话题再度引发热议。多地陆续发布网约车风险预警,提醒从业者谨慎入局,这背后究竟隐藏着怎样的市场现状呢?从数据来看,网约车市场的“过剩”现象已愈发明显。以东莞为例,截至2024年12月底,全市网约车数量超过5.77万辆,考取网约车驾驶员证的人数更是超过13.48万人。随着司机数量的不断攀升,订单量却未能同步增长,导致单车日均接单量和营收双双下降。2024年下半年,东莞网约出租车单车日均订单量约10.5单,而单车日均营收也不容乐
    用户1742991715177 2025-04-29 18:28 242浏览
  • 在CAN总线分析软件领域,当CANoe不再是唯一选择时,虹科PCAN-Explorer 6软件成为了一个有竞争力的解决方案。在现代工业控制和汽车领域,CAN总线分析软件的重要性不言而喻。随着技术的进步和市场需求的多样化,单一的解决方案已无法满足所有用户的需求。正是在这样的背景下,虹科PCAN-Explorer 6软件以其独特的模块化设计和灵活的功能扩展,为CAN总线分析领域带来了新的选择和可能性。本文将深入探讨虹科PCAN-Explorer 6软件如何以其创新的模块化插件策略,提供定制化的功能选
    虹科汽车智能互联 2025-04-28 16:00 214浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦