Shared Memory Example (using "CAL" argument)

The following C# program demonstrates how to set up 4 traces and gather the data using shared memory. This example uses the "CAL" argument, which lets you quickly get all the corrected SParameter data of a Standard channel. This code should be run on the PXI controller directly.

See Also

SYSTem:DATA:MEMory commands

 

// This example demonstrates how to use C# to setup 4 traces and to gather data using the shared memory component
// This example uses the "CAL" argument, which lets you quickly get all the corrected SParameter data of a Standard channel

// This code should be run on the PXI controller directly

// The example demonstrates using helper function to check for all possible errors

// during the running of the code. Checking for errors helps identify problems early

// Add visa32.cs to the project.
// It it is here (after installing IO Libraries on your PC)
// C:\Program Files\IVI Foundation\VISA\Win64\agvisa\include\agvisa32.cs
using System;
using System.Text;
using System.IO.MemoryMappedFiles;

class SharedMemory
Perform Multi DUT Parallel measurements{

    // Variables to store the VISA session numbers
    static int g_defaultSession = -1;
    static int g_session = -1;


    // This example demonstrates how to use the shared memory component to read all the
    // SParameters of a calibrated SParameter channel using the "CAL" property
    static void Main(string[] args)
    {
        try
        {
            // Find the VISA address from the SCPI parser console on your VNA
            // System->System Setup->Remote Interface... Show SCPI parser Console -> Status
            // TODO: CHANGE THIS VISA_ADDRESS to point to your VNA
            string VISA_ADDRESS = "TCPIP0::localhost::hislip0,4880::INSTR";
            int timeout = 1000;

            CheckViStatus(visa32.viOpenDefaultRM(out g_defaultSession));
            CheckViStatus(visa32.viOpen(g_defaultSession, VISA_ADDRESS, 0, timeout, out g_session));
            CheckViStatus(visa32.viSetAttribute(g_session, visa32.VI_ATTR_TMO_VALUE, timeout));
            int s = g_session; // s is a alias for session

            // Preset the instrument and delete all traces
            WriteString("SYST:FPR");
            WriteString("DISP:WIND:STAT 1");

            // Create 4 SParameters
            string[] parameters = new string[] { "S11", "S21", "S12", "S22" };
            for (int i = 0; i < parameters.Length; i++)
            {
                // Create a new parameter
                WriteString($"CALC1:MEAS{i + 1}:DEF '{parameters[i]}'");
                WriteString($"DISP:MEAS{i + 1}:FEED 1\n");
            }

            // The "CAL" option requires an SParameter calset
            // Create an ideal calset for the channel
            // First delete any existing ideal calset
            int doesCalsetExist = int.Parse(Query("CSET:EXISts? 'Ideal2P'"));
            if (doesCalsetExist != 0)
            {
                WriteString("CSET:DELete 'Ideal2P'");
            }
            // Then create the ideal calset. Now you have a Full 2Port
            WriteString("SENS:CORR:CSET:CRE:DEF 'Ideal2P','Full 2P(1,2)'");

            // Now, the code demonstrates how to setup and retrieve the calibrated data via the
            // shared memory "CAL" argument

            // initialize memory mapped structures in VNA
            WriteString("SYST:DATA:MEM:INIT");

            // Number of points = 4 SParameter buffers * 201 points * 2 points for real/imaginary = 1608 points
            // Configure a new section of the memory map to monitor the complex data
            // "CAL" argument requires a calibration, and only returns complex data. (not formatted data)
            WriteString("SYST:DATA:MEM:ADD '1:1:CAL:1608'"); // add parameter to memory mapped

            // This will be 0 in our case. But could be non-zero if you are monitoring multiple buffers
            int offsets_for_complex_data = int.Parse(Query("SYST:DATA:MEM:OFFSet?"));

            // Tell the VNA to allocate the memory map. Name it "VNA_MemoryMap" (your choice on the name)
            WriteString("SYST:DATA:MEM:COMM 'VNA_MemoryMap'");

            // Query the size of the memory map
            int size = int.Parse(Query("SYST:DATA:MEM:SIZE?"));

            // Create the memory map in C#. This requires .NET 4.5 framework
            MemoryMappedFile mappedFile = MemoryMappedFile.CreateOrOpen("VNA_MemoryMap", size);
            MemoryMappedViewAccessor mappedFileView = mappedFile.CreateViewAccessor();

            // Trigger a single sweep, and wait for it to complete
            WriteString("SENS:SWE:MODE SING");
            Query("*OPC?");

            // Allocate buffers to hold the output data
            // 201 points * 2 points per complex (real/imaginary) * 4 buffers = 1608
            float[] complexData = new float[1608];
           
            // Copy the data from the memory map into the output buffers
            // These copy the data from the in-process memory map.
            // This runs very fast - and is just a "memcpy" under the hood
            ReadBytes(mappedFileView, offsets_for_complex_data, 1608, complexData);
           
            // Output some data to show that it worked

            // S11 starts at offset 0
            // S21 starts at offset 402
            // S12 starts at offset 804
            // S22 starts at offset 1206
            Console.WriteLine(complexData[0].ToString()); // Output first point of S11 in real format
            Console.WriteLine(complexData[402].ToString()); // Output first point of S21 in real format
            Console.WriteLine(complexData[804].ToString()); // Output first point of S12 in real format
            Console.WriteLine(complexData[1206].ToString()); // Output first point of S22 in real format
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        // Close the handles - even if there was an error
        if (g_session != -1)
            visa32.viClose(g_session);
        if (g_defaultSession != -1)
            visa32.viClose(g_defaultSession);
    }

    static public unsafe void ReadBytes(MemoryMappedViewAccessor mappedFileView,
        int offset, int num, float[] arr)
    {
        // This is equivalent to:
        //         //m_mappedFileView.ReadArray<float>(m_sharedMemoryOffsets[i-1], complexArray, 0, points*2);
        // But, using this "unsafe" code is 30 times faster. 100usec versus 3ms
        byte* ptr = (byte*)0;
        mappedFileView.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
        System.Runtime.InteropServices.Marshal.Copy(IntPtr.Add(new IntPtr(ptr), offset), arr, 0, num);
        mappedFileView.SafeMemoryMappedViewHandle.ReleasePointer();
    }

    static void WriteString(string command)
    {
        command += "\n";
        CheckViStatus(visa32.viPrintf(g_session,command));
        CheckForErrors();
    }
    static string Query(string query)
    {
        query += "\n";
        CheckViStatus(visa32.viPrintf(g_session,query));
        StringBuilder errorMessage = new StringBuilder();
        CheckViStatus(visa32.viScanf(g_session, "%t", errorMessage));
        return errorMessage.ToString();|    }


    // Helper function to check for any error with a VISA call
    static void CheckViStatus(int viStatus)
    {
        if (viStatus < 0) // If the viStatus is less than 0, then it indicates an error
        {
            // Convert the error number to a string
            StringBuilder errorMessage = new StringBuilder();
            visa32.viStatusDesc(g_session, viStatus, errorMessage);

            // Throw an exception with the string
            throw new Exception(errorMessage.ToString());
        }
    }

    // Helper function to check for logical SCPI errors
    static void CheckForErrors()
    {
        // Next check if there was a SCPI error
        CheckViStatus(visa32.viPrintf(g_session, "SYST:ERR:COUN?\n"));
        int errorCount;
        CheckViStatus(visa32.viScanf(g_session, "%d", out errorCount));
        if (errorCount == 0)
            return; // no errors

        // There is an error, let's convert it to a string
        StringBuilder allErrors = new StringBuilder();
        for (int i = 0; i < errorCount; i++)
        {
            CheckViStatus(visa32.viPrintf(g_session, "SYST:ERR?\n"));
            StringBuilder errorMessage = new StringBuilder();
            CheckViStatus(visa32.viScanf(g_session, "%t", errorMessage));
            allErrors.Append(errorMessage);
        }
        throw new Exception(allErrors.ToString());
    }

}