Infrasonic audio output testing of an iPhone 4S

I have been testing the audio output of an iPhone 4S (line output on the bottom – not the headphone socket!) to see what response it has in the infrasound range (0.1Hz – 100Hz) with an aim to see if it can be used to play back EEG signals.

I could only find an iOS app to generate sine waves down to 1Hz which gave me the following results:

Freq (Hz)V pk-pkV rms
11.740.57
22.140.706
32.480.744
42.280.759
52.30.766
62.320.77
72.320.772
82.320.774
92.320.775
102.340.776
152.320.777
202.340.778
252.340.781
302.340.781
352.360.781
402.340.781
502.340.781
1002.340.781
5002.340.781
10002.340.782
50002.360.783
100002.360.778
iPhone 4S signal generator app - line output

plotted here:

iPhone 4S line out using sig gen app

.. however I wanted to get down to 0.1Hz, so I wrote a python script to generate wav files, with log frequency steps from 0.1 to 10Hz (10 per decade).

#!/bin/env/python
#
# create a set of wave files each with a single sine wave, maximum peak-peak amplitude
# length of wave file is minimum N wavelengths 
#
import math
import wave
import struct
import numpy

def write_wavfile(frequency, 
                  sample_rate, 
                  num_wavelengths,
                  sample_width,
                  num_channels,
                  filename):
    """
    create and write out a 'sine wave' wave file with 1 fundamental frequency
    """
    comptype = "NONE"
    compname = "not compressed"    
    pk_pk_amplitude = (2**(sample_width * 8))/2 -1  # maximum value for samplewidth (bipolar)

    # based on sine_frequency, and num_wavelengths, calculate length of time required
    time_length = num_wavelengths * 1/frequency
    # based on time required, and sample rate, calc samples length
    sample_length = int(sample_rate * time_length)
    bytes_length = sample_length * sample_width

    # make empty list of bytes of required length
    byte_list = bytearray(bytes_length)

    # for each sample calculate amplitude
    for x in range(sample_length):
        sample_point = int(math.sin(2*math.pi*frequency*(x/sample_rate))*pk_pk_amplitude)
        struct.pack_into('<h', byte_list, sample_width*x, sample_point)  # pack word little endian 

    # get ready for the wave file to be saved ...
    wav_file = wave.open(filename, "w")

    # set all the parameters at once
    wav_file.setparams((num_channels, 
                        sample_width, 
                        int(sample_rate), 
                        sample_length, 
                        comptype, 
                        compname))
    # write raw data
    try:    
        wav_file.writeframesraw(byte_list)
    except wave.Error as e: 
        print("wave write error '%s'" % e)

    wav_file.close()
    return(time_length, sample_length)


if __name__ == "__main__":

    sample_rate = 8000		# Hz
    sample_width = 2		# bytes per sample, => 16 bit samples
    num_channels = 1		# mono
    num_wavelengths	= 10	# length of wave file relative to frequency

        # create frequency step points, start = 0.1 = 10^-1, stop = 10 = 10^1, 20 points total
    f_points = numpy.concatenate((numpy.logspace(-1, 0, 10, False) , numpy.logspace(0, 1, 10)))

    for f_Hz in f_points:
        print("%1.3f Hz : " % f_Hz, end='')
        # write the synthetic wave file to ...
        fname = "%1.3f_Hz.wav" % f_Hz
        (len_s, len_d) = write_wavfile(frequency=f_Hz,
                                       sample_rate=sample_rate,
                                       num_wavelengths=num_wavelengths,
                                       sample_width = sample_width,
                                       num_channels = num_channels,
                                       filename=fname)
        print("filename = %s, length = %d seconds %d samples" % (fname, len_s, len_d))

using a Tektronix MSO3054 and playing back the wav files from the iPhone I was able to measure the frequency response.

Frequency (Hz)Vpk-pk (V)Vrms (V)Cycle Mean (dc offset) (V)Response dBV
0.1000.2340.0820.0054-11.3
0.1260.2920.1030.0054-9.4
0.1580.3670.1270.0053-7.4
0.2000.4580.1610.0054-5.5
0.2510.5660.2000.0052-3.6
0.3160.7020.2460.0055-1.7
0.3980.8580.3020.01130.0
0.5011.0320.3630.01101.6
0.6311.2210.4340.01133.1
0.7941.4220.4890.01134.4
1.0001.5980.5610.01835.4
1.2921.7770.6280.01796.3
1.6681.9150.6650.01237.0
2.1542.0170.7030.01777.4
2.7832.0840.7340.01507.7
3.5942.1580.7560.01218.0
4.6422.1760.7590.01278.1
5.9952.1980.7630.01178.2
7.7432.1940.7710.01828.2
10.0002.2120.7711.81E-028.2
12.9002.2180.7711.80E-028.2
16.6002.2200.7721.80E-028.3
21.5002.2220.7741.22E-028.3
27.8002.2390.7691.85E-028.3
35.9002.2410.7721.81E-028.3
46.4002.2420.7821.80E-028.3
59.9002.2450.7751.73E-028.4
77.4002.2480.7731.80E-028.4
100.0002.2510.7771.80E-028.4
iPhone4S line out low end response from wav files
iPhone 4S line out in volts using wav files

Not bad low frequency response for a phone!