Code covered by the BSD License  

Highlights from
RigExpert Driver V2.4 for MATLAB

image thumbnail
from RigExpert Driver V2.4 for MATLAB by Gergely Öllös
With this driver,one can make measurements, generate signals or get some screenshots from the device

RigExpert
classdef RigExpert < hgsetget
  %RigExpert AA230-PRO Driver V2.4 for MATLAB.
  %----------------------------------------------------------------------------------
  % Copyright (C) MSc. Gergely Ollos, February 23, 2013. (gergely.ollos@gmail.com)
  % All rights reserved.
  %----------------------------------------------------------------------------------
  % LICENSE:
  %   Redistribution and use in source and binary forms, with or without
  %   modification, are permitted provided that the following conditions are
  %   met:
  %
  %     * Redistributions of source code must retain the above copyright
  %       notice, this list of conditions and the following disclaimer.
  %     * Redistributions in binary form must reproduce the above copyright
  %       notice, this list of conditions and the following disclaimer in
  %       the documentation and/or other materials provided with the distribution
  %
  %   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  %   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  %   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  %   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  %   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  %   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  %   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  %   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  %   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  %   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  %   POSSIBILITY OF SUCH DAMAGE.
  %
  %----------------------------------------------------------------------------------
  % Basic description:
  %   This module controls the rig expert complex impedance meter. Generally you
  %   have to create the object first, then open the port and make your various
  %   measurements or generate signals etc. After you are done, close the
  %   communication channel and finally delete the object.
  %
  %----------------------------------------------------------------------------------
  % EXAMPLE(1): Measuring complex impedance from 300KHz to 200MHz of 1000 points
  %     AA=RigExpert('COM13');
  %     serOpen(AA);
  %     X=Measure(AA,300E3,200E6,1000);
  %     serClose(AA);
  %
  % Where X is a [n by 3] matrix, where the first column is the frequency in Hz, the
  % second column is the resistance and the third comulm is the reactance, both in
  % ohms.
  %
  %----------------------------------------------------------------------------------
  % EXAMPLE(2): Measuring and plotting the complex impedance from 300KHz to 200MHz
  %     AA=RigExpert('COM13');
  %     serOpen(AA);
  %     X=Measure(AA,300E3,100E6,300,'plot');
  %     serClose(AA);
  %
  % Where X is a [n by 3] matrix, where the first column is the frequency in Hz, the
  % second column is the resistance and the third comulm is the reactance, both in
  % ohms.
  %
  %----------------------------------------------------------------------------------
  % EXAMPLE(3): Generate 1 sec long 10dBm (max amplitude) 10MHz signal
  %     AA=RigExpert();
  %     serOpen(AA,'COM13');    %The com port can be specifies here as well
  %     setGen(AA,1E6,1);
  %     genOn(AA);
  %     pause(1);
  %     genOff(AA);
  %     serClose(AA);
  %
  %----------------------------------------------------------------------------------
  % EXAMPLE(4): Generating the following pattern:
  %           1 second long 1MHz signal of 0.7 amplitude
  %           0.5 second long silence
  %           2 second long 1MHz signal of 0.2 amplitude
  %           1sec long 5MHz signal of 1 amplitude
  %     -------------------------------------------------
  %     AA=RigExpert('COM13');
  %     serOpen(AA);            %Returns "1" if succesful else "0"
  %     setGen(AA,1E6,0.7);
  %     genOn(AA);
  %     pause(1);               %1sec 1MHZ signal
  %     genOff(AA);
  %     pause(0.5);             %0.5sec silence
  %     setAmp(AA,0.2);
  %     genOn(AA);
  %     pause(2);               %2sec 1MHz signal
  %     setGen(AA,5E6,1);
  %     pause(1);               %1sec 5MHz signal
  %     genOff(AA);
  %     serClose(AA);
  %
  %----------------------------------------------------------------------------------
  % EXAMPLE(5): Frequency and amplitude modulation demo
  %   AA=RigExpert('COM13');
  %   serOpen(AA);
  %   setGen(AA,1E6,0.5);
  %   genOn(AA);
  %
  %   for i=1:0.1:10
  %     setAmp(AA,abs(sin(i)));                     %Amplitude modulation
  %   end
  %   for i=1:0.1:30
  %     setGen(AA,3E6+(2.7E6)*sin(i),1);            %Frequency modulation
  %   end
  %   for i=1:0.1:30
  %     setGen(AA,3E6+(2.7E6)*sin(i),abs(sin(i)));  %Both
  %   end
  %
  %   genOff(AA);
  %   serClose(AA);
  %
  %----------------------------------------------------------------------------------
  % EXAMPLE (6): Getting the current screen of the RigExpert
  %     AA=RigExpert('COM13');
  %     img=screenShot(AA);
  %   imshow(img);
  %
  % Where img is a [64x128] binary matrix that stores the image. No need to close
  % the channel, since it is automatically closed.
  %
  %----------------------------------------------------------------------------------
  
  properties (SetAccess=private)
    % The serial COM object
    ComObj;
    % Scan/Generator default frequency
    genFreq=1E6;
    % Default scanner frequency
    genWidth=100E3;
    % Default reference phase
    phased=90;
    % Default measurement delay
    mdelay=4000;
    % default number of returned samples
    nsamp=10;
    % Default generator amplitude (max 10dBm when genAmp=1)
    genAmp=0.5;
    % Default serial port
    defSerPrt='COM13';
    % This variable signalizes active serial communication
    activeSer=0;
  end
  
  methods
    %% CONSTRUCTOR
    function Eobj = RigExpert(serPrt)
      % Creating the serial port object
      if exist('serPrt','var')
        Eobj.ComObj=serial(serPrt,'BaudRate',38400,'InputBufferSize',4096);
      end
    end
    
    
    
    %% OPENING THE PORT
    function ret=serOpen(obj,serPrt)
      % Checking if there is an active communication channel already established
      if obj.activeSer
        fprintf(2,'First you have to close the active channel!\n');
        return;
      end
      
      % Creating a new serial object if a new parameter is given
      if exist('serPrt','var')
        obj.ComObj=serial(serPrt,'BaudRate',38400,'InputBufferSize',4096);
      end
      
      % Checking if there is a serial object, if not, creating a default
      if ~isobject(obj.ComObj)
        fprintf(['There was no com port specified! '...
          'Opening the default %s port.\n'],obj.defSerPrt);
        obj.ComObj=serial(obj.defSerPrt,'BaudRate',38400,'InputBufferSize',4096);
      end
      
      % Attempting to open the serial port
      ret=1;
      try
        fopen(obj.ComObj);
      catch err %#ok<NASGU>
        ret=0;
        fprintf('Unable to open the specified port!\n');
        return
      end
      
      % Making a communication attempt
      fprintf(obj.ComObj,'VER\n');
      if ~waitForIt(obj,23,1)
        fclose(obj.ComObj);
        ret=0;
        fprintf('The rig expert is not responding (make sure it is in PC mode)!\n');
        return;
      end
      resp = fread(obj.ComObj, obj.ComObj.BytesAvailable);
      strings = regexp(char(resp)','\r\n','split'); %#ok<FREAD>
      if (length(strings) < 3) || (~strcmp(strings{2},'AA-230PRO 312'))
        ret=0;
        fclose(obj.ComObj);
        reply = input('Wrong firmware! Continue anyway? (Y/N) [Y]: ', 's');
        if ~(isempty(reply) || strcmpi(reply,'Y'))
          return
        end
      end
      
      % Initializing basic parameters
      cmdseq=updateCmds(obj);
      
      for i=[1 2 3 4 5]
        fprintf(obj.ComObj,cmdseq{i}); waitForIt(obj,6,1);
        if ~strcmp(strtrim(char(fread(obj.ComObj, ...
            obj.ComObj.BytesAvailable))'),'OK') %#ok<FREAD>
          ret=0;
          fprintf('Unable to configure the device! Channel left open!\n');
          return
        end
      end
      
      % Indicating the active channel
      obj.activeSer=ret;
    end
    
    
    
    %% TURNING ON THE GENERATOR
    function genOn(obj)
      % Checking if there is an active channel
      if ~obj.activeSer
        fprintf(2,'First you have to connect to the analyser!\n');
        return;
      end
      
      cmdseq=updateCmds(obj);
      % Turning on the generator
      for i=[8 1]
        fprintf(obj.ComObj,cmdseq{i}); waitForIt(obj,6,1); %ON
        if ~strcmp(strtrim(char(fread(obj.ComObj, ...
            obj.ComObj.BytesAvailable))'),'OK') %#ok<FREAD>
          fprintf('Unable to configure the device!\n');
        end
      end
      serialFlush(obj);
    end
    
    
    
    %% TURNING OFF THE GENERATOR
    function genOff(obj)
      % Checking if there is an active channel
      if ~obj.activeSer
        fprintf(2,'First you have to connect to the analyzer!\n');
        return;
      end
      
      cmdseq=updateCmds(obj);
      % Turning off the generator
      fprintf(obj.ComObj,cmdseq{7}); waitForIt(obj,6,1); %OFF
      if ~strcmp(strtrim(char(fread(obj.ComObj, ...
          obj.ComObj.BytesAvailable))'),'OK') %#ok<FREAD>
        fprintf('Unable to configure the device!\n');
      end
    end
    
    
    
    %% SETTING THE GENERATOR AMPLITUDE
    function setAmp(obj,amp)
      % Checking if there is an active channel
      if ~obj.activeSer
        fprintf(2,'First you have to connect to the analyzer!\n');
        return;
      end
      % Checking the range
      if ((amp < 0) || (amp > 1))
        fprintf(2,'Wrong amplitude!\n');
        return;
      end
      
      % Refreshing basic parameters
      obj.genAmp=amp;
      cmdseq=updateCmds(obj);
      
      fprintf(obj.ComObj,cmdseq{1}); waitForIt(obj,6,1);
      if ~strcmp(strtrim(char(fread(obj.ComObj, ...
          obj.ComObj.BytesAvailable))'),'OK') %#ok<FREAD>
        fprintf('Unable to configure the device!\n');
        return
      end
      
      serialFlush(obj);
    end
    
    
    
    %% MAKING A MEASUREMENT
    function dta=Measure(obj,ffrom,fto,nums,plotit)
      
      % Checking if there is an active channel
      if ~obj.activeSer
        fprintf(2,'First you have to connect to the analyzer!\n');
        return;
      end
      
      % Checking the parameters
      dta=NaN;
      if (ffrom >= fto) || (ffrom < 300E3) || (ffrom > 230E6) || ...
          (fto < 300E3) || (fto > 230E6) || (nums > 10000) || (nums < 2)
        fprintf(2,'Wrong parameters (freqency is in Hz)!\n');
        return;
      end
      
      % Initializing theRigExpert variables
      updateVec=[];
      if (obj.genFreq ~= round((ffrom+fto)/2))
        obj.genFreq=round((ffrom+fto)/2);
        updateVec(end+1)=2;
      end
      if (obj.genWidth ~= fto-ffrom)
        obj.genWidth=fto-ffrom;
        updateVec(end+1)=3;
      end
      obj.nsamp=nums-1; %RigExpert always returns one more sample
      cmdseq=updateCmds(obj);
      
      % Updating the device
      for i=updateVec
        fprintf(obj.ComObj,cmdseq{i}); waitForIt(obj,6,1);
        if ~strcmp(strtrim(char(fread(obj.ComObj, ...
            obj.ComObj.BytesAvailable))'),'OK') %#ok<FREAD>
          fprintf('Unable to configure the device!\n');
          return
        end
      end
      serialFlush(obj);
      
      % Asking for samples
      fprintf(obj.ComObj,cmdseq{6}); %FRX
      
      % Collecting the data without delay as it coms
      data=[]; tim=tic;
      while(toc(tim) < 60)
        if (obj.ComObj.BytesAvailable > 0)
          data=[data fread(obj.ComObj, obj.ComObj.BytesAvailable)';]; %#ok<AGROW>
        end
        if ((length(data) >= 6) && all(data(end-5:end)==[13 10 79 75 13 10]))
          % This is the end pointer
          break;
        end
      end
      
      if (toc(tim) >= 60)
        fprintf(2,'Unable to recive the data!\n');
        return;
      end
      serialFlush(obj);
      
      % Processing the strings
      strings = regexp(char(data),'\r\n','split');
      
      % Filtering the strings
      nstr={};
      for i=1:length(strings)
        if length(strings{i}) > 5
          nstr{end+1}=strings{i}; %#ok<AGROW>
        end
      end
      strings=nstr;
      
      % Converting the sub-strings
      for i=1:length(strings)
        dtas=regexp(strings{i},',','split');
        fr=str2double(dtas{1})*1E6;
        RR=str2double(dtas{2});
        XX=str2double(dtas{3});
        if isnan(dta)
          dta=[fr RR XX];
        else
          dta=[dta; [fr RR XX]]; %#ok<AGROW>
        end
      end
      
      % Turning off the generator
      genOff(obj);
      
      %Plotting the results if requested
      if (exist('plotit','var') && strcmpi(plotit,'plot'))
        % Create figure
        sc = get(0,'ScreenSize');
        figure1=figure('Name','Complex Impedance','NumberTitle','off','Resize',...
          'off','Color',[1 1 1],'Position',[sc(3)/2-375,sc(4)-465,719,379]);
        
        % Create axes
        axes1 = axes('Parent',figure1,'YMinorTick','on','YMinorGrid','off',...
          'YGrid','off',...
          'XMinorTick','on',...
          'XGrid','off',...
          'FontSize',16);
        hold(axes1,'all');
        
        % Create multiple lines using matrix input to plot
        if max(max(abs(dta(:,2:3)))) > 1E3
          RScale=1E3;
        else
          RScale=1;
        end
        
        if max(dta(:,1)) > 1E6
          FScale=1E6;
        elseif  max(dta(:,1)) > 1E3
          FScale=1E3;
        else
          FScale=1;
        end
        
        XData=dta(:,1)./FScale;
        RData=dta(:,2)./RScale;
        CData=dta(:,3)./RScale;
        
        % If smothing the data is acceptable (presuming not)
        % RData = pchip(XData,RData,linspace(min(XData),max(XData),1000))';
        % CData = pchip(XData,CData,linspace(min(XData),max(XData),1000))';
        % XData=linspace(min(XData),max(XData),1000)';
        
        plot1 = plot(XData,[RData CData],'Parent',axes1,'LineWidth',1);
        
        set(plot1(1),'DisplayName','R');
        set(plot1(2),'LineStyle','-','DisplayName','X');
        
        if max(dta(:,1)) > 1E6
          xlabel('frequency [MHz]','FontSize',16);
        elseif  max(dta(:,1)) > 1E3
          xlabel('frequency [KHz]','FontSize',16);
        else
          xlabel('frequency [Hz]','FontSize',16);
        end
        
        % Create ylabel
        if max(max(abs(dta(:,2:3)))) > 1E3
          ylabel('reactance [Kohm]','FontSize',16);
        else
          ylabel('reactance [Ohm]','FontSize',16);
        end
        
        % Create title
        title('complex impedance','FontSize',16);
        
        % Create legend
        legend1 = legend(axes1,'show');
        set(legend1,'EdgeColor',[1 1 1],'YColor',[1 1 1],'XColor',[1 1 1]);
        legend('boxoff');
        
        set(gca, 'Position', get(gca, 'OuterPosition') - ...
          get(gca, 'TightInset') * [-1 0 1 0; 0 -1 0 1; 0 0 1 0; 0 0 0 1]);
        
        axis tight;
      end
    end
    
    
    
    %% SETTING THE GENERATOR
    function setGen(obj, freq, amp)
      % Checking if there is an active channel
      if ~obj.activeSer
        fprintf(2,'First you have to connect to the analyzer!\n');
        return;
      end
      % Checking the range
      if ((amp < 0) || (amp > 1) || (freq < 300E3) || (freq > 230E6))
        fprintf(2,'Wrong amplitude (0..1) or frequency (300E3..230E6)!\n');
        return;
      end
      
      % Initializing the basic parameters (only those that were changed)
      updateVec=[];
      if (obj.genAmp ~= amp)
        obj.genAmp=amp;
        updateVec(end+1)=1;
      end
      if (obj.genFreq ~= freq)
        obj.genFreq = freq;
        updateVec(end+1)=2;
      end
      cmdseq=updateCmds(obj);
      
      for i=updateVec
        fprintf(obj.ComObj,cmdseq{i}); waitForIt(obj,6,1);
        if ~strcmp(strtrim(char(fread(obj.ComObj, ...
            obj.ComObj.BytesAvailable))'),'OK') %#ok<FREAD>
          fprintf('Unable to configure the device!\n');
          return
        end
      end
      serialFlush(obj);
    end
    
    
    
    %% GETTING THE SCREENSHOT FROM THE RIGEXPERT
    function binIm=screenShot(obj,serPrt)
      % Checking if there is an active channel
      if obj.activeSer
        fprintf(2,['First close the existing connection '...
          'end exit computer mode on the RigExpert!\n']);
        return;
      end
      
      % Trying to open the port
      if exist('serPrt','var')
        obj.defSerPrt=serPrt;
      end
      CObj=serial(obj.defSerPrt,'BaudRate',38400,'InputBufferSize',4096);
      
      fprintf('Please press F+6 on RigExpert when ready!\n');
      
      % Attempting to open the serial port
      try
        fopen(CObj);
      catch err %#ok<NASGU>
        fprintf('Unable to open the port!\n');
        return
      end
      
      % Waiting for the data to arrive
      while(CObj.BytesAvailable < 2064); end;
      
      % This is the raw data from the device
      rawdata=fread(CObj, CObj.BytesAvailable)';
      %This is the payload part
      hexdat=rawdata(15:(14+2048));
      
      % Convering the hexadecimal string to bytes
      dscreen=NaN*ones(1,1024);
      for i=1:length(dscreen)
        % These are the hexadecimal pairs of data that has to be converted to bytes
        dscreen(i)=hex2dec(char(hexdat([((i-1)*2+1) ((i-1)*2+2)])));
      end
      
      % Convering the byte streams into binary pixels
      binIm=NaN*ones(64,128);
      for y=1:size(binIm,1)
        for x=1:size(binIm,2)
          %Getting the address of the data inside the linear byte vector
          byteLinearAddr=x+(ceil(y/8)-1)*128;
          %Extracting the data byte from the linear byte vector
          dataByte=uint8(dscreen(byteLinearAddr));
          %Getting the address of the bit inside the dataByte
          bitAddr=mod(y-1,8)+1;
          %Getting the binary bit position mask which flags the desired bit
          bitMask=bitshift(1,bitAddr-1,'uint8');
          %Getting the bit from the dataByte on the flagged position by the mask
          binIm(y,x)=~logical(bitand(dataByte,bitMask,'uint8'));
        end
      end;
      
      % Closing the communication channel
      serialFlush(obj);
      fclose(CObj);
    end
    
    
    
    %% CLOSING THE SERIAL PORT
    function serClose(obj)
      % Checking if there is an active channel
      if ~obj.activeSer
        fprintf(2,'First you have to open a channel before closing it!\n');
        return;
      end
      fclose(obj.ComObj);
      obj.activeSer=0;
    end
  end
  
end



%% FLUSHING THE SERIAL PORT BUFFER
function serialFlush(obj)
  while (obj.ComObj.BytesAvailable > 0)
    fread(obj.ComObj, obj.ComObj.BytesAvailable);
    fprintf(2,'There were bytes to flush!\n');
  end
end



%% WAITF FOR THE SERIAL DATA TO ARRIVE
function ret=waitForIt(obj,dnum,dela)
  ret=1; t1=tic;
  while ((obj.ComObj.BytesAvailable < dnum) && (toc(t1) < dela)); end;
  if (toc(t1) >= dela)
    ret=0;
    fprintf(2,'Communication error (time out)!\n');
  end
end



%% THIS FUNCTION UPDATES THE CMD VECTOR WITH ACTUAL PARAMETERS
function cmdseq=updateCmds(obj)
  cmdseq{1}=sprintf('am%.f',round(obj.genAmp*1023));
  cmdseq{2}=sprintf('fq%.f',obj.genFreq);
  cmdseq{3}=sprintf('sw%.f',obj.genWidth);
  cmdseq{4}=sprintf('ph%.f',obj.phased);
  cmdseq{5}=sprintf('de%.f',obj.mdelay);
  cmdseq{6}=sprintf('frx%.f',obj.nsamp);
  cmdseq{7}=sprintf('off');
  cmdseq{8}=sprintf('on');
  cmdseq{9}=sprintf('ver');
end





Contact us