应用笔记 3557

逻辑分析仪内存不足? “拼”出解决之道!


摘要 : MATLAB®是一个强有力的工具,可用来快速分析从模数转换器(ADC)输出所捕获的数据。本应用笔记演示了如何使用MATLAB来突破逻辑分析仪存储深度的局限。描述并比较了三种数码拼接方式(基本,超前和反转)。并给出了三种方法所得的结果。

介绍

要评估一个高速模数转换器(ADC)的性能,就需要捕获其数字输出码,然后进行分析。逻辑分析仪的存储深度常常成为一个重要局限,妨碍系统捕获足够的数据点,以生成高分辨率FFT,或者精确的INL/DNL图。解决该问题的一个简单办法是使用某种数学工具,例如MATLAB (图1),将多组数据连接起来。连接数据的一个缺点是,通常会在两组数据之间的连接点出现很大的不连续性。尽管不连续性对INL/DNL图的影响极小,但对高分辨率FFT而言,几乎是毁灭性的(图2)。

图1. 连接后的数据在两组数据之间出现不连续。
图1. 连接后的数据在两组数据之间出现不连续。

图2. a) 捕获单组16384点数据并分析;b) 捕获两组8192点数据,连接,然后分析“拼接”技术。
图2. a) 捕获单组16384点数据并分析;b) 捕获两组8192点数据,连接,然后分析“拼接”技术。

有一种办法可以消除不连续性,就是在各组数据中寻找相同的点簇(一般为3到4个点),然后在这些点将两组数据“拼接”在一起(图3)。最简单的“拼接”方法是,记录下第一组数据中的最后四个点,然后在第二组数据里寻找相同的点簇。相同点簇出现在第二组数据中的位置称为“拼接点”。第二组数据中在拼接点之前的所有数据均被舍弃;第二组数据中的剩余部分与第一组数据合并。这种技术即所谓的基本数码拼接,实现起来非常简单,可以在MATLAB中非常快地运行。

图3. 基本数码拼接后得到的最终“拼接”数组
图3. 基本数码拼接后得到的最终“拼接”数组。

采用基本拼接方法拼接数据时,有时必须丢掉第二组数据中的近一半,才能找到与第一组数据最后四个点相匹配的一簇点。作为另一种选择,丢掉第一组数据尾部的几个点,常常有助于找到更靠近第二组数据起点的拼接点(图4)。然而,通过丢掉第一组数据尾部、第二组数据头部的部分采样点来寻找匹配点的方法实现起来比较困难。这种处理被称为超前数码拼接。理想拼接点应该能够保留尽可能多的数据点,寻找这样的拼接点需要认真的考虑和一定的编程技巧。正确地实现之后,超前拼接技术通常能够得到两组小数组所含数据点总数的至少90%。

图4. 采用超前拼接技术寻找理想拼接点,最终得到“拼接”后的数组。
图4. 采用超前拼接技术寻找理想拼接点,最终得到“拼接”后的数组。

将第二组数据(数组B)拼接到第一组数据(数组A)之前被称为反转拼接,这种方式有可能得到更大的拼接数组(图5)。但是,这种技术会使处理时间翻倍,因为必须在A领先于B和B领先于A两种情况下寻找拼接点。此外,当与其他拼接技术一起使用时,反转拼接方式所带来的好处通常很少。因此,对于较慢的PC,反转拼接技术大幅度增加的处理时间开销较之它所带来的好处而言并不太值。表1详细比较了这三种代码拼接方法。

图5. 反转拼接的处理时间加倍,但常常收效甚微。
图5. 反转拼接的处理时间加倍,但常常收效甚微。

表1. 三种拼接技术对比*
Stitch Technique Size of Final Data Set Description
Data Set Numbers # of codes
(averaged)
% of two data sets
(averaged)
1 + 2 3 + 4 1 + 4
Concatenate† N/A 16384 100% Will produce erroneous FFT; however, INL/DNL can be extracted from this data.
Basic 11060 8192‡ 14384 11212 68.4% FFT is useable for calculating figures of merit.
Reverse 11060 8192‡ 14384 11212 68.4%
Advanced 13790 16046 16022 15286 93.3%
Advanced
+
Reverse
15427 16176 16022 15875 96.9%

*采用上述拼接技术对两组8K (8192个)数据进行拼接。为确保准确性,采用四组8192点数据(分别编号为1至4)重复本测试。每组测试所合成的数据取平均后列于测试数据的右侧。
† 直接连接总能得到100%的数据。
‡ 无法拼接数据。

MATLAB函数说明

本文后附的MATLAB代码(附录A和B中的StitchMatrices和FindStitchPoint)将上述论点结合到一个易于使用的函数中。这些函数可接受两组数据(MATLAB中的单列矩阵)和几个输入变量(用来选择超前/反转拼接功能)。FindStitchPoint例程用来确定拼接点在数组A和B中的偏移量。StitchMatrices例程则根据FindStitchPoint例程给出的偏移量对两组数据A和B进行舍弃和组合。同时,最终数据的拼接点被记录在PrevStitchBins数组中,以便于后续处理。当拼接多组数据时,PrevStitchBins可保存老的拼接点。

结论

拼接两组数据可以得到一组理想的结果。图6给出了三组8192点数据使用上述拼接技术拼接起来(使用5个拼接点)后的FFT图。所得的FFT几乎与前面图2a所示,基于16384个连续点所得结果相同。

图6. 数码拼接后得到精确的FFT图。
图6. 数码拼接后得到精确的FFT图。

附录A:StitchMatrices例程(StitchMatrices.m)
function [StitchedMatrix, StitchBins] = StitchMatrices(MatrixA, ...
   				MatrixB, StitchNumber, PrevStitchBins, ...
				AdvCodeStitchEnabled, ReverseStitchEnabled);
%Stitch Matrices Function
%Revision 1.0
%
%By Donald Schelle, May 2005
%Maxim Integrated
%160 Rio Robles
%Sunnyvale, CA, 94086
%
%This function will take two matrices (MatrixA and MatrixB), find a 
%given number (StitchNumber) of identical points in each and 
%concatenate the two matrices into one.
%
%Inputs = MatrixA, MatrixB (Data Matrices)
%		    StitchNumber (Number of points to match)
%			 PrevStitchBins (Bins of Previous Stitches in MatrixA)
%			 AdvStitchEnabled (0 = NO, 1 = YES)
%			 ReverseStitchEnabled (0 = NO, 1 = YES)
%Output = StitchedMatrix (MatrixA + MatrixB)
%			 StitchBins (bins of StitchedMatrix where the two 
%						    matrices were joined.)
%
%If the matrices can not be joined the function will output a NaN
%for both the StitchedMatrix variable and the StitchBins variable
%--------------------------------------------------------------------------

%Check to see that there are at least TWO StitchNumber Points
if StitchNumber < 2,
   %Requested less than 2 stitch points
   StitchedMatrix = NaN;
   StitchBins = NaN;
   return;
end;

%Calculate Size of MatrixA and MatrixB
[SizeA, Junk] = size(MatrixA);
[SizeB, Junk] = size(MatrixB);

%Find the Stitch Points in MatrixB
[NormalA, NormalB] = FindStitchPoint(MatrixA, MatrixB, ...
   					StitchNumber, AdvCodeStitchEnabled);
%Calculate the size of the NormalStitched Matrix
NormalStitchedSize = NormalA + SizeB - NormalB + 1;
                            
%Check to see if the reverse function is enabled
if ReverseStitchEnabled == 1,
   %Find Stitch Points for Reverse Matrices
   [ReverseB, ReverseA] = FindStitchPoint(MatrixB, MatrixA, ...
      					StitchNumber, AdvCodeStitchEnabled);
   %Calculate the size of the Revered Stitched Matrix
   ReverseStitchedSize = ReverseB + SizeA - ReverseA + 1;
else
   %Set Values to defaults
   ReverseStitchedSize = NaN;		%MatrixB/A Stitch Size
   ReverseA = NaN;
   ReverseB = NaN;
end;

%Check to if it's possible to stitch two matrices
if isnan(NormalStitchedSize) & isnan(ReverseStitchedSize) == 1,
   %The two matrices could not be stitched
   StitchedMatrix = NaN;
   StitchBins = NaN;
   return;
end;

%--------------------- Normal Matrix Stitching Routine ---------------
if (NormalStitchedSize >= ReverseStitchedSize)| ...
   			isnan(ReverseStitchedSize) == 1,
   %Stitch MatrixB to the end of MatrixA
   StitchedMatrix = cat(1, MatrixA(1:NormalA), MatrixB(NormalB:SizeB));
   
   %Update Stitch Bins
   if isnan(PrevStitchBins) == 1,
      %There are no previous stitch bins
      StitchBins = [NormalA, NormalA + StitchNumber - 1];
   else
      %There are previous stitch bins
      %Check for Snipped Stitches
      [SizeStitchBins, Junk] = size(PrevStitchBins);
      
      while (PrevStitchBins(SizeStitchBins, 2) > (NormalA - 1)),
         %Second Bin is snipped from matrix. Check if first bin is snipped.
         if (PrevStitchBins(SizeStitchBins, 1) > (NormalA - 1)),
            %First Bin is snipped too. Delete Bin Pair
            PrevStitchBins = PrevStitchBins(1:(SizeStitchBins-1),:);
         else
            %First Bin is not snipped but second bin is snipped
            %Shrink Stitch Size
            PrevStitchBins(SizeStitchBins, 2) = NormalA - 1;
         end;
         
         %Calculate size of new PrevStitchBin Matrix
         [SizeStitchBins, Junk] = size(PrevStitchBins);
      end;
               
      %Insert New StitchBins      
      [SizeStitchBins, Junk] = size(PrevStitchBins);
      StitchBins = PrevStitchBins;
      StitchBins(SizeStitchBins + 1, :) = ...
      [NormalA, NormalA + StitchNumber - 1];
      
      %Check to see if the last two stitches need to be combined
      [SizeStitchBins, Junk] = size(StitchBins);
      if StitchBins(SizeStitchBins,1) == ...
            (StitchBins((SizeStitchBins - 1),2) + 1),
         %Combine Stitches
         StitchBins((SizeStitchBins - 1),2) = StitchBins((SizeStitchBins),2);
         %Shorten StitchBin Matrix
         StitchBins = StitchBins(1:(SizeStitchBins - 1),:);
      end;
      
   end;   
end;


%--------------------- Reverse Matrix Stitching Routine ---------------
if (ReverseStitchedSize >= NormalStitchedSize)| ...
   			isnan(NormalStitchedSize) == 1,
   %Stitch MatrixA to the end of MatrixB
   StitchedMatrix = cat(1,MatrixB(1:ReverseB), MatrixA(ReverseA:SizeA));
   
   %Update Stitch Bins
   if isnan(PrevStitchBins) == 1,
      %There are no previous stitch bins
      StitchBins = [ReverseB, ReverseB + StitchNumber - 1];
   else
      %There are previous stitch bins
      %Check for Snipped Stitches            
      while (PrevStitchBins(1,1) < (ReverseA + StitchNumber - 1)),
         %First Bin is snipped from matrix. Check if second is snipped
         if (PrevStitchBins(1,2) < (ReverseA + StitchNumber - 1)),
            %Second Bin is snipped too. Delete Bad Pair
            [SizeStitchBins, Junk] = size(PrevStitchBins);
      	     PrevStitchBins = PrevStitchBins(2:SizeStitchBins, :);
         else
            %Second Bin is not snipped, but first bin is snipped
            %Shrink Old Stitch Size
            PrevStitchBins(1,1) = ReverseA + StitchNumber - 1;
         end;
      end;
      
      %Offset Stitch Bins by inserted amount
      StitchBins = PrevStitchBins + ReverseB - ReverseA + 1; 
      %Make Room for new StitchBins
      [SizeStitchBins, Junk] = size(PrevStitchBins);
      StitchBins(2:SizeStitchBins+1, :) = StitchBins;
      %Insert New Stitch Bins
      StitchBins(1,:) = [ReverseB, ReverseB + StitchNumber - 1];
                  
      %Combine close stitches
      if StitchBins(1,2) == StitchBins(2,1) - 1,
         %Combine Stitches
         StitchBins(2,1) = StitchBins(1,1);
         %Shrink Stitch Bins Matrix
	 [SizeStitchBins, Junk] = size(StitchBins);
         StitchBins = StitchBins(2:SizeStitchBins,:);   
      end;
      
   end;
end;

附录B:FindStitchPoint例程(FindStitchPoint.m)

function [OutputBinA, OutputBinB]=FindStitchPoint(MatrixA, MatrixB, ...
   				MatchNumber, AdvancedStitchFindEnabled)
%Find Stitch Points Function
%Revision 1.0
%
%By Donald Schelle, May 2005
%Maxim Integrated
%160 Rio Robles
%Sunnyvale, CA, 94086
%
%This function will find the IDEAL stitch point in Matrix B given
%the number of data points to match
%
%Inputs = MatrixA
%			 MatrixB
%			 Number of Records to Match
%			 Advanced Stitch Find Enabled (0 = NO, 1 = YES)
%Output = (OutputBinA) End Bin of MatrixA to stitch data
%			 (OutputBinB) Start Bin of Matrix B to stitch data
%
%If no bins are found, the function will output a NaN
%--------------------------------------------------------------------------

%Do argument error checking to see if there is enough arguments
if nargin < 2,
   %The user has not supplied enough arguments
   disp('Function requires TWO Matrices');
   OutputBinA = NaN;
   OutputBinB = NaN;
   return;
elseif nargin < 3,
   disp('Select a number of points to match');
   OutputBinA = NaN;
   OutputBinB = NaN;
   return;
elseif nargin == 3,
   %Advanced code stitching is NOT enabled
   OutputBinA = NaN;
   AdvancedStitchFindEnabled=0;
end;

%Ensure that Matrix A and B are single ROW matrices
[row col] = size(MatrixA);
if row > col, MatrixA = MatrixA'; end;
[row col] = size(MatrixB);
if row > col, MatrixB = MatrixB'; end;

%Determine Size of Matrices
[Junk, SizeA] = size(MatrixA);
[Junk, SizeB] = size(MatrixB);

%Initialize OutputBinB to NaN (which means that NO stitch points are found)
OutputBinB = NaN;
%Set initial size of BinA
BinA = SizeA - MatchNumber + 1;
%Initialize BinStop Variable
BinStop = SizeA-100;

%Loop to search through Matrix B numerous times.  This loop is only
%excuted once if Advanced Stitch Find is disabled.  The loop will stop when
%the 'ideal' stitch point is found
while BinA > BinStop, 
   %Stuff the Match Numbers into a separate Matrix
	MatchMatrix = MatrixA(BinA:BinA+MatchNumber - 1);
   
   %Find all bins in MatrixB that match the first number of the Match Matrix
	MatchedBins = find(MatrixB == MatchMatrix(1));
   
   %Compare the 2nd through nth number of the Match Matrix with the
   %prospective series of numbers in MatrixB
   
   %Calculate the size of the Matched Bins Matrix
   [Junk, SizeMatchedBins] = size(MatchedBins);
   
   %The advanced stitch mode optimizes search time by eliminating
   %bad stitch points that would result in the final concatenated
   %matrix being smaller than the last set of stitch points
   if isnan(OutputBinB) == 0,
      %A Stitch Point exists from a previous run.  Elimiate bad stitch points
      %Calculate critical Stitch Point
      MatrixSize = OutputBinA + (SizeB-OutputBinB) + 1;
      CriticalBin = BinA + SizeB - MatrixSize - 1;
      %Find maximum number in the MatchMatrix
      BadBin = find(MatchedBins > CriticalBin);
      %Eliminate Bad Bins (if there are any)
      if isempty(BadBin) == 0,
         MatchedBins = MatchedBins(1:BadBin(1) - 1);
      end;
      %Calculate size of new Matched Bins Matrix
      [Junk, SizeMatchedBins] = size(MatchedBins);       
   end;
   
   %loop to cycle through initial matched bins
   for i=1:SizeMatchedBins,
      %Check to make sure that there isn't a MatrixB overrun
      if (MatchedBins(i) + MatchNumber - 1) > SizeB,
         break;
      end;
      
      %Assume that next few codes will match and set StitchBinGood = true
      StitchBinGood = 1;	   
      %Initialize MatchMatrixCounter
      Count = 1;
      %Cycle through MatrixB and compare Numbers with the MatchMatrix
      for j=MatchedBins(i):(MatchedBins(i) + MatchNumber - 1),
         if MatchMatrix(Count)==MatrixB(j),
            %Number is good, continue and check next number
	     Count = Count + 1;
	 else
            %Number is bad, break loop and try next sequence
            StitchBinGood = 0;
	     break;
	 end;
      end;
	   
      if StitchBinGood == 1,
         %The optimal (first) stitch has been found
         %Record the End bin of MatrixA
         %Record the Start bin of MatrixB
         OutputBinA = BinA;
         OutputBinB = MatchedBins(i) + 1;
         %Calculate the size of the joined Matrix and a new BinStop#
         BinStop = OutputBinA-OutputBinB+1;
         break;
      end;  
   end;
   
   if AdvancedStitchFindEnabled == 1,
      %Advanced Stitch Find is enabled and we should make a new match
      %matrix and search for these numbers
      BinA = BinA - 1;
   else
      %Advanced Stitch Find is disabled and we should end the loop
      break;
   end;
end;

%Check to see if NO Bins Matched
if isnan(OutputBinB) == 1,
   %NO Bins matched
   OutputBinA = NaN;
end;