def get_flat_top(shot=54196, times=None, smooth_dt = None, maxddw = None, hold=0, debug=0):
    """ debug=1 gives a plot
    """
    if times==None: times=np.linspace(0.02,8,8020) ;  
    from pyfusion.data.signal_processing import smooth

    bp=get_basic_diagnostics(shot=shot,diags=['w_p','dw_pdt','b_0'],times=times)
    # assume sign is OK - at the moment, the code to fix sign is in merge
    # but it is inactive.  Probably should be in get_basic_diag..
    # so far, it seems that w_p and i_p are corrected - not sure 
    # about other flux loops.
    w_p = bp['w_p']
    dw = bp['dw_pdt']
    w=np.where(w_p < 1e6)[0]  # I guess this is to exclude nans
    len(w)
    cent = np.sum(w_p[w]*times[w])/np.sum(w_p[w])
    icent = np.where(times > cent)[0][0]
    print("centroid = {0:.1f}".format(cent))
    if maxddw == None: maxddw = 100
    if smooth_dt==None: smooth_dt = 0.1 # smooth for 0.05 sec
    dt = (times[1]-times[0])
    ns = int(smooth_dt/dt)
    smootharr = [ns,ns,ns]
    offs = len(smootharr*ns)  # correction for smoothing offset
    dwsm = smooth(dw,n_smooth=smootharr)  # smooth dwdt
    ddw = np.diff(dwsm)/dt  #second deriv
    # work away from the centroid until 2nd deriv exceeds maxddw
    # assume 100kJ /sec is ramp, and a change of this over a second

    wb = int(0.5*offs) + np.nanargmax(dwsm)
    we = int(0.1*offs) + np.nanargmin(dwsm) # 
    wpmax = np.nanmax(w_p)
    # used to be maxddw - too restrictive now try dwsm
    wgtrev = np.where(np.abs(dwsm[icent-offs/2::-1])> maxddw*wpmax/100)[0]
    wgtfor = np.where(np.abs(dwsm[icent-offs/2:])> maxddw*wpmax/100)[0]
    if (len(wgtrev) < 10) or (len(wgtfor) < 10): 
        print('*** flat_top not found on shot {s}'.format(s=shot))
        return (0,0,(0,0,0,0,0))

    wbf = icent - wgtrev[0]
    wef = icent + wgtfor[0]
    if debug>0:
        pl.plot(w_p,label='w_p',hold=hold)
        pl.plot(ddw,label='ddw')
        pl.plot(dwsm,linewidth=3,label='sm(dw)')
        pl.plot(dw/10,label='dw_pdt/10')
        pl.scatter([wb, wbf, icent, wef, we],[0,200,300,250,275])
        pl.plot([wb,we],[0,0],label='b--e')
        pl.plot([wbf,wef],np.ones(2)*maxddw*wpmax/100,'o-',linewidth=2,label='bf-ef')
        pl.ylim(np.array([-1.1,1.1])*max(abs(dwsm)))
        pl.title(shot)
        pl.legend()
    debug_(max(pyfusion.DEBUG, debug),2, key='flat_top')
    #return(times[wb], times[we],(wb,we,wbf,wef,icent)) # used to ignore wbf,wef
    return(times[wbf], times[wef],(wb,we,wbf,wef,icent))
Example #2
0
def get_flat_top(shot=54196,
                 times=None,
                 smooth_dt=None,
                 maxddw=None,
                 hold=0,
                 debug=0):
    if times is None: times = np.linspace(0.02, 8, 8020)
    from pyfusion.data.signal_processing import smooth

    bp = get_basic_params(shot=shot,
                          diags=['w_p', 'dw_pdt', 'b_0'],
                          times=times)
    # assume get_basic corrects the sign
    w_p = bp['w_p']
    dw = bp['dw_pdt']
    w = np.where(w_p < 1e6)[0]
    len(w)
    cent = np.sum(w_p[w] * times[w]) / np.sum(w_p[w])
    icent = np.where(times > cent)[0][0]
    print("centroid = {0:.1f}".format(cent))
    if maxddw is None: maxddw = 100
    if smooth_dt is None: smooth_dt = 0.1  # smooth for 0.05 sec
    dt = (times[1] - times[0])
    ns = int(smooth_dt / dt)
    smootharr = [ns, ns, ns]
    offs = len(smootharr * ns)
    dwsm = smooth(dw, n_smooth=smootharr)
    ddw = np.diff(dwsm) / dt
    # work away from the centroid until 2nd deriv exceeds maxddw
    # assume 100kJ /sec is ramp, and a chage of this over a second

    wb = int(0.5 * offs) + np.nanargmax(dwsm)
    we = int(0.1 * offs) + np.nanargmin(dwsm)  #
    wbf = offs + np.where(np.abs(ddw[0:icent]) > maxddw)[0][-1]
    wef = offs + icent + np.where(np.abs(ddw[icent:]) > maxddw)[0][0]
    if debug > 0:
        pl.plot(w_p, label='w_p', hold=hold)
        pl.plot(dwsm, label='sm(dw)')
        pl.plot(ddw / 10, label='ddw/10')
        pl.plot(dw, label='dw_pdt)')
        pl.scatter([wb, wbf, icent, wef, we], [0, 500, 1000, 1500, 2000])
        pl.plot([wb, we], [0, 0], label='b--e')
        pl.ylim(array([-1.1, 1.1]) * max(abs(dwsm)))
        pl.title(shot)
        pl.legend()
    debug_(max(pyfusion.DEBUG, debug), key='flat_top')
    return (times[wb], times[we], (wb, we, wbf, wef, icent))
Example #3
0
def get_flat_top(shot=54196, times=None, smooth_dt = None, maxddw = None, hold=0, debug=0):
    if times is None: times=np.linspace(0.02,8,8020) ;  
    from pyfusion.data.signal_processing import smooth

    bp=get_basic_params(shot=shot,diags=['w_p','dw_pdt','b_0'],times=times)
    # assume get_basic corrects the sign
    w_p = bp['w_p']
    dw = bp['dw_pdt']
    w=np.where(w_p < 1e6)[0]
    len(w)
    cent = np.sum(w_p[w]*times[w])/np.sum(w_p[w])
    icent = np.where(times > cent)[0][0]
    print("centroid = {0:.1f}".format(cent))
    if maxddw is None: maxddw = 100
    if smooth_dt is None: smooth_dt = 0.1 # smooth for 0.05 sec
    dt = (times[1]-times[0])
    ns = int(smooth_dt/dt)
    smootharr = [ns,ns,ns]
    offs = len(smootharr*ns)
    dwsm = smooth(dw,n_smooth=smootharr)
    ddw = np.diff(dwsm)/dt
    # work away from the centroid until 2nd deriv exceeds maxddw
    # assume 100kJ /sec is ramp, and a chage of this over a second

    wb = int(0.5*offs) + np.nanargmax(dwsm)
    we = int(0.1*offs) + np.nanargmin(dwsm) # 
    wbf = offs + np.where(np.abs(ddw[0:icent])> maxddw)[0][-1]
    wef = offs + icent + np.where(np.abs(ddw[icent:])> maxddw)[0][0]
    if debug>0:
        pl.plot(w_p,label='w_p',hold=hold)
        pl.plot(dwsm,label='sm(dw)')
        pl.plot(ddw/10,label='ddw/10')
        pl.plot(dw,label='dw_pdt)')
        pl.scatter([wb, wbf, icent, wef, we],[0,500,1000,1500,2000])
        pl.plot([wb,we],[0,0],label='b--e')
        pl.ylim(array([-1.1,1.1])*max(abs(dwsm)))
        pl.title(shot)
        pl.legend()
    debug_(max(pyfusion.DEBUG, debug), key='flat_top')
    return(times[wb], times[we],(wb,we,wbf,wef,icent))
Example #4
0
def restore_sin(data, t_range=None, chan=None, method=2, sweep_freq= 500, Vpp=90*2, clip_level_minus=-88, verbose=1):
    """ Restore the clipped part of the sinusoid - see
    examples/restore_sin for the old script version

    sweep_freq:        sinusoidal sweep freq in Hz
    Vpp:               pp value of signal before it was clipped 
    clip_level_minus:  value to ensure even soft clipping is excluded
    method:            so far only 2
    """ 
    if t_range is not None:
        rd = data.reduce_time(t_range)
    else:
        rd = data.copy()  # so fudge below will work

    # a big fudge to allow this to work on one channel!!! beware
    if chan is not None:
        rd.signal = rd.signal[chan]
        rd.channels = rd.channels[chan]

    if verbose>0:
        rd.plot_signals()
    # fourier filter to retain the fundamental - the amplitude with be reduced by the clipping
    stopband = sweep_freq * np.array([0.8,1.2])
    passband = sweep_freq * np.array([0.9,1.1])
    fd = rd.filter_fourier_bandpass(stopband=stopband,passband=passband)

    # calculate the time-varying amplitude of the filtered sinusoid
    amp = np.abs(analytic_signal(fd.signal))/np.sqrt(2)
    # normalise to one
    amp = amp/np.average(amp)
    if verbose > 0:
        fig, ax1 = plt.subplots(1, 1)
    if verbose > 0:
        ax1.plot(rd.timebase, rd.signal, 'b', label='orig', linewidth=.3)
    if verbose > 1:
        ax1.plot(rd.timebase, fd.signal, 'g', label='filtered', linewidth=.3)
    if method == 1:
        ax1.plot(rd.timebase, fd.signal/amp, 'm', label='corrected', linewidth=.3)
        ax1.plot(rd.timebase, 50*(1.3*amp-2.1) + 1.2*fd.signal/amp, 'r', label='corrected')

    # not bad, but try making the amplitude constant first, then take the
    # difference , excluding the clipped part, boxcar averaged over a
    # small, whole number of periods

    for i in range(2):  # iterate to restore amplitude to a constant
        # first the reconstructed amplitude
        reconst = 1.0 * fd.signal  # make a copy of the signal
        amprec = np.abs(analytic_signal(reconst))
        reconst = Vpp/2.0 * reconst/amprec
    if method == 2:
        if verbose > 0:
            ax1.plot(rd.timebase, reconst, 'm', label='reconst before DC adjust')

    # should have a very nice constant ampl. sinusoid
    # now blank out the clipped, use given value because amplifier clipping
    # is 'soft', so automatic detection of clipping is not simple.
    wc = np.where(rd.signal < clip_level_minus)[0]
    weight = 1 + 0*reconst
    weight[wc] = 0
    period = int(round(data.timebase.sample_freq/sweep_freq))
    from pyfusion.data.signal_processing import smooth
    # iterate to make waves match where there is no clipping
    for i in range(6):
        err = rd.signal - reconst
        err[wc] = 0
        if verbose > 0:
            print('average error {e:.3g}'.format(e=float(np.sum(err)/np.sum(weight))))
        corrn = np.cumsum(err[0:-period]) - np.cumsum(err[period:])
        divisor = np.cumsum(weight[0:-period]) - np.cumsum(weight[period:]) 
        wnef = np.where(divisor <= 100)[0]
        divisor[wnef] = 100
        if verbose > 1:
            ax1.plot(rd.timebase, reconst, '--',
                     label='reconst, offset {i}'.format(i=i))
        # reconst[period//2:-period//2] = reconst[period//2:-period//2] - corrn/divisor
        reconst[period//2:1-period//2] = reconst[period//2:1-period//2] + smooth(err,period)/smooth(weight,period)
        # plot(smooth(err,period)/smooth(weight,period))

        debug_(pyfusion.DEBUG, 1, key='restore_sin')

    if verbose>0:
        ax1.plot(rd.timebase, reconst,'r', label='reconst, final offset')
        ax1.legend()
        fig.show()
    return(reconst)
Example #5
0
weight[wc] = 0
period = 1000
from pyfusion.data.signal_processing import smooth
# iterate to make waves match where there is no clipping
for i in range(6):
    err = rd.signal[0] - reconst
    err[wc] = 0
    print(sum(err) / sum(weight))
    corrn = np.cumsum(err[0:-period]) - np.cumsum(err[period:])
    divisor = np.cumsum(weight[0:-period]) - np.cumsum(weight[period:])
    wnef = np.where(divisor <= 100)[0]
    divisor[wnef] = 100
    if verbose > 1:
        ax1.plot(rd.timebase,
                 reconst,
                 '--',
                 label='reconst, offset {i}'.format(i=i))
    # reconst[period//2:-period//2] = reconst[period//2:-period//2] - corrn/divisor
    reconst[period // 2:1 -
            period // 2] = reconst[period // 2:1 - period // 2] + smooth(
                err, period) / smooth(weight, period)
    # plot(smooth(err,period)/smooth(weight,period))

    debug_(pyfusion.DEBUG, 1, key='restore_sin')
if method == 2:
    if verbose > 0:
        ax1.plot(rd.timebase, reconst, 'r', label='reconst, final offset')

ax1.legend()
fig.show()
Example #6
0
def get_flat_top(shot=54196,
                 times=None,
                 smooth_dt=None,
                 maxddw=None,
                 hold=0,
                 debug=0):
    """ debug=1 gives a plot
    """
    if times is None: times = np.linspace(0.02, 8, 8020)
    from pyfusion.data.signal_processing import smooth

    bp = get_basic_diagnostics(shot=shot,
                               diags=['w_p', 'dw_pdt', 'b_0'],
                               times=times)
    # assume sign is OK - at the moment, the code to fix sign is in merge
    # but it is inactive.  Probably should be in get_basic_diag..
    # so far, it seems that w_p and i_p are corrected - not sure
    # about other flux loops.
    w_p = bp['w_p']
    dw = bp['dw_pdt']
    w = np.where(w_p < 1e6)[0]  # I guess this is to exclude nans
    len(w)
    cent = np.sum(w_p[w] * times[w]) / np.sum(w_p[w])
    icent = np.where(times > cent)[0][0]
    print("centroid = {0:.1f}".format(cent))
    if maxddw is None: maxddw = 100
    if smooth_dt is None: smooth_dt = 0.1  # smooth for 0.05 sec
    dt = (times[1] - times[0])
    ns = int(smooth_dt / dt)
    smootharr = [ns, ns, ns]
    offs = len(smootharr * ns)  # correction for smoothing offset
    dwsm = smooth(dw, n_smooth=smootharr)  # smooth dwdt
    ddw = np.diff(dwsm) / dt  #second deriv
    # work away from the centroid until 2nd deriv exceeds maxddw
    # assume 100kJ /sec is ramp, and a change of this over a second

    wb = int(0.5 * offs) + np.nanargmax(dwsm)
    we = int(0.1 * offs) + np.nanargmin(dwsm)  #
    wpmax = np.nanmax(w_p)
    # used to be maxddw - too restrictive now try dwsm
    wgtrev = np.where(
        np.abs(dwsm[icent - offs / 2::-1]) > maxddw * wpmax / 100)[0]
    wgtfor = np.where(
        np.abs(dwsm[icent - offs / 2:]) > maxddw * wpmax / 100)[0]
    if (len(wgtrev) < 10) or (len(wgtfor) < 10):
        print('*** flat_top not found on shot {s}'.format(s=shot))
        return (0, 0, (0, 0, 0, 0, 0))

    wbf = icent - wgtrev[0]
    wef = icent + wgtfor[0]
    if debug > 0:
        pl.plot(w_p, label='w_p', hold=hold)
        pl.plot(ddw, label='ddw')
        pl.plot(dwsm, linewidth=3, label='sm(dw)')
        pl.plot(dw / 10, label='dw_pdt/10')
        pl.scatter([wb, wbf, icent, wef, we], [0, 200, 300, 250, 275])
        pl.plot([wb, we], [0, 0], label='b--e')
        pl.plot([wbf, wef],
                np.ones(2) * maxddw * wpmax / 100,
                'o-',
                linewidth=2,
                label='bf-ef')
        pl.ylim(np.array([-1.1, 1.1]) * max(abs(dwsm)))
        pl.title(shot)
        pl.legend()
    debug_(max(pyfusion.DBG(), debug), 2, key='flat_top')
    #return(times[wb], times[we],(wb,we,wbf,wef,icent)) # used to ignore wbf,wef
    return (times[wbf], times[wef], (wb, we, wbf, wef, icent))
Example #7
0
def restore_sin(data,
                t_range=None,
                chan=None,
                method=2,
                sweep_freq=500,
                Vpp=90 * 2,
                clip_level_minus=-88,
                verbose=1):
    """ Restore the clipped part of the sinusoid - see
    examples/restore_sin for the old script version

    sweep_freq:        sinusoidal sweep freq in Hz
    Vpp:               pp value of signal before it was clipped 
    clip_level_minus:  value to ensure even soft clipping is excluded
    method:            so far only 2
    """
    if t_range is not None:
        rd = data.reduce_time(t_range)
    else:
        rd = data.copy()  # so fudge below will work

    # a big fudge to allow this to work on one channel!!! beware
    if chan is not None:
        rd.signal = rd.signal[chan]
        rd.channels = rd.channels[chan]

    if verbose > 0:
        rd.plot_signals()
    # fourier filter to retain the fundamental - the amplitude with be reduced by the clipping
    stopband = sweep_freq * np.array([0.8, 1.2])
    passband = sweep_freq * np.array([0.9, 1.1])
    fd = rd.filter_fourier_bandpass(stopband=stopband, passband=passband)

    # calculate the time-varying amplitude of the filtered sinusoid
    amp = np.abs(analytic_signal(fd.signal)) / np.sqrt(2)
    # normalise to one
    amp = amp / np.average(amp)
    if verbose > 0:
        fig, ax1 = plt.subplots(1, 1)
    if verbose > 0:
        ax1.plot(rd.timebase, rd.signal, 'b', label='orig', linewidth=.3)
    if verbose > 1:
        ax1.plot(rd.timebase, fd.signal, 'g', label='filtered', linewidth=.3)
    if method == 1:
        ax1.plot(rd.timebase,
                 fd.signal / amp,
                 'm',
                 label='corrected',
                 linewidth=.3)
        ax1.plot(rd.timebase,
                 50 * (1.3 * amp - 2.1) + 1.2 * fd.signal / amp,
                 'r',
                 label='corrected')

    # not bad, but try making the amplitude constant first, then take the
    # difference , excluding the clipped part, boxcar averaged over a
    # small, whole number of periods

    for i in range(2):  # iterate to restore amplitude to a constant
        # first the reconstructed amplitude
        reconst = 1.0 * fd.signal  # make a copy of the signal
        amprec = np.abs(analytic_signal(reconst))
        reconst = Vpp / 2.0 * reconst / amprec
    if method == 2:
        if verbose > 0:
            ax1.plot(rd.timebase,
                     reconst,
                     'm',
                     label='reconst before DC adjust')

    # should have a very nice constant ampl. sinusoid
    # now blank out the clipped, use given value because amplifier clipping
    # is 'soft', so automatic detection of clipping is not simple.
    wc = np.where(rd.signal < clip_level_minus)[0]
    weight = 1 + 0 * reconst
    weight[wc] = 0
    period = int(round(data.timebase.sample_freq / sweep_freq))
    from pyfusion.data.signal_processing import smooth
    # iterate to make waves match where there is no clipping
    for i in range(6):
        err = rd.signal - reconst
        err[wc] = 0
        if verbose > 0:
            print('average error {e:.3g}'.format(
                e=float(np.sum(err) / np.sum(weight))))
        corrn = np.cumsum(err[0:-period]) - np.cumsum(err[period:])
        divisor = np.cumsum(weight[0:-period]) - np.cumsum(weight[period:])
        wnef = np.where(divisor <= 100)[0]
        divisor[wnef] = 100
        if verbose > 1:
            ax1.plot(rd.timebase,
                     reconst,
                     '--',
                     label='reconst, offset {i}'.format(i=i))
        # reconst[period//2:-period//2] = reconst[period//2:-period//2] - corrn/divisor
        reconst[period // 2:1 -
                period // 2] = reconst[period // 2:1 - period // 2] + smooth(
                    err, period) / smooth(weight, period)
        # plot(smooth(err,period)/smooth(weight,period))

        debug_(pyfusion.DEBUG, 1, key='restore_sin')

    if verbose > 0:
        ax1.plot(rd.timebase, reconst, 'r', label='reconst, final offset')
        ax1.legend()
        fig.show()
    return (reconst)
Example #8
0
def find_shot_times(dev, shot, activity_indicator=None, debug=0):
    """ Note: This is inside a try/except - errors will just skip over!! fixme
    From the channel specified in the expression "activity_indicator", determine
    the beginning and end of pulse.  A suitable expression is hard to
    find.  For example, density usually persists too long after the
    shot, and sxrays appear a little late in the shot.  The magnetics
    may be useful if magnet power supply noise could be removed.
    (had trouble with lhd 50628 until adj threshold ?start and end were at 0.5-0.6 secs )
    >>> import pyfusion
    >>> sh=pyfusion.core.get_shot(15043,activity_indicator="MP4")
    >>> print('start=%.3g, end=%.3g' % (sh.pulse_start, sh.pulse_end) )
    start=177, end=218
    >>> sh=pyfusion.core.get_shot(33372,activity_indicator="MP4")
    >>> print('start=%.3g, end=%.3g' % (sh.pulse_start, sh.pulse_end) )
    start=168, end=290
    """

    from pyfusion.data.signal_processing import smooth, smooth_n
    if debug>2: exception = None  # allow all exceptions to crash to debug
    else: exception = Exception

    if activity_indicator=="": 
        if pyfusion.OPT>5: 
            print(str(' No activity indicator connected to shot %d, ' 
                      'please consider implementing one to improve speed' % shot))
        return((pyfusion.settings.SHOT_T_MIN, pyfusion.settings.SHOT_T_MAX))

    diff_method = False
    try:  # if a single channel
        ch = dev.acq.getdata(shot, activity_indicator)

    except exception:
        if pyfusion.VERBOSE>0: print("using default activity indicator")

        if dev.name == 'HeliotronJ': 
            diff_method = True;
            cha = "HeliotronJ_MP3"
            chb = "HeliotronJ_MP1"

        elif dev.name == 'LHD': 
            diff_method = True;
            cha = "MP4"
            chb = "MP6"

    ## Assume the start baseline and the end baselines are different (e.g. MICRO01!)
    
    # for now, we hardwire in activity in MP1
    # later, change this to something like 'rms(pyf_hpn("MP1",2e3,4))>0.1'
    #  note: 15043 is a tricky test (bump at 290) (3v, 5us spike)
    threshold_type = True;
    level_type = False
    # the differential method should be useful for all,
    # but relies on the relative sensititivy of two channels to mains ripple
    # so only implement selectively.

    if not diff_method: 
        sig = ch[activity_indicator]
        timebase = ch.timebase
    else:
        activity_indicator = 'diff('+cha+ '-' +chb + ')'
        
    if level_type:
        n_avg = 10
        n_smooth = n_avg

        csum = cumsum(sig)
        # just the valid bit - signal_processing.smooth() does this better.
        sm_sig = (csum[2*n_smooth:] - csum[n_smooth:-n_smooth])/n_smooth

        maxpp = max(sm_sig)-min(sm_sig)
        threshold = max(0.005, maxpp/20)

    elif threshold_type: 
        n_avg = 300   # ripple is about 3ms (need to make this in phys units)
        n_smooth = n_avg

        if diff_method:
            # subtract two distant probes with similar power supply pickup.
            # distant increases phase diff hence real signal, and PS pickup will reduce if similar levels.
            ch1 = dev.acq.getdata(shot, cha)
            siga=ch1[cha]
            timebase = ch1.timebase
            ch2 = dev.acq.getdata(shot, chb)
            sigb=ch2[chb]
            tb2 = ch2.timebase
            if np.max(np.abs(tb2[0:10] - timebase[0:10]))> 1e-6:
                raise LookupError('timebases of {ca} and {cb} are different: '
                                  '\n {tb1}  \n{tb2}'
                                  .format(ca=cha, cb=chb, 
                                          tb1=timebase[0:10], tb2=tb2[0:10]))
            if pyfusion.VERBOSE>2: print("find_shot_times diff method, ids = %d, %d" % (id(siga), id(sigb)))
            sig = siga-sigb
            sm_sig=sqrt(smooth((sig-smooth(sig,n_smooth,keep=1))**2,n_smooth,keep=1))
            sm_sig[-n_smooth:]=sm_sig[-2*n_smooth:-n_smooth]
            tim=timebase
            threshold = 0.03   # good compromise is 0.02, 200 points, 1st order

        else:
            (inds, LP_sig) = smooth_n(sig,n_smooth,iter=4, indices=True,
                                      timebase=timebase)
            HP_sig = sig[inds] - LP_sig
            (tim,sm_sigsq) = smooth_n(HP_sig*HP_sig,n_smooth,
                                      timebase=timebase[inds])
            sm_sig = sqrt(sm_sigsq)
            threshold = 0.02   # good compromise is 0.02, 1500 points, 4th order

        maxpp = max(sm_sig)-min(sm_sig)

    start_bl = average(sm_sig[0:n_avg])
    end_bl = average(sm_sig[-n_avg:])

# if signal is quiet, but shows a contrast > 5, reduce threshold
    if maxpp < .1 and ((start_bl < maxpp/5) or (end_bl < maxpp/5)):
        threshold = maxpp/3

#    first_inds = (abs(sm_sig-start_bl) > threshold).nonzero()[0]
#    last_inds = (abs(sm_sig-end_bl) > threshold).nonzero()[0]
# New code is impulse proof - feature needs to last longer than one interval n_smooth
    first_inds=(smooth(abs(sm_sig-start_bl) > threshold, 2*n_smooth)>0.7).nonzero()[0]
    last_inds=(smooth(abs(sm_sig-end_bl) > threshold, 2*n_smooth)>0.7).nonzero()[0]
    
    if (debug>0) or pyfusion.VERBOSE>2: 
        fmt="%d: %s, threshold = %.3g, n_smooth=%d,"+\
            "n_avg=%d "
        fmt2="maxpp= %.3g, start_baseline=%.3g, end_baseline=%.3g,"+\
            " threshold=%.3g"
        info1=str(fmt % (shot, activity_indicator, threshold, n_smooth, n_avg))
        info2=str(fmt2 % (maxpp, start_bl, end_bl, threshold))
        print("activity indicator " + info1+'\n'+info2)

    if (debug>0) or (pyfusion.VERBOSE>2):  # plot before possible error signalled
        pl.plot(timebase, sig, 'c')
        pl.plot(tim, sm_sig,'b')
        pl.title('smoothed and raw signals used in finding active time of shot')
        pl.xlabel(info1+'\n'+info2)
        xr=pl.xlim()
        pl.plot([xr[0],mean(xr)], array([1,1])*start_bl)
        pl.plot([mean(xr),xr[1]], array([1,1])*end_bl)

    if len(first_inds) ==0 or  len(last_inds) ==0: 
        raise ValueError(
            'could not threshold the activity channel %s, %d start, %d end inds ' %
            (activity_indicator, len(first_inds), len(last_inds)))

        ## the first n_smooth is a correction for the lass of data in smoothing
        ## the last is a margin of error
        ## (have!) should replace this with actual corresponding time
        #start_time=ch.timebase[max(0,min(first_inds)+n_smooth-n_smooth)]
        #end_time=ch.timebase[min(len(sig)-1,max(last_inds)+
        #                                n_smooth+n_smooth)]
                                     
    start_time = tim[min(first_inds)]
    end_time = tim[max(last_inds)]
    end_time = min(end_time,timebase[-1])  

    if pyfusion.VERBOSE>2: print(end_time, last_inds)

    if (debug>0) or pyfusion.VERBOSE>4: # two crosses mark the endpoints
        pl.plot([start_time,end_time],[start_bl, end_bl], " +k", markersize=20, mew=0.5)
        pl.plot([start_time,end_time],[start_bl, end_bl], " ok", mfc='None', markersize=20, mew=1.5)
        # scatter is "out of date"  - integer width, different conventions and is hidden 
        # underneath plots
        # pl.scatter([start_time,end_time],[start_bl, end_bl], s=100, marker="+", linewidth=2)

    if pyfusion.VERBOSE>0: 
        print("found start time on %d of %.5g, end = %.5g using %s" %
              (shot, start_time, end_time, activity_indicator))

    return(start_time, end_time)
Example #9
0
    dev = pyfusion.getDevice(dev_name)
    try:
        dat = dev.acq.getdata(shot, diag_name)
    except:
        bads.append(shot)
        continue

    if dat.signal[0] > -10 or dat.signal[-1] > -30:
        IPs.append(shot)
        continue

    datr = dat.reduce_time([bl[0], bl[3]], copy=True)
    # first baseline removal to get rise and fall points
    datflat = datr.remove_baseline(baseline=bl)
    tmp_peak = np.max(
        smooth(datflat.signal, n_smooth=.02, timebase=datflat.timebase)[1])
    (filt_tb, filtd) = smooth(datflat.signal,
                              n_smooth=tfilt,
                              timebase=datflat.timebase,
                              causal=0)
    #  find a level where there is only two intersections
    for div in range(100, 1, -1):
        whigh = np.where(filtd > tmp_peak / div)[0]
        if (len(np.unique(np.diff(whigh)))
                == 1) and len(whigh) > len(filtd) // 10:
            method = 'best'
            break
    else:
        method = 'simple'
        if debug > 1:
            raise ValueError("can't find the pulse")
Example #10
0
def find_shot_times(dev, shot, activity_indicator=None, debug=0):
    """ Note: This is inside a try/except - errors will just skip over!! fixme
    From the channel specified in the expression "activity_indicator", determine
    the beginning and end of pulse.  A suitable expression is hard to
    find.  For example, density usually persists too long after the
    shot, and sxrays appear a little late in the shot.  The magnetics
    may be useful if magnet power supply noise could be removed.
    (had trouble with lhd 50628 until adj threshold ?start and end were at 0.5-0.6 secs )
    >>> import pyfusion
    >>> sh=pyfusion.core.get_shot(15043,activity_indicator="MP4")
    >>> print('start=%.3g, end=%.3g' % (sh.pulse_start, sh.pulse_end) )
    start=177, end=218
    >>> sh=pyfusion.core.get_shot(33372,activity_indicator="MP4")
    >>> print('start=%.3g, end=%.3g' % (sh.pulse_start, sh.pulse_end) )
    start=168, end=290
    """

    from pyfusion.data.signal_processing import smooth, smooth_n
    if debug > 2: exception = None  # allow all exceptions to crash to debug
    else: exception = Exception

    if activity_indicator == "":
        if pyfusion.OPT > 5:
            print(
                str(' No activity indicator connected to shot %d, '
                    'please consider implementing one to improve speed' %
                    shot))
        return ((pyfusion.settings.SHOT_T_MIN, pyfusion.settings.SHOT_T_MAX))

    diff_method = False
    try:  # if a single channel
        ch = dev.acq.getdata(shot, activity_indicator)

    except exception:
        if pyfusion.VERBOSE > 0: print("using default activity indicator")

        if dev.name == 'HeliotronJ':
            diff_method = True
            cha = "HeliotronJ_MP3"
            chb = "HeliotronJ_MP1"

        elif dev.name == 'LHD':
            diff_method = True
            cha = "MP4"
            chb = "MP6"

    ## Assume the start baseline and the end baselines are different (e.g. MICRO01!)

    # for now, we hardwire in activity in MP1
    # later, change this to something like 'rms(pyf_hpn("MP1",2e3,4))>0.1'
    #  note: 15043 is a tricky test (bump at 290) (3v, 5us spike)
    threshold_type = True
    level_type = False
    # the differential method should be useful for all,
    # but relies on the relative sensititivy of two channels to mains ripple
    # so only implement selectively.

    if not diff_method:
        sig = ch[activity_indicator]
        timebase = ch.timebase
    else:
        activity_indicator = 'diff(' + cha + '-' + chb + ')'

    if level_type:
        n_avg = 10
        n_smooth = n_avg

        csum = cumsum(sig)
        # just the valid bit - signal_processing.smooth() does this better.
        sm_sig = (csum[2 * n_smooth:] - csum[n_smooth:-n_smooth]) / n_smooth

        maxpp = max(sm_sig) - min(sm_sig)
        threshold = max(0.005, maxpp / 20)

    elif threshold_type:
        n_avg = 300  # ripple is about 3ms (need to make this in phys units)
        n_smooth = n_avg

        if diff_method:
            # subtract two distant probes with similar power supply pickup.
            # distant increases phase diff hence real signal, and PS pickup will reduce if similar levels.
            ch1 = dev.acq.getdata(shot, cha)
            siga = ch1[cha]
            timebase = ch1.timebase
            ch2 = dev.acq.getdata(shot, chb)
            sigb = ch2[chb]
            tb2 = ch2.timebase
            if np.max(np.abs(tb2[0:10] - timebase[0:10])) > 1e-6:
                raise LookupError('timebases of {ca} and {cb} are different: '
                                  '\n {tb1}  \n{tb2}'.format(
                                      ca=cha,
                                      cb=chb,
                                      tb1=timebase[0:10],
                                      tb2=tb2[0:10]))
            if pyfusion.VERBOSE > 2:
                print("find_shot_times diff method, ids = %d, %d" %
                      (id(siga), id(sigb)))
            sig = siga - sigb
            sm_sig = sqrt(
                smooth((sig - smooth(sig, n_smooth, keep=1))**2,
                       n_smooth,
                       keep=1))
            sm_sig[-n_smooth:] = sm_sig[-2 * n_smooth:-n_smooth]
            tim = timebase
            threshold = 0.03  # good compromise is 0.02, 200 points, 1st order

        else:
            (inds, LP_sig) = smooth_n(sig,
                                      n_smooth,
                                      iter=4,
                                      indices=True,
                                      timebase=timebase)
            HP_sig = sig[inds] - LP_sig
            (tim, sm_sigsq) = smooth_n(HP_sig * HP_sig,
                                       n_smooth,
                                       timebase=timebase[inds])
            sm_sig = sqrt(sm_sigsq)
            threshold = 0.02  # good compromise is 0.02, 1500 points, 4th order

        maxpp = max(sm_sig) - min(sm_sig)

    start_bl = average(sm_sig[0:n_avg])
    end_bl = average(sm_sig[-n_avg:])

    # if signal is quiet, but shows a contrast > 5, reduce threshold
    if maxpp < .1 and ((start_bl < maxpp / 5) or (end_bl < maxpp / 5)):
        threshold = maxpp / 3


#    first_inds = (abs(sm_sig-start_bl) > threshold).nonzero()[0]
#    last_inds = (abs(sm_sig-end_bl) > threshold).nonzero()[0]
# New code is impulse proof - feature needs to last longer than one interval n_smooth
    first_inds = (smooth(abs(sm_sig - start_bl) > threshold, 2 * n_smooth) >
                  0.7).nonzero()[0]
    last_inds = (smooth(abs(sm_sig - end_bl) > threshold, 2 * n_smooth) >
                 0.7).nonzero()[0]

    if (debug > 0) or pyfusion.VERBOSE > 2:
        fmt="%d: %s, threshold = %.3g, n_smooth=%d,"+\
            "n_avg=%d "
        fmt2="maxpp= %.3g, start_baseline=%.3g, end_baseline=%.3g,"+\
            " threshold=%.3g"
        info1 = str(fmt %
                    (shot, activity_indicator, threshold, n_smooth, n_avg))
        info2 = str(fmt2 % (maxpp, start_bl, end_bl, threshold))
        print("activity indicator " + info1 + '\n' + info2)

    if (debug > 0) or (pyfusion.VERBOSE >
                       2):  # plot before possible error signalled
        pl.plot(timebase, sig, 'c')
        pl.plot(tim, sm_sig, 'b')
        pl.title(
            'smoothed and raw signals used in finding active time of shot')
        pl.xlabel(info1 + '\n' + info2)
        xr = pl.xlim()
        pl.plot([xr[0], mean(xr)], array([1, 1]) * start_bl)
        pl.plot([mean(xr), xr[1]], array([1, 1]) * end_bl)

    if len(first_inds) == 0 or len(last_inds) == 0:
        raise ValueError(
            'could not threshold the activity channel %s, %d start, %d end inds '
            % (activity_indicator, len(first_inds), len(last_inds)))

        ## the first n_smooth is a correction for the lass of data in smoothing
        ## the last is a margin of error
        ## (have!) should replace this with actual corresponding time
        #start_time=ch.timebase[max(0,min(first_inds)+n_smooth-n_smooth)]
        #end_time=ch.timebase[min(len(sig)-1,max(last_inds)+
        #                                n_smooth+n_smooth)]

    start_time = tim[min(first_inds)]
    end_time = tim[max(last_inds)]
    end_time = min(end_time, timebase[-1])

    if pyfusion.VERBOSE > 2: print(end_time, last_inds)

    if (debug > 0) or pyfusion.VERBOSE > 4:  # two crosses mark the endpoints
        pl.plot([start_time, end_time], [start_bl, end_bl],
                " +k",
                markersize=20,
                mew=0.5)
        pl.plot([start_time, end_time], [start_bl, end_bl],
                " ok",
                mfc='None',
                markersize=20,
                mew=1.5)
        # scatter is "out of date"  - integer width, different conventions and is hidden
        # underneath plots
        # pl.scatter([start_time,end_time],[start_bl, end_bl], s=100, marker="+", linewidth=2)

    if pyfusion.VERBOSE > 0:
        print("found start time on %d of %.5g, end = %.5g using %s" %
              (shot, start_time, end_time, activity_indicator))

    return (start_time, end_time)
Example #11
0
wc = np.where(rd.signal[0] < clip_level_minus)[0]
weight = 1 + 0*reconst
weight[wc] = 0
period = 1000
from pyfusion.data.signal_processing import smooth
# iterate to make waves match where there is no clipping
for i in range(6):
    err = rd.signal[0] - reconst
    err[wc] = 0
    print(sum(err)/sum(weight))
    corrn = np.cumsum(err[0:-period]) - np.cumsum(err[period:])
    divisor = np.cumsum(weight[0:-period]) - np.cumsum(weight[period:]) 
    wnef = np.where(divisor <= 100)[0]
    divisor[wnef] = 100
    if verbose>1:
        ax1.plot(rd.timebase, reconst, '--', 
                 label='reconst, offset {i}'.format(i=i))
    # reconst[period//2:-period//2] = reconst[period//2:-period//2] - corrn/divisor
    reconst[period//2:1-period//2] = reconst[period//2:1-period//2] + smooth(err,period)/smooth(weight,period)
    # plot(smooth(err,period)/smooth(weight,period))

    debug_(pyfusion.DEBUG, 1, key='restore_sin')
if method==2:
    if verbose>0:
        ax1.plot(rd.timebase, reconst,'r', label='reconst, final offset')
    
ax1.legend()
fig.show()