def dimArrays(self):
     # Initialize numpy arrays and python lists as zeros.
     shape2D = (self.chCount, self.pktCount)
     # 0-indexed by packet number.
     self.pkt = sp.zeros(self.pktCount, dtype=int)
     self.cpuDTStr = [cs.emptyClass()] * self.pktCount
     self.cpuDT = [0] * self.pktCount
     self.gpsDTStr = [cs.emptyClass()] * self.pktCount
     self.gpsDT = [0] * self.pktCount
     self.lat = sp.zeros(self.pktCount, dtype=float)
     self.longi = sp.zeros(self.pktCount, dtype=float)
     # 0-indexed by channel number.
     # 0-indexed by packet number.
     self.clipHi = sp.zeros(shape2D, dtype=int)
     self.clipLo = sp.zeros(shape2D, dtype=int)
     self.meanPct = sp.zeros(shape2D, dtype=float)
     self.meanUpPct = sp.zeros(shape2D, dtype=float)
     self.meanDnPct = sp.zeros(shape2D, dtype=float)
     self.meanPhys = sp.zeros(shape2D, dtype=float)
     self.meanUpPhys = sp.zeros(shape2D, dtype=float)
     self.meanDnPhys = sp.zeros(shape2D, dtype=float)
     self.countUp = sp.zeros(shape2D, dtype=int)
     self.countDn = sp.zeros(shape2D, dtype=int)
     # 0-indexed by channel number.
     # 0-indexed by packet number.
     # 0-indexed by sample number.
     self.raw = sp.zeros((self.chCount, self.pktCount, self.n), dtype=float)
def ipArgandCompare():

    pklFolder = r'C:\Users\timl\Documents\IP_data_plots\190503_oil'
    fileNums = sp.array([6, 7, 8, 9, 10])
    # File numbers with the low frequency for normalization for each file
    # number.
    #    lowFiles = sp.zeros_like(fileNums)
    #    shortColors = ['C0', 'C1', 'blueviolet']
    #    shortIdx = 0
    #    shortLinestyles = ['--', '-', '-']
    #
    #    colors = []
    #    linestyles = []
    #    legFilter = sp.zeros_like(fileNums, dtype=bool)
    #    for idx in range(0, len(fileNums), 3):
    #        lowFiles[idx:idx+3] = fileNums[idx]
    #        colors += 3*[shortColors[shortIdx]]
    #        linestyles += 3*[shortLinestyles[shortIdx]]
    #        shortIdx += 1
    #        legFilter[idx] = True

    linestyles = len(fileNums) * ['-']
    colors = len(fileNums) * [None]
    legFilter = sp.ones(len(fileNums), dtype=bool)
    lowFiles = fileNums.copy()

    instruct = cs.emptyClass()
    instruct.pklFolder = pklFolder
    instruct.fileNums = fileNums
    instruct.lowFiles = lowFiles
    instruct.colors = colors
    instruct.linestyles = linestyles
    instruct.legFilter = legFilter

    arg.ipArgand(instruct)
Пример #3
0
def coordExtrema(a):
    """
    Return corner coordinate positions of the smallest rectangle aligned with
    lines of longitude and latitude that would contain all the survey data
    points on or within its borders.

    Parameters
    ----------
    a : fileStruct, list
      Contains longitude and latitude information for each packet in each file.

    Returns
    -------
    ext : float (deg), fields of a class
      longiMin, longiMax, latMin, latMax
    """
    # Extreme values of longitude and latitude in the survey.
    longiMin = sp.inf
    latMin = sp.inf
    longiMax = -sp.inf
    latMax = -sp.inf
    for t in range(len(a)):
        if a[t].pktCount > 0:
            arraMin = sp.amin(a[t].longi)
            if arraMin < longiMin:
                longiMin = sp.amin(a[t].longi)
            arraMin = sp.amin(a[t].lat)
            if arraMin < latMin:
                latMin = arraMin
            arraMax = sp.amax(a[t].longi)
            if arraMax > longiMax:
                longiMax = arraMax
            arraMax = sp.amax(a[t].lat)
            if arraMax > latMax:
                latMax = arraMax

    ext = cs.emptyClass()
    ext.longiMin = longiMin
    ext.longiMax = longiMax
    ext.latMin = latMin
    ext.latMax = latMax
    return ext
def ipScatterEverything():

    folderPath = r'C:\temp\180827_smallSQUR'
    fileStart = cs.lastName(folderPath)

    # Processed file choice.
    loadThis = 'zOddH'
    # Plotting choice.
    plotThis = 'zPhase'

    # Channel plotted.
    ch = 2

    # Index of the frequency plotted.
    freqIdx = 0

    # Colors for plotting main results.
    if plotThis == 'zPhase':
        color = 'Red'
    elif plotThis == 'zMag':
        color = 'Green'
    elif plotThis == '2MagPhys':
        color = 'DarkGoldenRod'

    # Loading the data:
    fileName = fileStart + '_' + loadThis + '.pkl'
    filePath = os.path.join(folderPath, fileName)
    with open(filePath, 'rb') as f:  # Python 3: open(..., 'rb')
        a = pickle.load(f)

    # Pick out the desired result data to be plotted as x and y values.
    res = cs.emptyClass()
    res.yVal = sp.array([])
    for t in range(len(a)):
        if plotThis == 'zPhase':
            res.yVal = sp.hstack((res.yVal, a[t].phaseDiff[ch, :, freqIdx]))
        elif plotThis == 'zMag':
            res.yVal = sp.hstack((res.yVal, a[t].zMag[ch, :, freqIdx]))
        elif plotThis == '2MagPhys':
            res.yVal = sp.hstack((res.yVal, 2 * a[t].magPhys[ch, :, freqIdx]))
    res.xVal = sp.array(range(len(res.yVal)))

    # Initialize plot settings.
    ps = cs.emptyClass()
    ps.color = color
    ps.markerSize = 3
    ps.marker = 'o'
    ps.titleWrap = 75
    ps.xLabel = 'Packets'
    if plotThis == 'zPhase':
        ps.yLabel = 'Impedance Phase (mrad)'
    elif plotThis == 'zMag':
        ps.yLabel = 'Impedance Amplitude (m$\Omega$)'
    elif plotThis == '2MagPhys':
        if ch == 0:
            ps.yLabel = 'Twice Complex Mag. (A)'
        else:
            ps.yLabel = 'Twice Complex Mag. (V)'

    # Plot.
    # Function plots one thing at a time and can update formatting and labels.
    params = {
        'legend.fontsize': 'x-large',
        'figure.figsize': (9, 6.5),
        'axes.labelsize': 'x-large',
        'axes.titlesize': 'x-large',
        'xtick.labelsize': 'x-large',
        'ytick.labelsize': 'x-large'
    }
    plt.rcParams.update(params)

    # Plot the main result.
    # Use the string '_nolegend_' to hide the label from the legend display.
    plt.scatter(res.xVal, res.yVal, color=ps.color, marker=ps.marker)

    titleStr = '%s All Packets' % (fileStart)
    if ps.titleWrap < sp.inf:
        # Wrap text at a set character length.
        titleStr = '\n'.join(wrap(titleStr, ps.titleWrap))
    plt.title(titleStr)
    plt.xlabel(ps.xLabel)
    plt.ylabel(ps.yLabel)
    plt.legend()
    plt.grid(b=True)
    plt.tight_layout()
    plt.show()
def circuitTheory():

    ci = cs.emptyClass()
    # Resistors. (Ohm)
    ci.r1 = 0.1
    ci.r2 = 0.1
    ci.r3 = ci.r2
    ci.r4 = 1
    ci.r5 = ci.r4
    ci.r6 = 0.8
    ci.r7 = 8
    # Capacitor. (F)
    ci.c = 3e-6
    # Transmit current. Phase = 0. (complex A)
    ci.i1 = 3

    # Transmit frequency list. (Hz)
    xmitFund = 4
    freqList = sp.array(range(xmitFund, xmitFund * (33 + 1), 2 * xmitFund))
    phaseShift = sp.zeros_like(freqList)
    for idx in range(len(freqList)):
        # Frequency. (Hz)
        ci.f = freqList[idx]
        # Phase shift between the voltage across R1 and the transmit current.
        # Convert to milliradian.
        phaseShift[idx] = 10**3 * phaseI4(ci)

    params = {
        'legend.fontsize': 'x-large',
        'figure.figsize': (9, 6.5),
        'axes.labelsize': 'x-large',
        'axes.titlesize': 'x-large',
        'xtick.labelsize': 'x-large',
        'ytick.labelsize': 'x-large'
    }
    plt.rcParams.update(params)

    ps = cs.emptyClass()
    ps.color = 'C0'
    ps.markerSize = 6
    ps.marker = 'o'
    ps.legStr = 'Circuit Theory'
    ps.linestyle = 'solid'
    ps.titleStr = 'Capacitor, C = %.2f uF.' % (ci.c * 10**6)
    ps.titleWrap = 75
    ps.titleBool = True
    ps.xLabel = 'Frequency (Hz)'
    ps.yLabel = 'Phase Shift (mrad)'
    ps.legOutside = False

    # Plot the main result.
    lines2D = plt.plot(freqList,
                       phaseShift,
                       color=ps.color,
                       markersize=ps.markerSize,
                       marker=ps.marker,
                       label=ps.legStr,
                       linestyle=ps.linestyle)

    titleStr = ps.titleStr
    if ps.titleWrap < sp.inf:
        # Wrap text at a set character length.
        titleStr = '\n'.join(wrap(titleStr, ps.titleWrap))
    if ps.titleBool:
        plt.title(titleStr)
    plt.xlabel(ps.xLabel)
    plt.ylabel(ps.yLabel)
    if ps.legOutside:
        plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
        plt.subplots_adjust(right=0.75)
    else:
        plt.legend(loc="lower left")
        plt.tight_layout()
    plt.grid(b=True)
    plt.show()
Пример #6
0
def ipSurvey():
    params = {
        'legend.fontsize': 'x-large',
        'figure.figsize': (9, 6.5),
        'axes.labelsize': 'x-large',
        'axes.titlesize': 'x-large',
        'xtick.labelsize': 'x-large',
        'ytick.labelsize': 'x-large'
    }
    plt.rcParams.update(params)

    # Class object holding plot settings.
    ps = cs.emptyClass()

    # Whether to save the plotted datasets to txt files.
    ps.saveTxt = False

    crop = True

    ps.folderPath = r'C:\Users\timl\Documents\IP_data_plots\190506_eagle'
    folderName = cs.lastName(ps.folderPath)

    # Processed result choice.
    loadThis = 'zAnyF'

    # Read the depth information for each file.
    infoPath = os.path.join(ps.folderPath, 'depthInfo.txt')
    depthList = []
    with open(infoPath, 'r') as f:
        for lidx, line in enumerate(f, 1):
            # Strip off trailing newline characters.
            line = line.rstrip('\n')
            # Split up comma-delimited information.
            (fileDateStr, fileNum, senseFt) = line.split(',')
            # Type casting.
            fileNum = int(fileNum)
            # Estimated water depth on the line.
            senseFt = float(senseFt)  # (ft)
            depth = senseFt / 3.28084  # (m)
            # Dump results in a list.
            depthList.append([fileDateStr, fileNum, depth])

    # Loading the data.
    pklName = folderName + '_' + loadThis + '.pkl'
    filePath = os.path.join(ps.folderPath, pklName)
    with open(filePath, 'rb') as f:  # Python 3: open(..., 'rb')
        a = pickle.load(f)

    # Which files will be plotted.
    filesPlotted = cs.readFilesPlotted(a, ps.folderPath)

    # Crop information.
    if crop:
        cs.readCropInfo(a, ps.folderPath, 'pklCropInfo.txt')

    # Plotting choice.
    ps.plotThis = 'zMag'

    # Channel plotted.
    ps.ch = 1

    # Harmonic number of the xmitFund plotted.
    ps.h = 1
    # Index of the frequency in the list of odd harmonics.
    ps.freqIdx = 4 * ps.h

    # Whether the color axis bounds are set manually.
    manualColor = True
    clipColorData = False
    colMin = 1  # /(2*sp.pi*4)
    colMax = 5.5  # /(2*sp.pi*4)

    # Whether to plot line segments and points along the survey track.
    ps.showLines = False

    # Whehter to save polygon and line shape files.
    ps.saveShape = False

    # Rectangle defined by coordinate extrema along longi and lat axes.
    ps.ext = mm.coordExtrema(a)

    # Offset distance to either side of the survey line color strip extends.
    ps.sideRange = 3  # (m)

    # Whether to plot in (longi, lat) or a projected reference.
    ps.plotWGS84 = False

    # The WGS84 latitude-longitude Coordinate Reference System (CRS).
    ps.crsWGS84 = {'init': 'epsg:4326'}

    # Define an azimuthal equidistant Coordinate Reference System (CRS).
    longiCent = (ps.ext.longiMax + ps.ext.longiMin) / 2
    latCent = (ps.ext.latMax + ps.ext.latMin) / 2
    longiCent = -122.50032907675
    latCent = 47.617131187
    ccrsAzEq = ccrs.AzimuthalEquidistant(central_longitude=longiCent,
                                         central_latitude=latCent)
    # This Cartopy CRS (CCRS) can be converted into a `proj4` string/dict
    # compatible with GeoPandas.
    ps.crsAzEq = ccrsAzEq.proj4_init

    # Initializations.
    ps.colMin = sp.inf
    ps.colMax = -sp.inf
    tList = sp.array(range(len(a)))
    tList = tList[filesPlotted]
    originalFreqIdx = ps.freqIdx
    for t in tList:
        ps.freqIdx = originalFreqIdx
        if a[t].pktCount > 0:
            # Join the longitude and latitude arrays into one matrix with two
            # columns. Col 0: longi, Col 1: lat.
            # (deg)
            a[t].fix = sp.transpose(sp.vstack((a[t].longi, a[t].lat)))
            # Associate a water depth with each fix at the ship location.
            for idx in range(len(depthList)):
                if a[t].fileNum == depthList[idx][1]:
                    if a[t].fileDateStr == depthList[idx][0]:
                        depth = depthList[idx][2]
            a[t].depth = depth * sp.ones_like(a[t].pkt)  # (m)
            # Cable lead-length deployed.
            a[t].leadin = 65.25  # (m)
            # Take an average of the 3rd and 5th harmonics to get a reading
            # at 4 Hz when the xmitFund was 1 Hz.
            if a[t].xmitFund == 1 and ps.h == 1:
                ps.freqIdx = 4 * 4
                freqIdx3Hz = 4 * 3
                freqIdx5Hz = 4 * 5
                a[t].phaseDiff[ps.ch, :, ps.freqIdx] = (
                    (a[t].phaseDiff[ps.ch, :, freqIdx3Hz] +
                     a[t].phaseDiff[ps.ch, :, freqIdx5Hz]) / 2)
            # Pick which data to map to colors in the plot.
            if ps.plotThis == 'zPhase':
                a[t].color = a[t].phaseDiff[ps.ch, :, ps.freqIdx]
                # Despike phase differences with a threshold spike in mrad.
                #                a[t].color = despike(a[t].color, 10)
                cbarLabel = 'Impedance Phase (mrad)'
            elif ps.plotThis == 'zMag':
                a[t].color = a[t].zMag[ps.ch, :, ps.freqIdx]
                # Despike magnitudes with a threshold spike in mOhm.
                #                a[t].color = despike(a[t].color, 0.5)
                cbarLabel = 'Impedance Magnitude (m$\Omega$)'
            elif ps.plotThis == '2MagPhys':
                a[t].color = 2 * a[t].magPhys[ps.ch, :, ps.freqIdx]
                #                a[t].color = despike(a[t].color, 0.01)
                if ps.ch == 0:
                    cbarLabel = 'Twice Complex Mag. (A)'
                else:
                    cbarLabel = 'Twice Complex Mag. (V)'
            elif ps.plotThis == 'zTime':
                freq = a[t].freq[ps.freqIdx]  # (Hz)
                a[t].color = (a[t].phaseDiff[ps.ch, :, ps.freqIdx] /
                              (2 * sp.pi * freq))  # (millisecond)
                # Despike phase differences with a threshold spike in us.
                #                a[t].color = despike(a[t].color, 100)
                cbarLabel = 'v-i Time (ms)'
            elif ps.plotThis == 'crop':
                a[t].color = a[t].cropLogic.astype(float)
            # Edit the color data to clip at the manual bounds, if desired.
            if clipColorData:
                a[t].color[a[t].color < colMin] = colMin
                a[t].color[a[t].color > colMax] = colMax
            # Keep track of the maximum and minimum color values.
            if a[t].xmitFund != 8:
                if not crop:
                    arraMin = sp.amin(a[t].color)
                    arraMax = sp.amax(a[t].color)
                else:
                    if sp.any(a[t].cropLogic):
                        arraMin = sp.amin(a[t].color[a[t].cropLogic])
                        arraMax = sp.amax(a[t].color[a[t].cropLogic])
                    else:
                        arraMin = sp.inf
                        arraMax = -sp.inf
            if arraMin < ps.colMin:
                ps.colMin = arraMin
            if arraMax > ps.colMax:
                ps.colMax = arraMax

    # Manually set the min and max color values.
    if manualColor:
        ps.colMin = colMin
        ps.colMax = colMax

    # Big picture class containing master polygon, color, and line lists for
    # all survey lines.
    bp = cs.emptyClass()
    bp.polyList = []
    bp.colorList = []
    bp.lineList = []
    for t in tList:
        if a[t].pktCount > 0:
            if not crop or (crop and sum(a[t].cropLogic) > 0):
                print('file %s_%d' % (a[t].fileDateStr, a[t].fileNum))
                print(a[t].descript)
                # Print time the file started.
                print(a[t].cpuDTStr[0].t)
                plotStrip(bp, a[t], ps, crop)

    ps.fig = plt.gcf()
    ps.ax = ps.fig.add_subplot(111)
    ps.ax.set_aspect('equal')
    ps.cmap = 'jet'
    ps.lineCol = 'k'  # Color of the basic track line shape.
    # Geopandas data frame object containing each polygon in the list, along
    # with colors.
    dfPoly = gpd.GeoDataFrame({'geometry': bp.polyList, 'color': bp.colorList})
    dfPoly.crs = ps.crsAzEq

    dfLine = gpd.GeoDataFrame({'geometry': bp.lineList})
    dfLine.crs = ps.crsAzEq

    # Transform back to (longi,lat), if requested.
    if ps.plotWGS84:
        dfLine = dfLine.to_crs(ps.crsWGS84)
        dfPoly = dfPoly.to_crs(ps.crsWGS84)

    dfPoly.plot(ax=ps.ax,
                column='color',
                cmap=ps.cmap,
                vmin=ps.colMin,
                vmax=ps.colMax)

    if ps.showLines:
        dfLine.plot(ax=ps.ax, color=ps.lineCol)

    # Transform back to (longi,lat).
    if ~ps.plotWGS84:
        dfLine = dfLine.to_crs(ps.crsWGS84)
        dfPoly = dfPoly.to_crs(ps.crsWGS84)

    # Keep axis bounds from before the shorelines are plotted.
    xlimLeft, xlimRight = plt.xlim()
    ylimLeft, ylimRight = plt.ylim()
    xlimLeft = -100
    xlimRight = 500
    ylimLeft = -600
    ylimRight = 600
    #    xlimLeft = -100
    #    xlimRight = 500
    #    ylimLeft = -300
    #    ylimRight = 400
    #    xlimLeft = 5000
    #    xlimRight = 9000
    #    ylimLeft = -3500
    #    ylimRight = -1500
    #    xlimLeft = 7800
    #    xlimRight = 9000
    #    ylimLeft = -3000
    #    ylimRight = -2100

    if ps.saveShape:
        # Save the geodataframes to files for colors and lines.
        polyFileName = '%s_%s_Ch%dH%d' % (a[0].fileDateStr, ps.plotThis, ps.ch,
                                          ps.h)
        if clipColorData:
            polyFileName += '_clip%dand%d' % (colMin, colMax)
        lineFileName = '%s_lines' % (a[0].fileDateStr)
        shapeFolder = r'C:\temp\181213_dataFrameFileEagle'
        polyFilePath = os.path.join(shapeFolder, polyFileName)
        lineFilePath = os.path.join(shapeFolder, lineFileName)
        dfPoly.to_file(polyFilePath)
        dfLine.to_file(lineFilePath)

    # Shoreline plotting.
    shoreline(ps)

    # Reset the axis bounds after shorelines are plotted.
    plt.xlim(xlimLeft, xlimRight)
    plt.ylim(ylimLeft, ylimRight)

    # Display the colormap in use as a sidebar colorbar.
    sm = plt.cm.ScalarMappable(cmap=ps.cmap,
                               norm=plt.Normalize(vmin=ps.colMin,
                                                  vmax=ps.colMax))
    sm._A = []
    # colorbar() requires a scalar mappable, "sm".
    if ps.plotThis != 'crop':
        #        cbaxes = ps.fig.add_axes([0.8, 0.1, 0.03, 0.8])
        divider = make_axes_locatable(ps.ax)
        cax1 = divider.append_axes("right", size="10%", pad=0.05)
        cb = plt.colorbar(sm, cax=cax1)
        cb.set_label(cbarLabel)

    plt.sca(ps.ax)
    # Axes labels.
    if not ps.plotWGS84:
        plt.xlabel('W-E (m)')
        plt.ylabel('S-N (m)')
    else:
        plt.xlabel('Longitude (deg)')
        plt.ylabel('Latitude (deg)')
    plt.grid(b=True)
    # Plot title. Use notes recorded in one of the files plotted.
    tTitle = cs.find(filesPlotted, True)
    #    titleStr = ('%s Ch %d (%s). Harmonic %d = %.0f Hz. xmitFund = %.0f Hz.'
    #                % (a[tTitle].fileDateStr, ps.ch, a[tTitle].measStr[ps.ch], ps.h,
    #                   ps.h*a[tTitle].xmitFund, a[tTitle].xmitFund))
    titleStr = ('Ch %d (%s). Harmonic %d = %.0f Hz. xmitFund = %.0f Hz.' %
                (ps.ch, a[tTitle].measStr[ps.ch], ps.h,
                 ps.h * a[tTitle].xmitFund, a[tTitle].xmitFund))
    #    titleStr = ('%s Ch %d (%s). Frequency = %.0f Hz.'
    #                % (a[tTitle].fileDateStr, ps.ch, a[tTitle].measStr[ps.ch],
    #                   ps.h*a[tTitle].xmitFund))
    #    titleStr = ('%s_%d Line %s. Ch %d (%s). Frequency = %.0f Hz. '
    #                'xmitFund = %.0f Hz.'
    #                % (a[tTitle].fileDateStr, a[tTitle].fileNum,
    #                   a[tTitle].descript, ps.ch, a[tTitle].measStr[ps.ch],
    #                   a[tTitle].freq[ps.freqIdx], a[tTitle].xmitFund))
    if manualColor or clipColorData:
        if ps.plotThis == 'zPhase':
            titleStr += (' \nColors clipped at %d mrad and %d mrad.' %
                         (ps.colMin, ps.colMax))
        elif ps.plotThis == 'zMag':
            titleStr += ((' \nColors clipped at %.1f m$\Omega$ ' +
                          'and %.1f m$\Omega$.') % (ps.colMin, ps.colMax))
        elif ps.plotThis == '2MagPhys':
            titleStr += ((' \nColors clipped at %.2f A ' + 'and %.2f A.') %
                         (ps.colMin, ps.colMax))
        elif ps.plotThis == 'zTime':
            titleStr += ((' \nColors clipped at %.2f ms ' + 'and %.2f ms.') %
                         (ps.colMin, ps.colMax))
        elif ps.plotThis == 'crop':
            titleStr = '%s Orange = Array on Floor (Guess)' % (
                a[0].fileDateStr)
#            t = 4
#            titleStr = ('%s_%d Line %s. Average Speed 1.7 kt.' %
#                        (a[t].fileDateStr, a[t].fileNum, a[t].descript))
    plt.title(titleStr)
def artificialRaw():
    int215 = 2**15
    # Whether to add voltage spikes at the upward square wave transition.
    addSpikes = True
    doFilter = False
    ntaps = 1001
    cutoff = 10  # (Hz)
    if addSpikes:
        descript = 'spikes'
    else:
        descript = 'no spikes'
    if doFilter:
        descript += ' filtered'
    else:
        descript += ' unfiltered'
    at = cs.emptyClass()
    at.descript = descript
    folderPath = os.path.join(
        r'C:\Users\timl\Documents\IP_data_plots\190415_artificialSpikes')
    # Change .
    rawFolderPath = os.path.join(folderPath, 'rawData')
    at.fileDateStr = '190415'  # folderName[:6]
    at.fileNum = 2
    fileName = '%s_%d.txt' % (at.fileDateStr, at.fileNum)
    filePath = os.path.join(rawFolderPath, fileName)

    if doFilter:
        at.minor = '%.0f Hz cutoff, %d taps' % (cutoff, ntaps)
    else:
        at.minor = 'None.'

    at.major = ''
    at.scanChCount = 8
    at.writeChCount = 8
    at.n = 8192
    at.fs = 8192  # (Hz)
    at.xmitFund = 4  # (Hz)
    at.rCurrentMeas = 1.25  # (Ohm)
    at.rExtraSeries = 0  # (Ohm)

    at.measStr = at.writeChCount * ['N/A']
    at.measStr[0] = 'currentMeas'
    at.measStr[1] = 'voltage'

    at.In5BHi = sp.array([10, 0.1, 0.1, 0.1, 0.1, 1, 10, 10])
    at.In5BHi = at.In5BHi[:at.writeChCount]
    at.Out5BHi = sp.array([5, 10, 10, 10, 10, 5, 5, 5])
    at.Out5BHi = at.Out5BHi[:at.writeChCount]
    at.ALoadQHi = at.Out5BHi

    # Artificially generate raw current and voltage waveforms.
    if False:
        at.pktCount = 1
        at.raw = sp.zeros((at.writeChCount, at.pktCount, at.n))
        oilFolderPath = r'C:\Users\Public\Documents\oil_data'
        oilFilePath = os.path.join(oilFolderPath, at.descript + 'i.txt')
        at.raw[0, 0, :] = readOilFile(oilFilePath, at.n)
        oilFilePath = os.path.join(oilFolderPath, at.descript + 'd.txt')
        at.raw[1, 0, :] = readOilFile(oilFilePath, at.n)
    elif True:
        # Number of packets saved to the file.
        at.pktCount = 1
        # Time series.
        timeVec = sp.linspace(0, at.n / at.fs, at.n, endpoint=False)
        # Add a time offset from zero.
        timeVec += 0.1
        # Basic wave parameters to work from.
        amp = 6  # (%)
        freq = 4  # (Hz)
        # Wave phases by channel.
        phaseVec = sp.array(7 * [17]) / 1000  # (rad)
        phaseVec = sp.hstack((sp.zeros(1), phaseVec))

        # Measurment string.
        for ch in range(at.writeChCount):
            if addSpikes:
                if ch == 0:
                    at.measStr[ch] = 'Ch %d. No Spikes.' % ch
                else:
                    at.measStr[ch] = 'Ch %d. With Spikes.' % ch
            else:
                at.measStr[ch] = 'Ch %d. No Spikes.' % ch
        listTime = at.scanChCount * [timeVec]
        for ch in range(at.writeChCount):
            # Add channel skew error.
            deltaT = ch / (at.fs * at.scanChCount)  # (s)
            listTime[ch] = timeVec + deltaT
        at.raw = sp.zeros((at.writeChCount, at.pktCount, at.n))
        for p in range(at.pktCount):
            for ch in range(at.writeChCount):
                at.raw[ch, p, :] = amp * sp.signal.square(
                    2 * sp.pi * freq * listTime[ch] + phaseVec[ch])
                # Add voltage spikes to 100% at the transition from negative to
                # positive.
                if addSpikes and ch != 0:
                    lastSign = at.raw[ch, p, 0] > 0
                    for tIdx in range(1, len(at.raw[ch, p, :])):
                        newSign = at.raw[ch, p, tIdx] > 0
                        if newSign and (newSign != lastSign):
                            at.raw[ch, p, tIdx] = 100
                        lastSign = newSign

        # Convert from percentages of a range to a 16-bit integer scale.
        at.raw = scaleAndShift(at.raw)

        if doFilter:
            # Create an FIR filter.
            filtWin = firwin(ntaps, cutoff, fs=at.fs, pass_zero=True)

            # Apply the FIR filter to each channel.
            for p in range(at.pktCount):
                for ch in range(at.writeChCount):
                    #                filteredSig = sig_convolve(at.raw[ch, p, :],
                    #                                      filtWin)
                    x = at.raw[ch, p, :]
                    x = x[sp.newaxis, :]
                    filteredSig = np.array(
                        [np_convolve(xi, filtWin, mode='same') for xi in x])
                    at.raw[ch, p, :] = filteredSig.copy()

    with open(filePath, 'w') as f:
        # Write the file header.
        line = '%s,%d\n' % (at.fileDateStr, at.fileNum)
        f.write(line)
        line = '%s\n%s\n%s\n' % (at.descript, at.minor, at.major)
        f.write(line)
        line = '%d,%d,%d,%d,%.2f\n' % (at.scanChCount, at.writeChCount, at.n,
                                       at.fs, at.xmitFund)
        f.write(line)
        line = '%.1f,%.1f\n' % (at.rCurrentMeas, at.rExtraSeries)
        f.write(line)
        line = ''
        for ch in range(at.writeChCount):
            line = line + at.measStr[ch] + ','
        # Remove the last comma, and include a carriage return line feed.
        line = line[:-1] + '\n'
        f.write(line)
        line = float2lineStr(at.In5BHi, 3)
        f.write(line)
        line = float2lineStr(at.Out5BHi, 3)
        f.write(line)
        line = float2lineStr(at.ALoadQHi, 3)
        f.write(line)

        # Write packets of data to the file.
        cpuTimeStr = '133130.621'
        gpsDateStr = '000000'
        gpsTimeStr = '000000.000'
        lat = 'NaN'
        longi = 'NaN'
        maskUp = at.raw >= int215
        maskDn = at.raw < int215
        for p in range(at.pktCount):
            line = '$%d\n' % (p + 1)
            f.write(line)
            line = '\'%s,%s\n' % (at.fileDateStr, cpuTimeStr)
            f.write(line)
            line = '@%s,%s,%s,%s\n' % (gpsDateStr, gpsTimeStr, lat, longi)
            f.write(line)
            clipHi = sp.sum(at.raw[:, p, :] == (2**16 - 1), axis=1)
            line = float2lineStr(clipHi, 0)
            f.write(line)
            clipLo = sp.sum(at.raw[:, p, :] == 0, axis=1)
            line = float2lineStr(clipLo, 0)
            f.write(line)
            mean = sp.mean(at.raw[:, p, :], axis=1)
            mean = shiftAndScale(mean, int215)
            line = float2lineStr(mean, 1)
            f.write(line)
            meanUp = sp.zeros(at.writeChCount)
            meanDn = sp.zeros(at.writeChCount)
            for ch in range(at.writeChCount):
                meanUp[ch] = sp.mean(at.raw[ch, p, maskUp[ch, p, :]])
                meanDn[ch] = sp.mean(at.raw[ch, p, maskDn[ch, p, :]])
            meanUp = shiftAndScale(meanUp, int215)
            meanDn = shiftAndScale(meanDn, int215)
            line = float2lineStr(meanUp, 1)
            f.write(line)
            line = float2lineStr(meanDn, 1)
            f.write(line)
            countUp = sp.sum(maskUp[:, p, :], 1)
            line = float2lineStr(countUp, 0)
            f.write(line)
            countDn = sp.sum(maskDn[:, p, :], 1)
            line = float2lineStr(countDn, 0)
            f.write(line)
            for s in range(at.n):
                line = float2lineStr(at.raw[:, p, s], 0)
                f.write(line)
            # Asterisk character to end the packet.
            line = '*\n'
            f.write(line)
def ipArgand(instruct):
    # Whether to save the plot images.
    doSave = False

    plotThis = 'zPhase'

    pklFolder = instruct.pklFolder
    fileStart = cs.lastName(pklFolder)

    # Processed file choice.
    loadThis = 'zAnyF'

    # Channels plotted.
    ch = 2

    # Whether to identify and plot target files.
    targetBool = True

    # Whether to manually select which file numbers to plot.
    manualTargetBool = True
    manualTargetArra = instruct.fileNums

    # Whether to plot all the files together without erasing at all.
    fileTogether = True

    # Whether to omit 60 Hz data from the plots.
    omit60Hz = True

    # Frequencies plotted.
    maskChoice = 'oddHUp2'

    isYAxStartedFromZero = False

    # Whether to subtract baseline phase results from separate files.
    subtract1 = False
    if subtract1:
        # Pick a standard packet range to use.
        pktRang = range(17)

    # Whether to include the minor note in the legend entries rather than the
    # title.
    minorLegBool = False

    # Whether to include the minor note anywhere at all.
    minorBool = True

    # Whether to swap the description and minor note text for display purposes.
    swapDescriptMinor = False

    legOutside = False
    loc = 'center right'

    stdBool = False

    # Whether to plot only one packet's results instead of an average over all
    # the packets in the file.
    onePkt = False

    # File number from which the plot title is taken. inf if it doesn't matter.
    titleFileNum = sp.inf

    # Let colors be selected automatically if files are plotted together.
    if fileTogether:
        color = None
        stdColor = None

    # Loading the data:
    fileName = fileStart + '_' + loadThis + '.pkl'
    filePath = os.path.join(pklFolder, fileName)
    with open(filePath, 'rb') as f:  # Python 3: open(..., 'rb')
        a = pickle.load(f)

    # List of file numbers.
    fileNumArra = sp.zeros(len(a))
    for t in range(len(a)):
        fileNumArra[t] = a[t].fileNum
        if swapDescriptMinor:
            descript = a[t].descript
            a[t].descript = a[t].minor
            a[t].minor = descript

    if targetBool:
        tarList = []
        lowFilesA = sp.zeros(len(a), dtype=int)
        colorsA = len(a) * ['']
        linestylesA = len(a) * ['']
        legFilterA = sp.zeros(len(a), dtype=bool)
        for t in range(len(a)):
            if manualTargetBool:
                if any(a[t].fileNum == manualTargetArra):
                    tarList.append(t)
                    # Set up the low frequency normalization files for each file.
                    manualIdx = cs.find(manualTargetArra, a[t].fileNum)
                    lowFileNum = instruct.lowFiles[manualIdx]
                    lowFilesA[t] = cs.find(fileNumArra, lowFileNum)
                    colorsA[t] = instruct.colors[manualIdx]
                    linestylesA[t] = instruct.linestyles[manualIdx]
                    legFilterA[t] = instruct.legFilter[manualIdx]
            else:
                # Identify target files (They aren't baselines or tests).
                if a[t].descript != 'baseline' and a[t].descript != 'test':
                    if t < (len(a) - 1):
                        tarList.append(t)

    # Discover the maximum file number.
    maxFile = -sp.inf
    for t in range(len(a)):
        if a[t].fileNum > maxFile:
            maxFile = a[t].fileNum

    # Pick out the desired result data to be plotted as x and y values.
    res = []

    for t in range(len(a)):
        # Result class for each possible file to be read.
        res.append(cs.emptyClass())

    for t in tarList:
        if not subtract1 or not any(t == sp.array(tarList)):
            # (radian)
            phaseDiff = a[t].phaseDiff[ch, ...] / 1000
            zMag = a[t].zMag[ch, ...]
        else:
            # Subtract the baseline phase differences. (radian)
            fileOff = 3
            phaseDiff = (a[t].phaseDiff[ch, pktRang, :] -
                         a[t - fileOff].phaseDiff[ch, pktRang, :]) / 1000
            # Magnitudes.
            zMag = a[t].zMag[ch, pktRang, :]

        res[t].xVal = zMag * sp.cos(phaseDiff)
        res[t].yVal = zMag * sp.sin(phaseDiff)

        # Average over packets.
        if not onePkt:
            res[t].xVal = sp.mean(res[t].xVal, axis=0)
            res[t].yVal = sp.mean(res[t].yVal, axis=0)
        else:
            meanRang = instruct.pkt + sp.array([-1, 0, 1])
            res[t].xVal = res[t].xVal[meanRang, :]
            res[t].yVal = res[t].yVal[meanRang, :]
            # Average over the chosen packet and those on either side.
            res[t].xVal = sp.mean(res[t].xVal, axis=0)
            res[t].yVal = sp.mean(res[t].yVal, axis=0)

        # Mask out unwanted frequencies.
        mask = sp.zeros_like(a[t].freq, dtype=bool)
        if maskChoice == 'oddHUp2':
            mask[4:len(mask):8] = True
            # Number of frequencies included in the plot.
            freqCount = 17
            mask[(1 + 4 + 8 * (freqCount - 1)):] = False
        # Mask out 60 Hz, if requested.
        if omit60Hz:
            mask[a[t].freq == 60] = False
        res[t].xVal = res[t].xVal[mask]
        res[t].yVal = res[t].yVal[mask]

        # Result X and Y data normalized by the low freq. fundamental real
        # component of impedance.
        if t == lowFilesA[t]:
            maxReal1 = res[lowFilesA[t]].xVal[0]
        res[t].xVal /= maxReal1
        res[t].yVal /= maxReal1

        # If the phase difference baselines were subtracted, divide the
        # magnitudes.
        if subtract1 and any(t == sp.array(tarList)):
            baseMags = sp.sqrt(res[t - fileOff].xVal**2 +
                               res[t - fileOff].yVal**2)
            res[t].xVal /= baseMags
            res[t].yVal /= baseMags
            # Renormalize.
            if t == lowFilesA[t]:
                maxReal2 = res[lowFilesA[t]].xVal[0]
            res[t].xVal /= maxReal2
            res[t].yVal /= maxReal2

    # Initialize plot settings.
    ps = cs.emptyClass()
    # Figure with axes.
    ps.color = color
    ps.stdColor = stdColor
    ps.markerSize = 5
    ps.marker = 'o'
    ps.linestyle = '-'
    ps.markerSize = 4
    ps.titleWrap = 83
    ps.legOutside = legOutside
    ps.omit60Hz = omit60Hz
    ps.isYAxStartedFromZero = isYAxStartedFromZero
    ps.xLabel = 'REAL'
    ps.yLabel = 'IMAG'
    ps.stdBool = stdBool
    ps.normMag = False
    ps.loc = loc

    # List of file indices plotted.
    if targetBool:
        tList = tarList
    else:
        tList = range(0, len(a))

    # List adjacent files with each target file, if there are three per plot.
    tarList = tList

    # Plot, and save if needed.
    for idx in range(len(tList)):
        t = tList[idx]
        tar = tarList[idx]
        ps.ch = ch
        ps.color = colorsA[t]
        ps.linestyle = linestylesA[t]
        #        ps.titleStr = ('%s Ch %d (%s). xmitFund = %.0f Hz. %s'
        #                       % (a[t].fileDateStr, ch, a[t].measStr[ch],
        #                          a[t].xmitFund, a[t].major))
        ps.titleStr = ('%s Ch %d (%s). xmitFund = %.0f Hz.' %
                       (a[t].fileDateStr, ch, a[t].measStr[ch], a[t].xmitFund))
        #        ps.titleStr = ('Phase differences for artificial signals.')
        if onePkt:
            ps.titleStr += (' Results averaged over three packets centered '
                            'on each packet listed in the legend.')

        if subtract1:
            ps.titleStr += (
                ' Baseline sand phase angles have been subtracted, ' +
                'and normalized magnitudes have been divided by ' +
                'baseline normalized magnitudes before normalizing ' +
                'to a low frequency real value of 1 again.')
        # Legend text.
        if legFilterA[t]:
            # With legend.
            ps.legStr = 'File %d. Ch %d. %s.' % (a[t].fileNum, ch,
                                                 a[t].descript)
            if onePkt:
                ps.legStr = '(pkt %d) ' % (a[t].pkt[instruct.pkt]) + ps.legStr
        else:
            # Without legend.
            ps.legStr = '_nolegend_'
        if minorBool and (ps.legStr != '_nolegend_'):
            if not minorLegBool:
                if a[t].minor != 'None.':
                    ps.titleStr += ' %s.' % (a[t].minor)
            else:
                ps.legStr += ' %s.' % (a[t].minor)
        # The plot title is taken from the target file.
        ps.titleBool = False
        if t == tar:
            if (titleFileNum == sp.inf) or (titleFileNum == a[t].fileNum):
                ps.titleBool = True

        if plotThis == 'argand':
            ps.titleStr += ' Normalized Apparent Impedance Argand.'
            ps.xVal = res[t].xVal
            ps.yVal = res[t].yVal
        elif plotThis == 'zMag':
            ps.xVal = a[t].freq[mask]
            ps.yVal = sp.sqrt(res[t].xVal**2 + res[t].yVal**2)
            if subtract1:
                ps.titleStr += (
                    ' Normalized magnitudes have been divided by ' +
                    'baseline normalized magnitudes before normalizing ' +
                    'to a low frequency real value of 1 again.')
            ps.xLabel = 'Frequency (Hz)'
            ps.yLabel = 'Impedance Magnitude (Normalized)'
        elif plotThis == 'zPhase':
            ps.xVal = a[t].freq[mask]
            # Milliradian
            ps.yVal = 1000 * sp.arctan2(res[t].yVal, res[t].xVal)
            ps.xLabel = 'Frequency (Hz)'
            ps.yLabel = 'Impedance Phase (mrad)'
        pw.basePlot(ps)

        if (t == tar):
            if ((not fileTogether)
                    or (fileTogether and idx == len(tList) - 1)):
                if doSave:
                    pass
                if not (t == tList[-1]):
                    plt.clf()

    ax = plt.gca()
    if plotThis == 'argand':
        ax.set_aspect('equal', 'box')
    xmin, xmax = plt.xlim()
    ymin, ymax = plt.ylim()
    if ps.isYAxStartedFromZero:
        if ymax > 0:
            ax.axis([xmin, xmax, 0, ymax])
        else:
            ax.axis([0, xmax, ymin, 0])
def ipSurvey():
    params = {
        'legend.fontsize': 'x-large',
        'figure.figsize': (9, 6.5),
        'axes.labelsize': 'x-large',
        'axes.titlesize': 'x-large',
        'xtick.labelsize': 'x-large',
        'ytick.labelsize': 'x-large'
    }
    plt.rcParams.update(params)

    # Class object holding plot settings.
    ps = cs.emptyClass()

    # Whether to save the plotted datasets to txt files.
    ps.saveTxt = False

    crop = True

    ps.folderPath = r'C:\temp\181112_eagle'
    folderName = cs.lastName(ps.folderPath)

    # Processed result choice.
    loadThis = 'zAnyF'

    # Read the depth information for each file.
    infoPath = os.path.join(ps.folderPath, 'depthInfo.txt')
    depthList = []
    with open(infoPath, 'r') as f:
        for lidx, line in enumerate(f, 1):
            # Strip off trailing newline characters.
            line = line.rstrip('\n')
            # Split up comma-delimited information.
            (fileDateStr, fileNum, senseFt) = line.split(',')
            # Type casting.
            fileNum = int(fileNum)
            senseFt = float(senseFt)  # (ft)
            # Add the depth of the sensor and convert to meter.
            depth = (2.5 + senseFt) / 3.28084  # (m)
            # Dump results in a list.
            depthList.append([fileDateStr, fileNum, depth])

    # Loading the data.
    pklName = folderName + '_' + loadThis + '.pkl'
    filePath = os.path.join(ps.folderPath, pklName)
    with open(filePath, 'rb') as f:  # Python 3: open(..., 'rb')
        a = pickle.load(f)

    # Crop information.
    if crop:
        cs.readCropInfo(a, ps.folderPath)

    # Plotting choice.
    ps.plotThis = 'zPhase'

    # Channel plotted.
    ps.ch = 1

    # Harmonic number of the xmitFund plotted.
    ps.h = 13
    # Index of the frequency in the list of odd harmonics.
    ps.freqIdx = 4 * ps.h

    # Whether the color axis bounds are set manually.
    manualColor = False
    clipColorData = True
    colMin = 185
    colMax = 420

    # Whether to plot line segments and points along the survey track.
    ps.showLines = False
    ps.showPts = False

    # Rectangle defined by coordinate extrema along longi and lat axes.
    ps.ext = mm.coordExtrema(a)

    # Offset distance to either side of the survey line color strip extends.
    ps.sideRange = 3.5  # (m)

    # Whether to plot in (longi, lat) or a projected reference.
    ps.plotWGS84 = False

    # The WGS84 latitude-longitude Coordinate Reference System (CRS).
    ps.crsWGS84 = {'init': 'epsg:4326'}

    # Define an azimuthal equidistant Coordinate Reference System (CRS).
    longiCent = (ps.ext.longiMax + ps.ext.longiMin) / 2
    latCent = (ps.ext.latMax + ps.ext.latMin) / 2
    longiCent = -122.50032907675
    latCent = 47.617131187
    ccrsAzEq = ccrs.AzimuthalEquidistant(central_longitude=longiCent,
                                         central_latitude=latCent)
    # This Cartopy CRS (CCRS) can be converted into a `proj4` string/dict
    # compatible with GeoPandas.
    ps.crsAzEq = ccrsAzEq.proj4_init

    # Initializations.
    ps.colMin = sp.inf
    ps.colMax = -sp.inf
    tList = range(len(a))
    for t in tList:
        if a[t].pktCount > 0:
            # Join the longitude and latitude arrays into one matrix with two
            # columns. Col 0: longi, Col 1: lat.
            # (deg)
            a[t].fix = sp.transpose(sp.vstack((a[t].longi, a[t].lat)))
            # Associate a water depth with each fix at the ship location.
            for idx in range(len(depthList)):
                if a[t].fileNum == depthList[idx][1]:
                    if a[t].fileDateStr == depthList[idx][0]:
                        depth = depthList[idx][2]
            a[t].depth = depth * sp.ones_like(a[t].pkt)  # (m)
            # Cable lead-length deployed.
            a[t].leadin = 57  # (m)
            # Pick which data to map to colors in the plot.
            if ps.plotThis == 'zPhase':
                a[t].color = a[t].phaseDiff[ps.ch, :, ps.freqIdx]
                # Despike phase differences with a threshold spike in mrad.
                #                a[t].color = despike(a[t].color, 10)
                cbarLabel = 'Impedance Phase (mrad)'
            elif ps.plotThis == 'zMag':
                a[t].color = a[t].zMag[ps.ch, :, ps.freqIdx]
                # Despike magnitudes with a threshold spike in mOhm.
                #                a[t].color = despike(a[t].color, 0.5)
                cbarLabel = 'Impedance Magnitude (m$\Omega$)'
            elif ps.plotThis == '2MagPhys':
                a[t].color = 2 * a[t].magPhys[ps.ch, :, ps.freqIdx]
                #                a[t].color = despike(a[t].color, 0.01)
                if ps.ch == 0:
                    cbarLabel = 'Twice Complex Mag. (A)'
                else:
                    cbarLabel = 'Twice Complex Mag. (V)'
            elif ps.plotThis == 'zTime':
                freq = a[t].freq[ps.freqIdx]  # (Hz)
                a[t].color = (a[t].phaseDiff[ps.ch, :, ps.freqIdx] /
                              (2 * sp.pi * freq))  # (millisecond)
                # Despike phase differences with a threshold spike in us.
                #                a[t].color = despike(a[t].color, 100)
                cbarLabel = 'v-i Time (ms)'
            # Edit the color data to clip at the manual bounds, if desired.
            if clipColorData:
                a[t].color[a[t].color < colMin] = colMin
                a[t].color[a[t].color > colMax] = colMax
            # Keep track of the maximum and minimum color values.
            arraMin = sp.amin(a[t].color)
            if arraMin < ps.colMin:
                ps.colMin = arraMin
            arraMax = sp.amax(a[t].color)
            if arraMax > ps.colMax:
                ps.colMax = arraMax

    # Manually set the min and max color values.
    if manualColor:
        ps.colMin = colMin
        ps.colMax = colMax

    ps.fig, ps.ax = plt.subplots()
    ps.ax.set_aspect('equal')
    ps.cmap = 'jet'
    ps.lineCol = 'k'  # Color of the basic track line shape.
    for t in tList:
        if a[t].pktCount > 0:
            if not crop or (crop and sum(a[t].cropLogic) > 0):
                print('file %s_%d' % (a[t].fileDateStr, a[t].fileNum))
                print(a[t].descript)
                plotStrip(a[t], ps, crop)

    # Keep axis bounds from before the shorelines are plotted.
    xlimLeft, xlimRight = plt.xlim()
    ylimLeft, ylimRight = plt.ylim()
    xlimLeft = -408.14159194218564
    xlimRight = 383.2435609713969
    ylimLeft = -375.3266408701022
    ylimRight = 325.37655253272123

    if ps.saveShape:
        # Save the geodataframes to files for colors and lines.
        polyFileName = 'ch%d_H%d_%s_%s_%d.txt' % (
            ps.ch,
            ps.h,
            ps.plotThis,
            at.fileDateStr,
            at.fileNum,
        )

    # Shoreline plotting.
    shoreline(ps)

    # Reset the axis bounds after shorelines are plotted.
    plt.xlim(xlimLeft, xlimRight)
    plt.ylim(ylimLeft, ylimRight)

    # Display the colormap in use as a sidebar colorbar.
    sm = plt.cm.ScalarMappable(cmap=ps.cmap,
                               norm=plt.Normalize(vmin=ps.colMin,
                                                  vmax=ps.colMax))
    sm._A = []
    # colorbar() requires a scalar mappable, "sm".
    cb = plt.colorbar(sm)
    cb.set_label(cbarLabel)

    # Axes labels.
    if not ps.plotWGS84:
        plt.xlabel('W-E (m)')
        plt.ylabel('S-N (m)')
    else:
        plt.xlabel('Longitude (deg)')
        plt.ylabel('Latitude (deg)')
    plt.grid(b=True)
    # Plot title.
    titleStr = ('%s Ch %d (%s). Harmonic %d = %.2f Hz. xmitFund = %.2f Hz.' %
                (a[0].fileDateStr, ps.ch, a[0].measStr[ps.ch], ps.h,
                 ps.h * a[0].xmitFund, a[0].xmitFund))
    if manualColor or clipColorData:
        if ps.plotThis == 'zPhase':
            titleStr += (' \nColors clipped at %d mrad and %d mrad.' %
                         (ps.colMin, ps.colMax))
        elif ps.plotThis == 'zMag':
            titleStr += ((' \nColors clipped at %.1f m$\Omega$ ' +
                          'and %.1f m$\Omega$.') % (ps.colMin, ps.colMax))
        elif ps.plotThis == '2MagPhys':
            titleStr += ((' \nColors clipped at %.2f A ' + 'and %.2f A.') %
                         (ps.colMin, ps.colMax))
        elif ps.plotThis == 'zTime':
            titleStr += ((' \nColors clipped at %.2f ms ' + 'and %.2f ms.') %
                         (ps.colMin, ps.colMax))
    plt.title(titleStr)
def ipPlot(inFolder, inFileNums, inPlotThis):
    # Whether to save the plot images.
    doSave = False

    pklFolder = inFolder
    fileStart = cs.lastName(pklFolder)

    # Processed file choice.
    loadThis = 'zAnyF'
    # Plotting choice (y-axis).
    plotThis = inPlotThis
    # Plotting choice (x-axis).
    # 'freq': frequency (Hz).
    # 'phase': absolute phase (rad).
    xChoice = 'freq'

    # Frequency index to plot, if not plotting vs frequency.
    hChoice = 1
    freqIdx1 = 4*hChoice

    # Channels plotted.
    chList = [6]

    # Whether to include the listed channels together in the same plots.
    chTogether = False

    # Whether to identify and plot target files.
    targetBool = True

    # Whether to manually select which file numbers to plot.
    manualTargetBool = True
    manualTargetArra = inFileNums

    # Number of files included in each plot.
    # 1: just one file.
    # 3: 3 files are included, one primary, and each of the two adjacent files.
    fileCount = 1

    # Whether to subtract an average of results from the adjacent two files.
    subtractAdj = False

    # Whether to subtract one file's results from the target.
    subtract1 = False

    # Whether to plot all the files together without erasing at all.
    fileTogether = True

    # Whether to average over packets.
    meanBool = True

    if meanBool:
        # Whether to plot standard deviation envelopes.
        stdBool = True
    else:
        stdBool = False
        # Whether to plot all packets individually on the same plots.
        allPktBool = True
        if not allPktBool:
            # Which packet index to plot alone.
            pIso = 0

    # Whether to omit 60 Hz data from the plots.
    omit60Hz = True

    # Frequencies plotted.
    maskChoice = 'oddHUp2'

    isYAxStartedFromZero = False


    # Whether to include the minor note anywhere at all.
    minorBool = False

    # Whether to include the minor note in the legend entries rather than the
    # title.
    minorLegBool = False

    # Whether to swap the description and minor note text for display purposes.
    swapDescriptMinor = False

    legOutside = False
    loc = 'best'

    if plotThis == 'zMag':
        # Whether to normalize the impedance magnitudes by the fundamental.
        normMag = False
    else:
        normMag = False

    # File number from which the plot title is taken. inf if it doesn't matter.
    titleFileNum = sp.inf

    # Colors for plotting main results.
    if plotThis == 'zPhase':
        color = 'Red'
        stdColor = 'Fuchsia'
    elif plotThis == 'zMag':
        color = 'Green'
        stdColor = 'LimeGreen'
    elif plotThis == '2MagPhys':
        color = 'DarkGoldenRod'
        stdColor = 'Gold'
    elif plotThis == 'inductance':
        color = None
        stdColor = None

    # Let colors be selected automatically if files are plotted together.
    if fileTogether:
        color = None
        stdColor = None

    if fileCount == 3:
        # Colors for plotting main results.
        color3 = ['Black', 'Blue', color]
        stdColor3 = ['Gray', 'DodgerBlue', stdColor]

    # Colors for plotting results on different channels.
    chColor = ['Black', 'SteelBlue', 'LimeGreen', 'Crimson', 'Green',
               'DeepPink', 'BlueViolet', 'Orange']
    chStdColor = ['Gray', 'SkyBlue', 'YellowGreen', 'Brown', 'ForestGreen',
                  'HotPink', 'DarkMagenta', 'Coral']

    # Loading the data:
    fileName = fileStart + '_' + loadThis + '.pkl'
    filePath = os.path.join(pklFolder, fileName)
    with open(filePath, 'rb') as f:  # Python 3: open(..., 'rb')
        a = pickle.load(f)

    # Pick out the desired result data to be plotted as x and y values.
    res = []
    for t in range(len(a)):
        res.append(cs.emptyClass())
        if xChoice == 'freq':
            # Frequencies along the x-axis.
            res[t].xVal = a[t].freq
        elif xChoice == 'phase':
            res[t].xVal = abs(abs(a[t].phase) - sp.pi/2)

        if plotThis == 'zPhase':
            res[t].yVal = a[t].phaseDiff
        elif plotThis == 'zMag':
            res[t].yVal = a[t].zMag
        elif plotThis == '2MagPhys':
            res[t].yVal = 2*a[t].magPhys
        elif plotThis == 'zTime':
            res[t].yVal = sp.zeros_like(a[t].phaseDiff)
            # Convert phase differences to time differences.
            for idx in range(len(a[t].freq)):
                freq = a[t].freq[idx]
                if freq != 0:
                    # (microsecond)
                    res[t].yVal[:, :, idx] = (10**3 * a[t].phaseDiff[:, :, idx]
                        / (2 * sp.pi * freq))
        elif plotThis == 'inductance':
            # Convert to estimates of the inductance in the circuit.
            r2 = 8.1  # Ohm
            r3 = sp.inf  # initialization
            if sp.any(a[t].fileNum == sp.array([2, 5, 9, 10])):
                r3 = 1.0  # Ohm
            elif sp.any(a[t].fileNum == sp.array([3, 6, 11, 12])):
                r3 = 2.0  # Ohm
            # Matrix of inductance values.
            lMat = sp.zeros_like(a[t].phaseDiff)
            for p in range(a[t].pktCount):
                for freqIdx in range(len(a[t].freq)):
                    omega = 2*sp.pi*a[t].freq[freqIdx]  # (rad/s)
                    # Solving the quadratic for L.
                    # (rad)
                    phaseDiff = a[t].phaseDiff[chList[0], p, freqIdx]/1000
                    tangent = sp.tan(phaseDiff)
                    aQ = omega**2*tangent
                    b = -omega*r2
                    c = r3*(r3 + r2)*tangent
                    # (H)
                    lMat[chList[0], p, freqIdx] = (-b - sp.sqrt(b**2 - 4*aQ*c)
                                                   )/(2*aQ)
            # Convert to microHenry.
            lMat *= 1e6  # (uH)
            res[t].yVal = lMat
        if xChoice == 'freq':
            # Mask out unwanted frequencies.
            mask = sp.zeros_like(a[t].freq, dtype=bool)
            if maskChoice == 'oddH':
                # Save odd harmonics of the transmit fundamental.
                mask[4:len(mask):8] = True
            elif maskChoice == 'fund':
                mask[4] = True
            elif maskChoice == 'blockSine':
                mask[4:len(mask):8] = True
                mask[12:len(mask):24] = False
            elif maskChoice == 'oddHUp2':
                mask[4:len(mask):8] = True
                # Number of frequencies included in the plot.
                freqCount = 17
                mask[(1+4+8*(freqCount-1)):] = False
            elif maskChoice == 'oddUp2':
                mask[1:len(mask):2] = True
                mask[10:] = False
            elif maskChoice == 'nonzero':
                mask[1:150] = True
            elif maskChoice == 'custom':
                mask[sp.array([4, 12, 20, 27, 35, 43, 51, 59, 66, 74, 82, 90, 98, 106,
                     113, 121, 129, 137, 145])] = True
            # Mask out 60 Hz, if requested.
            if omit60Hz:
                mask[a[t].freq == 60] = False
            res[t].xVal = res[t].xVal[mask]
            res[t].yVal = res[t].yVal[..., mask]

    if targetBool:
        tarList = []
        for t in range(len(a)):
            if manualTargetBool:
                if any(a[t].fileNum == manualTargetArra):
                    tarList.append(t)
            else:
                # Identify target files (They aren't baselines or tests).
                if a[t].descript != 'baseline' and a[t].descript != 'test':
                    if t < (len(a) - 1):
                        tarList.append(t)

    # List of file numbers.
    fileNumList = []
    for t in range(len(a)):
        fileNumList.append(a[t].fileNum)
        if swapDescriptMinor:
            descript = a[t].descript
            a[t].descript = a[t].minor
            a[t].minor = descript

    # Initialize plot settings.
    ps = cs.emptyClass()
    # Figure with axes.
    ps.color = color
    ps.stdColor = stdColor
    ps.stdBool = stdBool
    ps.markerSize = 3
    ps.marker = 'o'
    if xChoice == 'freq':
        ps.linestyle = 'solid'
    else:
        ps.linestyle = 'none'
        ps.markerSize = 4
    ps.titleWrap = 75
    ps.legOutside = legOutside
    ps.omit60Hz = omit60Hz
    ps.isYAxStartedFromZero = isYAxStartedFromZero
    ps.normMag = normMag
    ps.loc = loc
    if xChoice == 'freq':
        ps.xLabel = 'Frequency (Hz)'
    elif xChoice == 'phase':
        ps.xLabel = 'abs(abs(Phase) - pi/2) (rad)'

    if plotThis == 'zPhase':
        ps.yLabel = 'Impedance Phase (mrad)'
        if subtractAdj or subtract1:
            ps.yLabel = 'Phase Displacement from Baseline (mrad)'
    elif plotThis == 'zMag':
        if not normMag:
            ps.yLabel = 'Impedance Magnitude (m$\Omega$)'
        else:
            ps.yLabel = 'Impedance Magnitude (Normalized)'
    elif plotThis == '2MagPhys':
        if chList[0] == 0:
            ps.yLabel = 'Twice Complex Mag. (A)'
        else:
            ps.yLabel = 'Twice Complex Mag. (V)'
    elif plotThis == 'zTime':
        ps.yLabel = 'Voltage Lead Time ($\mu$s)'
    elif plotThis == 'inductance':
        ps.yLabel = 'Inductance L ($\mu$H)'

    # List of file indices plotted.
    if targetBool:
        tList = tarList
    else:
        tList = range(0, len(a))

    # List adjacent files with each target file, if there are three per plot.
    if fileCount == 3:
        newTList = []
        tarList = []
        for t in tList:
            newTList.extend(t + sp.array([-1, 1, 0]))
            tarList.extend(3*[t])
        tList = newTList
        del newTList
    else:
        tarList = tList

    # Plot, and save if needed.
    for idx in range(len(tList)):
        imgFolder = plotThis + str(fileCount)
        t = tList[idx]
        tar = tarList[idx]
        if False:
            if a[t].fileNum <= 10 + 2:
                ps.color = 'C0'
            elif a[t].fileNum <= 22 + 2:
                ps.color = 'C1'
            elif a[t].fileNum <= 34 + 2:
                ps.color = 'C2'

        for ch in chList:
            ps.ch = ch
            if chTogether:
                ps.color = chColor[ch]
                ps.stdColor = chStdColor[ch]
            ps.xVal = res[t].xVal
            if fileCount == 3:
                colorIdx = cs.find((t - tar) == [-1, 1, 0], True)
                ps.color = color3[colorIdx]
                ps.stdColor = stdColor3[colorIdx]
#            ps.titleStr = ('%s Ch %d (%s). xmitFund = %.2f Hz. %s'
#                           % (a[t].fileDateStr, ch, a[t].measStr[ch],
#                              a[t].xmitFund, a[t].major))
            ps.titleStr = ('%s Ch %d (%s). %s'
                           % (a[t].fileDateStr, ch, a[t].measStr[ch],
                              a[t].major))
            if xChoice == 'phase':
                ps.titleStr = ('Plotted freq. = %d Hz. '
                               % (a[t].freq[freqIdx1]) + ps.titleStr)
            # Linestyle choice.
            if a[t].minor == 'Sand.':
                ps.linestyle = '--'
            else:
                ps.linestyle = 'solid'
            # Legend text.
            if a[t].xmitFund == 1 and sp.mod(a[t].fileNum, 12) != 0:
                # With legend.
                ps.legStr = '%s' % (a[t].descript[:-6])
            else:
                # Without legend.
                ps.legStr = '_nolegend_'
#            ps.legStr = ('%d. %s' % (a[t].fileNum, a[t].descript))
            if chTogether:
                ps.titleStr = ('%s_%d %s. xmitFund = %.1f Hz. %s'
                               % (a[t].fileDateStr, a[t].fileNum,
                                  a[t].descript, a[t].xmitFund,
                                  a[t].major))
                ps.legStr = 'Ch %d (%s)' % (ch, a[t].measStr[ch])
            if minorBool and (ps.legStr != '_nolegend_'):
                if not minorLegBool:
                    ps.titleStr = '%s ' % (a[t].minor) + ps.titleStr
                else:
                    ps.legStr = '%s ' % (a[t].minor) + ps.legStr
#            if not sp.any(a[t].fileNum ==
#                          (32 + sp.array([1, 3, 5, 7, 9, 11, 13, 15]))):
#                ps.legStr = '_nolegend_'
            # The plot title is taken from the target file.
            ps.titleBool = False
            if t == tar:
                if (titleFileNum == sp.inf) or (titleFileNum == a[t].fileNum):
                    ps.titleBool = True
            imgFile = ('%s_ch%d_%d_%s'
                       % (a[t].fileDateStr, ch, a[t].fileNum, plotThis))
            if meanBool:
                # Result Y data.
                ps.yVal = res[t].yVal[ch, ...]
#                ps.legStr += ' (Avg. of %d packets)' % (a[t].pktCount)
                if stdBool:
                    ps.titleStr += ' Shaded patches are means +/- 1 STD.'
                if not subtractAdj and not subtract1:
                    pw.plot1Mean(ps)
                elif subtract1:
                    ps.yValA = res[t-3].yVal[ch, ...]
                    pw.plot1MeanSubtract1(ps)
                elif subtractAdj:
                    ps.yValA = res[t-1].yVal[ch, ...]
                    ps.yValB = res[t+1].yVal[ch, ...]
                    pw.plot1MeanSubtractAdj(ps)
            else:
                if allPktBool:
                    pList = sp.array(range(a[t].pktCount))
                else:
                    pList = sp.array([pIso])
                if xChoice != 'freq':
                    pList = sp.array([0])
                for idx in range(len(pList)):
                    p = pList[idx]
                    if idx != 0:
                        # Only the first packet in the list appears in the
                        # legend.
                        ps.legStr = '_nolegend_'
                    else:
                        if allPktBool:
                            ps.legStr += '\n (%d packets)' % (a[t].pktCount)
                        else:
                            ps.legStr += ' (pkt %d)' % (a[t].pkt[p])
                    if xChoice != 'freq':
                        # When x is not frequency.
                        ps.xVal = res[t].xVal[ch, :, freqIdx1]
                        ps.yVal = res[t].yVal[ch, :, freqIdx1]
                    else:
                        ps.yVal = res[t].yVal[ch, p, :]
                    pw.basePlot(ps)

            if (t == tar):
                if (not chTogether) or (chTogether and ch == chList[-1]):
                    if ((not fileTogether) or
                            (fileTogether and idx == len(tList) - 1)):
                        if doSave:
                            cs.saveImg(pklFolder, imgFolder, imgFile)
                        if not ((t == tList[-1]) and (ch == chList[-1])):
                            plt.clf()

    ax = plt.gca()
    xmin, xmax = plt.xlim()
    ymin, ymax = plt.ylim()
#    plt.xscale('log')
    if ps.isYAxStartedFromZero:
        if ymax > 0:
            ax.axis([xmin, xmax, 0, ymax])
        else:
            ax.axis([xmin, xmax, ymin, 0])
Пример #11
0
def circuitTheory(meas='R1', plotThis='zPhase'):

    ci = cs.emptyClass()
    # Resistors. (Ohm)
    ci.r1 = 0.1
    ci.r2 = 0.1
    ci.r3 = ci.r2

    ci.r4 = 8
    # Capacitor. (F)
    ci.c = 3e-3
    
    ci.meas = meas
    ci.plotThis = plotThis
    
    # Transmit current. Phase = 0. (complex A)
    ci.i1 = 1

    # Transmit frequency list. (Hz)
    xmitFund = 4
    freqList = sp.array(range(xmitFund, xmitFund*(100 + 1), 2*xmitFund))
    result = sp.zeros_like(freqList)
    for idx in range(len(freqList)):
        # Frequency. (Hz)
        ci.f = freqList[idx]
        # Convert to milliUnits.
        result[idx] = 10**3*circuitSolve(ci)

    params = {'legend.fontsize': 'x-large',
              'figure.figsize': (9, 6.5),
              'axes.labelsize': 'x-large',
              'axes.titlesize': 'x-large',
              'xtick.labelsize': 'x-large',
              'ytick.labelsize': 'x-large'}
    plt.rcParams.update(params)

    ps = cs.emptyClass()
    ps.color = None
    ps.markerSize = 3
    ps.marker = 'o'
    ps.legStr = meas
    if meas == 'z_t':
        ps.legStr = 'Z_Target'
    ps.linestyle = 'solid'
    ps.titleStr = ('Resistors (Ohm): R1 = %.1f, R2 = %.1f, R3 = %.1f, '
                   'R4 = %.0f. Capacitor: C = %.0f mF. '
                   'Z_Target is the parallel impedance of R4 and C.'
                   % (ci.r1, ci.r2, ci.r3, ci.r4, ci.c*10**3))
    ps.titleWrap = 75
    ps.titleBool = True
    ps.xLabel = 'Frequency (Hz)'
    if plotThis == 'zPhase':
        ps.yLabel = 'Voltage Phase Shift from Transmit Current (mrad)'
    elif plotThis == 'zMag':
        ps.yLabel = 'Voltage Magnitude (mV)'
    ps.legOutside = False

    # Plot the main result.
    lines2D = plt.plot(freqList, result, color=ps.color,
                       markersize=ps.markerSize,
                       marker=ps.marker, label=ps.legStr,
                       linestyle=ps.linestyle)

    titleStr = ps.titleStr
    if ps.titleWrap < sp.inf:
        # Wrap text at a set character length.
        titleStr = '\n'.join(wrap(titleStr, ps.titleWrap))
    if ps.titleBool:
        plt.title(titleStr)
    plt.xlabel(ps.xLabel)
    plt.ylabel(ps.yLabel)
    if ps.legOutside:
        plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
        plt.subplots_adjust(right=0.75)
    else:
        plt.legend(loc="best")
        plt.tight_layout()
    plt.grid(b=True)
    plt.show()