예제 #1
0
def test_puretone_run_sequence():
    """ Check that puretone's synthesize_sequence() correctly accepts a list of dicts and returns a correspond
    ing number of stimuli """
    synth = sy.PureTone()
    # Generate 1000 and 2000 Hz pure tones using synthesize_parameter_sequence
    results = synth.synthesize_sequence([{
        'freq': 1000,
        'level': 50,
        'phase': 0,
        'dur': 1,
        'fs': int(48e3),
        'dur_ramp': 0.1
    }, {
        'freq': 2000,
        'level': 50,
        'phase': 0,
        'dur': 1,
        'fs': int(48e3),
        'dur_ramp': 0.1
    }])
    # Generate references manually
    reference1 = sg.cosine_ramp(
        sg.scale_dbspl(sg.pure_tone(1000, 0, 1, int(48e3)), 50), 0.1,
        int(48e3))
    reference2 = sg.cosine_ramp(
        sg.scale_dbspl(sg.pure_tone(2000, 0, 1, int(48e3)), 50), 0.1,
        int(48e3))
    assert np.all(results[0] == reference1) and np.all(
        results[1] == reference2)
예제 #2
0
def test_puretone_random_level():
    """ Check that pure tone can accept a random level as a parameter and handle its evaluation when synthesis() is
    called. We check this by making sure that the output RMS level is not the same from one sample to another. """
    synth = sy.PureTone()
    tempfunc = lambda: np.random.uniform(40, 60, 1)
    assert sg.rms(synth.synthesize_sequence(parameters=[{'level': tempfunc}])[0]) != \
           sg.rms(synth.synthesize_sequence(parameters=[{'level': tempfunc}])[0])
예제 #3
0
def test_ideal_observer_valid_input():
    """ Test that if we provide a valid params to a ratefunc wrapped in decode_ideal_observer that everything runs
     without any errors """
    # Initialize simulator object
    sim = anf.AuditoryNerveHeinz2001()

    # Define stimulus parameters
    fs = int(200e3)
    tone_level = 30
    tone_dur = 0.1
    tone_ramp_dur = 0.01
    tone_freq = 1000

    # Synthesize stimuli
    synth = sy.PureTone()
    params = si.Parameters(level=tone_level,
                           dur=tone_dur,
                           dur_ramp=tone_ramp_dur,
                           freq=tone_freq,
                           fs=fs)
    params.increment({'freq': 0.001})
    stimuli = synth.synthesize_sequence(params)
    params.add_inputs(stimuli)

    # Add stimuli and model params
    params.append(['cf_low', 'cf_high', 'n_cf'], [1000, 1000, 1])
    params.append(['n_fiber_per_chan', 'fs', 'delta_theta', 'API'],
                  [1, int(200e3), [0.001], np.zeros(1)])

    # Run
    out = sim.run(params, runfunc=decode_ideal_observer(sim.simulate))
예제 #4
0
def test_puretone_incremented_level():
    """ Check that pure tone can accept a level with an increment and return appropriately scaled pure tones """
    synth = sy.PureTone()
    params = increment_parameters({'level': 20}, {'level': 1})
    np.testing.assert_approx_equal(
        sg.dbspl_pascal(synth.synthesize_sequence(parameters=params)[0]) -
        sg.dbspl_pascal(synth.synthesize_sequence(parameters=params)[1]), -1,
        5)
예제 #5
0
def test_puretone_synthesize():
    """ Check that PureTone object can successfully synthesize and replicates standard pure tone synthesis"""
    synth = sy.PureTone()
    output = synth.synthesize(1000, 50, 0, 1, 0.1, int(48e3))
    reference = sg.cosine_ramp(
        sg.scale_dbspl(sg.pure_tone(1000, 0, 1, int(48e3)), 50), 0.1,
        int(48e3))
    assert np.all(output == reference)
예제 #6
0
def test_puretone_wiggled_level_with_random_variables():
    """ Check that we can construct a parameter dict, wiggle level to be various random variables, and then
    synthesize and get plausible output values. """
    synth = sy.PureTone()
    params = wiggle_parameters(dict(), 'level', [
        lambda: np.random.uniform(35, 45, 1),
        lambda: np.random.uniform(45, 55, 1)
    ])
    outs = synth.synthesize_sequence(parameters=params)
    assert sg.rms(outs[0]) < sg.rms(outs[1])
예제 #7
0
def test_puretone_incremented_level_with_random_level():
    """ Check that pure tone can accept a random level as a parameter with an increment and return appropriately scaled
     pure tones. We simplify the calculation by using a ~random~ distribution with no variance. """
    synth = sy.PureTone()
    tempfunc = lambda: np.random.uniform(50, 50, 1)
    params = increment_parameters({'level': tempfunc}, {'level': 1})
    np.testing.assert_approx_equal(
        sg.dbspl_pascal(synth.synthesize_sequence(parameters=params)[0]) -
        sg.dbspl_pascal(synth.synthesize_sequence(parameters=params)[1]), -1,
        5)
예제 #8
0
def test_ideal_observer_real_simulation_with_level_roving():
    """ Test that ideal observer analysis on simple pure tone FDLs shows increasing FDLs with increasing frequency in
    the context of a mild level rove on the pure tone """
    # Initialize simulator object
    sim = anf.AuditoryNerveHeinz2001()

    # Define stimulus parameters
    fs = int(200e3)

    def tone_level():
        return np.random.uniform(25, 35, 1)

    tone_dur = 0.1
    tone_ramp_dur = 0.01
    tone_freqs = [1000, 2000, 4000, 8000]

    # Encode stimulus parameters
    params = {
        'level': tone_level,
        'dur': tone_dur,
        'dur_ramp': tone_ramp_dur,
        'fs': fs
    }
    params = si.wiggle_parameters(params, 'freq', tone_freqs)

    # Encode model parameters
    params = si.stitch_parameters(params, 'cf_low', [1000, 2000, 4000, 8000])
    params = si.stitch_parameters(params, 'cf_high', [1000, 2000, 4000, 8000])
    params = si.append_parameters(
        params, ['fs', 'n_cf', 'n_fiber_per_chan', 'delta_theta', 'API'],
        [int(200e3), 1, 5, [0.001, 0.001],
         np.array([[0, 0], [0, 1 / 6**2]])])

    # Encode repeats and increments
    params = si.repeat_parameters(params, 10)
    params = si.increment_parameters(params, {'freq': 0.001, 'level': 0.001})

    # Synthesize stimuli and encode in params
    synth = sy.PureTone()
    stimuli = synth.synthesize_sequence(params)
    params = si.stitch_parameters(params, '_input', stimuli)

    # Run model
    output = sim.run(params,
                     parallel=True,
                     runfunc=decode_ideal_observer(sim.simulate))

    # Extract AI thresholds
    output = [
        out[0] for out in output
    ]  # AI thresholds are always the first element of each tuple in output

    # Check to make sure that thresholds grow with frequency
    assert np.all(np.diff(output) > 0)
예제 #9
0
def test_ideal_observer_FDL_vs_frequency():
    """ Test that ideal observer analysis on simple pure tone FDLs shows increasing FDLs with increasing frequency """
    # Initialize simulator object
    sim = anf.AuditoryNerveHeinz2001()

    # Define stimulus parameters
    fs = int(200e3)
    tone_level = 30
    tone_dur = 0.1
    tone_ramp_dur = 0.01
    tone_freqs = [1000, 2000, 4000, 8000]

    # Encode stimulus information
    params = {
        'level': tone_level,
        'dur': tone_dur,
        'dur_ramp': tone_ramp_dur,
        'fs': fs
    }
    params = si.wiggle_parameters(params, 'freq', tone_freqs)

    # Encode model information
    params = si.stitch_parameters(params, 'cf_low', [1000, 2000, 4000, 8000])
    params = si.stitch_parameters(params, 'cf_high', [1000, 2000, 4000, 8000])
    params = si.append_parameters(
        params, ['n_cf', 'fs', 'n_fiber_per_chan', 'delta_theta', 'API'],
        [1, int(200e3), 5, [0.001], np.zeros((1))])

    # Flatten and increment frequency
    params = si.flatten_parameters(params)
    params = si.increment_parameters(params, {'freq': 0.001})
    synth = sy.PureTone()
    stimuli = synth.synthesize_sequence(params)
    params = si.stitch_parameters(params, '_input', stimuli)

    # Run model
    output = sim.run(params,
                     parallel=True,
                     runfunc=decode_ideal_observer(sim.simulate))

    # Extract AI thresholds
    output = [
        out[0] for out in output
    ]  # AI thresholds are always the first element of each tuple in output

    # Check to make sure that thresholds grow with frequency
    assert np.all(np.diff(output) > 0)
예제 #10
0
def test_puretone_incremented_sequence():
    """ Check that puretone's synthesize_sequence() and increment_sequence() successfully combine to
    produce two pure tones, one with a slightly higher frequency"""
    synth = sy.PureTone()
    # Generate 1000 and 2000 Hz pure tones using synthesize_parameter_sequence
    results = synth.synthesize_sequence(
        increment_parameters(parameters={'freq': 1000},
                             increments={'freq': 0.001}))
    # Generate references manually
    reference1 = sg.cosine_ramp(
        sg.scale_dbspl(sg.pure_tone(1000, 0, 1, int(48e3)), 50), 0.1,
        int(48e3))
    reference2 = sg.cosine_ramp(
        sg.scale_dbspl(sg.pure_tone(1000.001, 0, 1, int(48e3)), 50), 0.1,
        int(48e3))
    assert np.all(results[0] == reference1) and np.all(
        results[1] == reference2)
예제 #11
0
def test_ideal_observer_single_input():
    """ Test that if we provide a single stimulus to a ratefunc wrapped in decode_ideal_observer that some sort of
     error is raised to indicate that an ideal observer can't be calculated based on a single simulation! """
    # Initialize simulator object
    sim = anf.AuditoryNerveHeinz2001()

    # Define stimulus parameters
    fs = int(200e3)
    tone_level = 30
    tone_dur = 0.1
    tone_ramp_dur = 0.01
    tone_freq = 1000

    # Synthesize stimuli
    synth = sy.PureTone()
    params = {
        'level': tone_level,
        'dur': tone_dur,
        'dur_ramp': tone_ramp_dur,
        'freq': tone_freq,
        'fs': fs
    }
    stimuli = synth.synthesize_sequence([params])

    # Add stimuli and model params
    params = si.append_parameters(params,
                                  ['_input', 'cf_low', 'cf_high', 'n_cf'],
                                  [stimuli[0], 1000, 1000, 1])
    params = si.append_parameters(
        params, ['n_fiber_per_chan', 'fs', 'delta_theta', 'API'],
        [5, int(200e3), [0.001], np.zeros(1)])

    # Run model
    try:
        sim.run([params], runfunc=decode_ideal_observer(sim.simulate))
        raise Exception('This should have failed!')
    except ValueError:
        return
예제 #12
0
def test_anf_rate_level_function(anf_model):
    """ Test to make sure that a basic anf simulation can be set up and run on a single sequence of pure tones with
     increasing levels and that the simulation returns a corresponding increasing rate response. Check both the
      Heinz et al. (2001) and the Zilany et al. (2014) nerve model. """
    # Initialize simulator object
    sim = anf_model()

    # Define stimulus parameters
    fs = int(200e3)  # sampling rate, Hz
    tone_freq = 1000  # tone frequency, Hz
    tone_dur = 0.1  # tone duration, s
    tone_ramp_dur = 0.01  # ramp duration, s
    tone_levels = [0, 10, 20, 30, 40, 50]  # levels to test, dB SPL
    cf_low = 1000  # cf of auditory nerve, Hz
    cf_high = 1000  # cf of auditory nerve, Hz
    n_cf = 1  # how many auditory nerves to test, int

    # Encode parameters in Parameters
    params = si.Parameters(freq=tone_freq,
                           dur=tone_dur,
                           dur_ramp=tone_ramp_dur,
                           fs=fs,
                           cf_low=cf_low,
                           cf_high=cf_high,
                           n_cf=n_cf)
    params.wiggle('level', tone_levels)

    # Add stimuli to Parameters
    params.add_inputs(sy.PureTone().synthesize_sequence(params))

    # Run model
    output = sim.run(params)
    means = [np.mean(resp)
             for resp in output]  # calculate mean of each response

    assert np.all(np.diff(means) > 0)
예제 #13
0
def test_synthesizer_raises_warnings_about_kwargs():
    """ Check that when we pass through kwargs to Synthesizer objects that we do get warnings """
    synth = sy.PureTone()
    with pytest.warns(UserWarning):
        synth.synthesize(freq=1000, testparam='foo')