Giulio Maestrini

Measuring and modeling complex impedance in the audio range

This is postmortem review of a project I started with a couple of friends in 2021 while Italy was partially stuck in a COVID19 lockdown. (Un)fortunately the lockdown ended before we managed to get any real results, but the preliminary work we made can be of some interest in itself. The aim of our project was to study how pickups used in electric guitars work from an electrical point of view, with the long term goal of building something new (a new pickup, a new amplifier a new psychoacoustic model etc... XD). We only managed to reach the preliminary goal of characterizing electrically a couple of existing pickups.

Great expectations

Introduction

A pickup is a transducer that captures or senses mechanical vibrations produced by musical instruments, particularly stringed instruments such as the electric guitar, and converts these to an electrical signal that is amplified using an instrument amplifier to produce musical sounds through a loudspeaker in a speaker enclosure. A typical magnetic pickup is a transducer (specifically a variable reluctance sensor) that consists of one or more permanent magnets (usually alnico or ferrite) wrapped with a coil of several thousand turns of fine enameled copper wire. The magnet creates a magnetic field which is focused by the pickup's pole piece or pieces. The permanent magnet in the pickup magnetizes the guitar string above it. This causes the string to generate a magnetic field which is in alignment with that of the permanent magnet. When the string is plucked, the magnetic field around it moves up and down with the string. This moving magnetic field induces a current in the coil of the pickup as described by Faraday's law of induction. Typical output might be 100–300 millivolts. Pickup - from Wikipedia)

The first step in our project was understanding the basics of magnetic pickups in the simplest form, single coil pickups.

Experimental setup

A way to characterize an electrical component is to model its frequency behavior by fitting experimental data with a theoretical model. An easy quantity to measure, even by means of inexpensive bench-top instruments, is the complex impedance, especially when frequencies involved are in the audio range and everything can be modeled using a discrete component approximation. By using a function generator to produce a sine wave $V_g$ and an oscilloscope to measure the amplitude and phase shift of two voltages $V_1$ and $V_2$ a simple voltage divider can be used to study an unknown impedance $Z$:

Experimental setup

$V_g$ is the sinusoid produced by a function generator and $V_1$ and $V_2$ represent the two input channels of an oscilloscope.
Again, given the low-frequency range, it is not necessary to care much about transmission lines and a free standing wiring can be used. By using the generalized Ohm's law the following relation holds between $V_1$ and $V_2$:

$$ V_2 =R \cdot \frac{V_1}{R + Z} $$

If $Z$ can be approximated with a linear model, this relation allows to fit the experimental $V_2 / V_1$ ratio to estimate the parameters of the model.

Measuring technique

If you have an analog oscilloscope, the amplitude and phase shift of $V_1$ and $V_2$ must be measured manually, but any digital oscilloscope allows to automatize the process.
Entry level Rigol oscilloscopes as ours DS1054Z the one we used are true magic, because they are inexpensive and super flexible at the same time.
Two major features they support are the SCPI programming interface, which is thoroughly documented in the programming manual, and the and the LXI standard for LAN connectivity.

It is trivial to communicate with the scope via the Ethernet interface on any linux or unix-like system: all you need is the nc (aka netcat) utility, no additional driver or software is required. If you what to send the command cmd to the oscilloscope whose IP address is 192.168.2.3 (listening on port 5555) just type in your terminal:

    reply=$(echo "cmd" | nc 192.168.2.3 5555)

The variable reply will contain the answer (if any) available for any purpose. Using a bunch of commands, such as:

    # Configure the scope to average 4 acquisitions
    ":ACQuire:TYPE AVERages"
    ":ACQuire:AVERages 4"

    #Measure period of input waveform (channel 1)
    ":MEASure:ITEM? PERiod,CHANnel1"

    # Get horizontal timescale
    ":TIMebase:MAIN:SCALe?"

    #Set horizontal timescale to "new_ts"
    ":TIMebase:MAIN:SCALe $new_ts"

    # Measure amplitude of input waveform (channel 2)
    ":MEASure:ITEM? VMAX,CHANnel2"

    # Get vertical scale
    ":CHANnel2:SCALe?"

    # Measure frequency
    ":MEASure:ITEM? FREQuency,CHANnel1"

    # Measure relative phaseshift of CH2 vs. CH1
    ":MEASure:SETup:PSA CHANnel1"
    ":MEASure:SETup:PSB CHANnel2"
    ":MEASure:ITEM? RPHase,CHANnel1,CHANnel2"

we created a bash script to collect all the repeat the measurement every 0.5s. Setting the function generator to swipe the frequency range 30Hz - 100KHz the output file will look like this:

    # Thu Mar 18 13:53:29 CET 2021
    #Freq (Hz)       V1 (V)          V2 (V)          Phase shift (deg)
    2.958580e+01     2.000000e+00    9.011200e-01    2.130177e+00
    2.976191e+01     2.000000e+00    9.011200e-01    0.000000e+00
    ...
    1.020408e+05     2.000000e+00    7.130316e-01    -4.868853e+01
    1.024590e+05     2.040000e+00    7.340032e-01    -5.142857e+01

Electrical model

The obvious approximation of a conductive coil is an inductor $L$. Other factors to consider are the series resistance of the copper wire $R_s$ and a parallel capacitance $C_p$.
Two reasonable discrete models of such components are the following:

Single coil pickup model

Given the frequency $ f $ and defining $ \omega (f) = 2 \pi f$ The impedance of the circuit on the left will be:

$$ Z(\omega)= \left( \frac{1}{R_s + i \omega L} + i \omega C_p \right) ^{-1} $$

While the one for the circuit on the right:

$$ Z(\omega)= R_s + \left( \frac{1}{i \omega L} + i \omega C_p \right) ^{-1} $$

gnuplot includes a powerful fit command that allows to fit any user-supplied real-valued expression to a set of data points, using the nonlinear least-squares Marquardt-Levenberg algorithm.
We created a script to analyze a set of measurements by fitting $\lvert V_2 / V_1 \lvert$ against the models described above.
The choice to fit the absolute value is just a convention, any other real-valued quantity such as the real or imaginary part, phase, or any combination thereof could be used. Experimental data is available here.

The core of the script is this part:

    i={0,1}
    w(f) = 2*pi*f
    rad(deg) = deg * pi / 180.0
    deg(rad) = arg (rad) * 180.0 / pi
    z(real,imag) = real + i * imag

    set xrange [20:101000]
    set logscale x
    set xlabel "Frequency [Hz]"
    set ylabel "Abs [ohm]"
    set logscale y
    set y2label "Phase [deg]"
    set y2tics 20 nomirror tc lt 2 font ",13"
    set xtics rotate
    set grid
    set key font ",12"

    fit_start = 50
    fit_end = 100000

    # impedance model
    z(x) = (1/(rs + i*w(x)*l) + (i*w(x)*cp))**-1
    # V2/V1 ratio from the voltage divider
    t(x) = r / ( r + z(x))

    # Kwnon value
    r = 4600
    # Initial guess
    rs = 5810
    cp = 1e-10
    l = 2

    in = "single_coil.txt"
    fit [fit_start:fit_end] abs(t(x)) in u 1:($3/$2) via l,cp, rs
    set label 1 sprintf("l=%.2f H \t cp=%.2e F \t rs=%.0f ohm",l,cp,rs)  at graph 0.02, 0.15, 0 left font ",10"
    set label 2 sprintf("Fit from %.0e to %.0e Hz - reduced chisquare: %1.1e",fit_start,fit_end,FIT_STDFIT*FIT_STDFIT)  at graph 0.02, 0.1, 0 left font ",10"
    plot abs(z(x)) t "single coil - abs" lt 6 lw 2 axes x1y1, -deg(z(x)) t "phase" axes x1y2

Results

The results of the fitting procedure are shown in the figure below, where experimental data points are plotted against the absolute value and phase of $V_2/V_1$. The model used is the one on the left, which gives a better adherence to experimental data (smaller chisquare).
gnuplot will indeed produce two output files: the plot itself, in the format specified, and a fit.log file including all the details about the fit results:

FIT:    data read from in u 1:($3/$2)
        format = x:z
        x range restricted to [50.0000 : 100000.]
        #datapoints = 744
        residuals are weighted equally (unit weight)

function used for fitting: abs(t(x))
    t(x) = r / ( r + z(x))
    z(x) = (1/(rs + i*w(x)*l) + (i*w(x)*cp))**-1
    w(f) = 2*pi*f
fitted parameters initialized with current variable values
[...]
After 3 iterations the fit converged.
final sum of squares of residuals : 0.0531344
rel. change during last iteration : -7.42185e-06

degrees of freedom    (FIT_NDF)                        : 741
rms of residuals      (FIT_STDFIT) = sqrt(WSSR/ndf)    : 0.00846796
variance of residuals (reduced chisquare) = WSSR/ndf   : 7.17064e-05

Final set of parameters            Asymptotic Standard Error
=======================            ==========================
l               = 2.17113          +/- 0.008791     (0.4049%)
cp              = 1.3742e-10       +/- 4.87e-13     (0.3544%)
rs              = 5755.05          +/- 14.94        (0.2596%)
[...]

The best estimate of parameters is printed directly above each plot, together with the reduced chisquare.
The plots are related to:

  1. The single coil pickup
  2. The two coils of an humbucker pickup, measured individually
  3. The two coils, in parallel
  4. The two coils, in series

Fit

The plots of the fitted $Z$, again as absolute value and phase is this:

impedance

A comparison of all the coils together in the audible range is this:

comparison