예제 #1
0
    def width_at_overlap(self, overlap):
        """
        return the half widths of the ellipse in major axis and
        minor axis direction given a overlap level.

        the relationship between one sigma and the full width maximal can be
        found in this link

        https://en.wikipedia.org/wiki/Full_width_at_half_maximum
        2.*np.sqrt(2.*np.log(2)) = 2.3548200450309493
        """
        sigmaH = self.axisH * (2. / 2.3548200450309493)
        sigmaV = self.axisV * (2. / 2.3548200450309493)

        widthH = normInverse(overlap, 0, sigmaH)
        widthV = normInverse(overlap, 0, sigmaV)

        return widthH, widthV
예제 #2
0
def calculateBeamOverlaps(ellipseCenters, radius, majorAxis, minorAxis,
                          rotation, overlap, mode):
    def RotatedGaussian2DPDF(x, y, xMean, yMean, xSigma, ySigma, angle):
        angle = -(angle - np.pi)
        a = np.power(np.cos(angle), 2) / (2 * xSigma**2) + np.power(
            np.sin(angle), 2) / (2 * ySigma**2)
        b = -np.sin(2 * angle) / (4 * xSigma**2) + np.sin(
            2 * angle) / (4 * ySigma**2)
        c = np.power(np.sin(angle), 2) / (2 * xSigma**2) + np.power(
            np.cos(angle), 2) / (2 * ySigma**2)

        return np.exp(-(a * np.power(x - xMean, 2) + 2 * b * (x - xMean) *
                        (y - yMean) + c * np.power(y - yMean, 2)))

    def isInsideEllips(center, majorAxis, minorAxis, rotation, testPointX,
                       testPointY):

        xOffset = testPointX - center[0]
        yOffset = testPointY - center[1]
        cosa = np.cos(rotation)
        sina = np.sin(rotation)
        # majorSquare = np.power(majorAxis,2)
        # minorSquare = np.power(minorAxis,2)

        result = np.power((cosa*xOffset + sina*yOffset)/majorAxis,2) +\
                 np.power((sina*xOffset - cosa*yOffset)/minorAxis,2)

        # result = 1/majorAxis**2 * ((testPointX - center[0])*np.cos(rotation) +\
        # (testPointY - center[1])*np.sin(rotation))**2 +\
        # 1/minorAxis**2 * ((testPointX - center[0])*np.sin(rotation) -\
        # (testPointY - center[1])*np.cos(rotation))**2
        return result

    if mode == "counter":
        mode = 1
    elif mode == "heater":
        mode = 2
    elif mode == "both":
        mode = 3

    rotation = np.deg2rad(rotation)
    # rotated = 0/(3600*24.) * 2 * np.pi
    # rotation += rotated
    longAxis = majorAxis if majorAxis > minorAxis else minorAxis
    gridNum = 1000
    # print 0.3*radius, longAxis
    # halfSidelength = 0.15 * radius
    halfSidelength = longAxis * 3.
    offsetCenter = [radius, radius]
    # np.savetxt('tmp/oldcenter', ellipseCenters)
    ellipseCenters = ellipseCenters + offsetCenter
    # np.savetxt('tmp/newcenter', ellipseCenters)
    innerEllipses = []
    for ellipseCenter in ellipseCenters:
        if (ellipseCenter[0] > (offsetCenter[0]-halfSidelength) and\
            ellipseCenter[0] < (offsetCenter[0]+halfSidelength)) and\
           (ellipseCenter[1] > (offsetCenter[1]-halfSidelength) and\
            ellipseCenter[1] < (offsetCenter[1]+halfSidelength)):
            innerEllipses.append(ellipseCenter)
    paddingRatio = 2 * longAxis / halfSidelength
    halfSidelength *= 1 + paddingRatio
    # np.savetxt('tmp/innercenter', innerEllipses)
    # step = 2*halfSidelength/gridNum
    width = longAxis * 2
    squareEdgeX = [
        offsetCenter[0] - halfSidelength, offsetCenter[0] + halfSidelength
    ]
    squareEdgeY = [
        offsetCenter[1] - halfSidelength, offsetCenter[1] + halfSidelength
    ]
    # print squareEdgeX, squareEdgeY

    # grids = np.mgrid[squareEdgeY[0]:squareEdgeY[1]:step, squareEdgeX[0]:squareEdgeX[1]:step]

    grids = np.meshgrid(np.linspace(squareEdgeX[0], squareEdgeX[1], gridNum),
                        np.linspace(squareEdgeX[1], squareEdgeX[0], gridNum))

    # nopoint = []
    # gridLength = grids.shape[1]
    gridLength = gridNum
    overlapCounter = np.zeros((gridLength, gridLength))
    overlapHeater = np.zeros((gridLength, gridLength))
    # overlapCounter = np.full((gridLength, gridLength), np.inf)
    sigmaH, sigmaV = majorAxis * (2. / 2.3556), minorAxis * (2. / 2.3556)
    widthH = normInverse(overlap, 0, sigmaH)
    widthV = normInverse(overlap, 0, sigmaV)

    for ellipseCenter in innerEllipses:
        horizontalBoarder = [
            ellipseCenter[0] - width, ellipseCenter[0] + width
        ]
        verticalBoarder = [ellipseCenter[1] - width, ellipseCenter[1] + width]

        horizontalIndex = np.round([(horizontalBoarder[0] - squareEdgeX[0]) /
                                    (2.0 * halfSidelength) * gridNum,
                                    (horizontalBoarder[1] - squareEdgeX[0]) /
                                    (2.0 * halfSidelength) * gridNum
                                    ]).astype(int)
        verticalIndex = gridNum - np.round(
            [(verticalBoarder[0] - squareEdgeY[0]) /
             (2.0 * halfSidelength) * gridNum,
             (verticalBoarder[1] - squareEdgeY[0]) /
             (2.0 * halfSidelength) * gridNum]).astype(int)
        # print verticalIndex, horizontalIndex
        insideThisBorder = np.s_[verticalIndex[1]:verticalIndex[0],
                                 horizontalIndex[0]:horizontalIndex[1]]
        gridX = grids[0][insideThisBorder]
        gridY = grids[1][insideThisBorder]

        #heat
        if mode == 2 or mode == 3:
            probability = RotatedGaussian2DPDF(gridX, gridY, ellipseCenter[0],
                                               ellipseCenter[1], sigmaH,
                                               sigmaV, rotation)

            probabilityMask = (overlapHeater[insideThisBorder] < probability)
            overlapHeater[insideThisBorder][probabilityMask] = probability[
                probabilityMask]

        #counter
        if mode == 1 or mode == 3:
            counts = isInsideEllips(ellipseCenter, widthH, widthV, rotation,
                                    gridX, gridY)
            countMask = counts < 1
            counts[countMask] = 1
            counts[~countMask] = 0
            overlapCounter[insideThisBorder] += counts

        # print ellipseCenter, majorAxis, minorAxis, rotation
        # np.save('tmp/grid', [gridX, gridY])
        # np.savetxt('tmp/pointm', result)
        # exit(0)
        # if np.amin(result) > 1.:
        # np.savetxt('tmp/grid', [gridX,gridY])
        # print ellipseCenter
        # exit()
        # print len(gridX)
        # print result[result<1]
        # print len(gridY), np.amin(result), result[result<1]
    # np.savetxt('tmp/nopoint', nopoint)
    trimmedGridLength = int(np.round(gridLength / (1 + 2 * paddingRatio)))
    halfPaddingCount = int(np.round((gridLength - trimmedGridLength) / 2.))
    overlapCounter = overlapCounter[halfPaddingCount:-halfPaddingCount,
                                    halfPaddingCount:-halfPaddingCount]
    overlapHeater = overlapHeater[halfPaddingCount:-halfPaddingCount,
                                  halfPaddingCount:-halfPaddingCount]
    # print np.count_nonzero(overlapCounter > 1), np.count_nonzero(overlapCounter == 1), np.count_nonzero(overlapCounter == 0)

    # unique, counts = np.unique(overlapCounter, return_counts=True)
    # print dict(zip(unique, counts))

    if mode == 1:
        return overlapCounter
    elif mode == 2:
        return overlapHeater
    elif mode == 3:
        return overlapCounter, overlapHeater
예제 #3
0
        values = np.exp(-(a * xMinusxMean**2 + 2 * b * (xMinusxMean) *
                          (yMinusyMean) + c * yMinusyMean**2))
        return values

    yData = image
    dataShape = yData.shape

    X, Y = np.meshgrid(np.linspace(0, dataShape[0] - 1, dataShape[0]),
                       np.linspace(0, dataShape[1] - 1, dataShape[1]))

    X = X[yData != 0]
    Y = Y[yData != 0]
    yData = yData[yData != 0]

    initial_guess = (dataShape[1] / 2, dataShape[0] / 2, 160, 160, 0)

    # paras_bounds = ([300, 300, 10, 10, -2*np.inf], [500, 500, dataShape[0], dataShape[0], 2*np.inf])
    paras_bounds = ([360, 360, 10, 10, -2 * np.inf],
                    [440, 440, dataShape[0], dataShape[0], 2 * np.inf])
    popt, pcov = curve_fit(RotatedGaussian2DPDF, (X, Y),
                           yData,
                           p0=initial_guess,
                           bounds=paras_bounds)

    centerX, centerY, sigmaH, sigmaV, angle = popt

    widthH = normInverse(0.5, 0, sigmaH)
    widthV = normInverse(0.5, 0, sigmaV)

    return widthH, widthV, angle
예제 #4
0
    def createContour(self, antennas, fileName=None, minAlt=0):


        self.array = coord.Array("main", antennas, self.arrayReferece)

        self.baselines = self.array.getBaselines()

        self.boresight = coord.Boresight("main", self.boresightCoord, self.observeTime,
                self.arrayReferece, self.boresightFrame)

        self.projectedBaselines = self.array.getRotatedProjectedBaselines(self.boresight)
        rotatedProjectedBaselines = self.projectedBaselines

        beamMajorAxisScale, beamMinorAxisScale = self.calculateBeamScaleFromBaselines(
                self.projectedBaselines, self.waveLength)
        # print self.waveLength, beamMinorAxisScale
        baselineMax = 1.22*self.waveLength/(beamMinorAxisScale*2)

        baselineNum = len(self.baselines)
        density = self.imageDensity
        gridNum = self.gridNumOfDFT
        imageLength = gridNum * self.resolution

        sidelength = density * self.beamSizeFactor
        windowLength = self.resolution * sidelength

        if baselineNum > 2 and self.autoZoom == True:
            axisRatio = beamMajorAxisScale/beamMinorAxisScale
            newBeamSizeFactor = axisRatio * beamMajorAxisScale*2*1.3 / (self.resolution * density)
            # print newBeamSizeFactor,
            if baselineMax > 2e3:
                logger.debug('larger')
                # print 'larger'
                newBeamSizeFactor = 6 if newBeamSizeFactor < 6 else int(round(newBeamSizeFactor))
            else:
                # print 'smaller', newBeamSizeFactor
                logger.debug('smaller')
                if newBeamSizeFactor > 6:
                    newBeamSizeFactor = 6
                elif newBeamSizeFactor > 1.:
                    newBeamSizeFactor = int(round(newBeamSizeFactor))
                else:
                    newBeamSizeFactor = 1

            # if newBeamSizeFactor < 3:
                # newBeamSizeFactor = 3 if baselineMax < 1e3 else 6
            # elif newBeamSizeFactor > 12:
                # newBeamSizeFactor = 10 if baselineMax < 1e3 else 20
            # else:
                # newBeamSizeFactor = int(round(newBeamSizeFactor))

            # print newBeamSizeFactor,
            # print newBeamSizeFactor
            self.setBeamSizeFactor(newBeamSizeFactor)

            sidelength = density * self.beamSizeFactor
            windowLength = self.resolution * sidelength
            imageLength = gridNum * self.resolution

            image = self.partialDFT(self.partialDFTGrid, rotatedProjectedBaselines,
                    self.waveLength, imageLength, density, gridNum)

            #if fileName != None:
            #    plotBeamContour(image, (0,0), windowLength,
            #        interpolation = self.interpolating, fileName='contourTest.png')

            sizeInfo = calculateBeamSize(image, density, windowLength, np.rad2deg(beamMajorAxisScale))
            # self.beamAxis = [sizeInfo[0], sizeInfo[1], sizeInfo[2]]
            # print sizeInfo[3]
            if sizeInfo[3] != 0:
                sigmaTest = normSigma(windowLength/2., 0, sizeInfo[3])
                majorAxis = normInverse(0.4, 0, sigmaTest)
                # majorAxis =  beamMajorAxisScale / (sizeInfo[3]/0.5)
            else:
                majorAxis, minorAxis, angle = sizeInfo[0], sizeInfo[1], sizeInfo[2]
            # print np.deg2rad(majorAxis), beamMajorAxisScale
            newBeamSizeFactor = 2*majorAxis*1.7 / (self.resolution *  density)
            # print newBeamSizeFactor
            overstep = sizeInfo[3]
            if overstep != 0:
                newBeamSizeFactor += 3.5
            # print newBeamSizeFactor
            # print majorAxis, minorAxis, angle
            if newBeamSizeFactor < 1.:
                sidelength = density * newBeamSizeFactor
                windowLength = self.resolution * sidelength
                if windowLength / (2.*majorAxis*1.4) < 1.1:
                    newBeamSizeFactor = 2
                else:
                    newBeamSizeFactor = 1
            else:
                newBeamSizeFactor = int(round(newBeamSizeFactor))
            self.setBeamSizeFactor(newBeamSizeFactor)
            # imageLength = self.calculateImageLength(rotatedProjectedBaselines,
                # self.waveLength, self.beamSizeFactor, density, gridNum, fixRange=width)


            image = self.partialDFT(self.partialDFTGrid, rotatedProjectedBaselines,
                    self.waveLength, imageLength, density, gridNum)

        else:
            image = self.partialDFT(self.partialDFTGrid, rotatedProjectedBaselines,
                    self.waveLength, imageLength, density, gridNum)

        # image_height, image_width = image.shape
        # image_grid = np.mgrid(-image_height/2., image_height/2., 1)
        # pixel_coordinates = np.stack((image_grid[0], vert_grid), axis= -1)
        # print pixel_coordinates.shape

        sidelength = density * self.beamSizeFactor
        windowLength = self.resolution * sidelength

        self.imageLength = windowLength

        upper_left_pixel = [-windowLength/2., windowLength/2.] # x,y
        bottom_right_pixel = [windowLength/2., -windowLength/2.] # x,y

        coordinates_equatorial = coord.convert_pixel_coordinate_to_equatorial(
            [upper_left_pixel, bottom_right_pixel], self.boresight.equatorial)
        equatorial_range = [coordinates_equatorial[0][0], coordinates_equatorial[1][0], # left, right
                            coordinates_equatorial[0][1], coordinates_equatorial[1][1]] # up, bottom

        self.beamAxis = [None, None, None, equatorial_range]
        self.constructFitsHeader(density, self.resolution*self.beamSizeFactor, self.boresight.equatorial)

        self.psf = PointSpreadFunction(image, self.boresight,
                windowLength, self.WCS, equatorial_range)

        if fileName is not None:
            plotBeamContour(image, self.boresight.equatorial, equatorial_range,
                    interpolation = self.interpolating, fileName = fileName)

        # if baselineNum > 2:
            # resolution = windowLength/density
            # sizeInfo = calculateBeamSize(image, density, windowLength, beamMajorAxisScale, fit=True)
            # if sizeInfo[3] != 0:
                # elevation = np.rad2deg(self.boresight.horizontal[1])
                # if abs(elevation) < 20.:
                    # logger.warning("Elevation is low %f" % elevation)
                # logger.warning("Beam shape probably is not correct.")
            # self.beamAxis[0:3] = [sizeInfo[0], sizeInfo[1], sizeInfo[2]]

        self.imageData = image
        logger.info("beamshape simulation imputs, freq: {:.5g}, source: {}, "
                    "time: {}, subarray: {}".format(299792458./self.waveLength,
                        self.boresightInput, self.observeTime,
                        [ant.name for ant in antennas]))
        return image