• WANTED: Happy members who like to discuss audio and other topics related to our interest. Desire to learn and share knowledge of science required. There are many reviews of audio hardware and expert members to help answer your questions. Click here to have your audio equipment measured for free!

DIY 3D Speaker Scanner - the Mathematics and Everything Else

somebodyelse

Major Contributor
Joined
Dec 5, 2018
Messages
3,765
Likes
3,074
I'm too used to auto-homing via limit switches on 3d printers. Should have been thinking CNC touch-off.
 

bigjacko

Addicted to Fun and Learning
Joined
Sep 18, 2019
Messages
723
Likes
362
I have seen the inverse kinematic NTK posted, that was huge mount of maths there, but is it possible to just type in the forward kinematics and let the program calculate the inverse kinematic itself?
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Somebodyelse: I bought limit switches just in case, but I’m hoping I can make preliminary tests without them. The videos I linked to show a manual zeroing step which looks like a good starting point. I’m expecting to learn that many of my naive assumptions are...naive. Great way to learn!
 
Last edited:
OP
NTK

NTK

Major Contributor
Forum Donor
Joined
Aug 11, 2019
Messages
2,724
Likes
6,027
Location
US East
Thanks, I knew my reference to feedback would cause confusion and I regretted including it as soon as I posted. I do realize it is all just geometry-based.

Another try: If I define a coordinate system and locate the motor assemblies within it, and then define a target mic location, I can calculate the 3 mic-motor distances (cable lengths). Why is that not the end of it?
:facepalm::facepalm::facepalm: You are right. I totally missed the problem. I was solving x, y, z given a, b, c. You already know x, y, z and need to find a, b, c, which is much simpler. My apology.
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Writing LabVIEW-based software to measure the transfer function of speakers has involved more fiddling than I hoped, but some of the time has been consumed by missing subtleties that led me off on unproductive trajectories. If I subtract off the “stupid time” I guess it’s not so bad.

A few questions regarding the nature of the data required for fitting:

I’m assuming that there should be no adjustment (for example normalization) of levels—the measured responses should be stored in “raw” form. Is that right?

Do the data need an accurate t=0 reference point? In other words, do I need a loopback function in the set-up to be sure the acoustic measurements are based on an accurate stimulus start time? I think I can now do that, in case usb etc. builds in some potentially variable latency.

Does it matter if the measurements are stored as impulse responses, or magnitudes and phases? They can be interconverted, of course, but I’d like to maximize efficiency by storing things conveniently


On the robotic front, I decided not to permanently mount the three stepper-driven spools to the ceiling. Doing so would keep them out of the way, and minimize set-up time, but it would make changes—or using the system in another space—much less convenient. So my not-yet-tested approach is to use telescoping poles to press the spool systems to the ceiling, with the other ends of the poles wedged against the floor. I bought three poles along with “matching” nuts for the poles’ threaded ends, but discovered the nuts and threads on the telescoping poles didn’t match (5 vs. 6 threads per inch, I think). So I molded three nuts around the poles’ threads and will mount those (somehow) to the spool assemblies.

My plan is to screw one stepper/spool system onto each telescoping pole, and then use the pole to wedge the system against the ceiling. Once in place, I’ll use plumb bobs hanging from the line guides to make measuring the locations of the line guides less cumbersome—easier at floor level than at the ceiling. Those positions are necessary to calculate the appropriate stepper movements.

Few
 
OP
NTK

NTK

Major Contributor
Forum Donor
Joined
Aug 11, 2019
Messages
2,724
Likes
6,027
Location
US East
Writing LabVIEW-based software to measure the transfer function of speakers has involved more fiddling than I hoped, but some of the time has been consumed by missing subtleties that led me off on unproductive trajectories. If I subtract off the “stupid time” I guess it’s not so bad.

A few questions regarding the nature of the data required for fitting:

I’m assuming that there should be no adjustment (for example normalization) of levels—the measured responses should be stored in “raw” form. Is that right?

Do the data need an accurate t=0 reference point? In other words, do I need a loopback function in the set-up to be sure the acoustic measurements are based on an accurate stimulus start time? I think I can now do that, in case usb etc. builds in some potentially variable latency.

Does it matter if the measurements are stored as impulse responses, or magnitudes and phases? They can be interconverted, of course, but I’d like to maximize efficiency by storing things conveniently


On the robotic front, I decided not to permanently mount the three stepper-driven spools to the ceiling. Doing so would keep them out of the way, and minimize set-up time, but it would make changes—or using the system in another space—much less convenient. So my not-yet-tested approach is to use telescoping poles to press the spool systems to the ceiling, with the other ends of the poles wedged against the floor. I bought three poles along with “matching” nuts for the poles’ threaded ends, but discovered the nuts and threads on the telescoping poles didn’t match (5 vs. 6 threads per inch, I think). So I molded three nuts around the poles’ threads and will mount those (somehow) to the spool assemblies.

My plan is to screw one stepper/spool system onto each telescoping pole, and then use the pole to wedge the system against the ceiling. Once in place, I’ll use plumb bobs hanging from the line guides to make measuring the locations of the line guides less cumbersome—easier at floor level than at the ceiling. Those positions are necessary to calculate the appropriate stepper movements.

Few
Thank you very much for blazing the trail :D I haven't experimented with any actual hardware implementation, so you are way ahead of me. Please treat what I'm saying in this post just ideas — they may be OK ideas or may be bad ideas. Other please chime in if you see any glaring errors.

All the measurements will need precise timing alignment because we need the phase information. I haven't used any USB mics such as the miniDSP UMIK-1. So I don't know how to programmatically acquire a waveform from one, or how to precisely time reference the acquired waveform to the stimulus signal.

The method I have much more confidence in is to acquire the data with a 2 channel ADC, such as a USB audio interface or sound card. Below is the signal flow diagram from ANSI/CTA-2034-A (with my added annotations).

DAQ.JPG


The data required for the fitting calculations would be the transfer function. Transfer function is the Fourier transform of the output divided by the Fourier transform of the input. To obtain the transfer function, you first take the FFT of the mic measurements and the FFT of the measured reference input. Then perform an element by element division (remember to use complex math as the FFT returns complex numbers).

I believe, the reference input should be in volts, typically at 2.83 Vrms. The mic measurements should probably be converted to sound pressures in Pascals. The calculated transfer function would then be from voltage input to sound pressure output.

I haven't used any USB interfaces, but I'd think if the USB interface behaves as an audio device, you can likely use the LabVIEW "Play Waveform" and "Acquire Sound" Express VI's to send the test signal and acquire the responses. I think a chirp (say, from a bit under 20 Hz to a bit over 20 kHz) would be a suitable test signal. (I believe LabVIEW uses DirectX sound, and probably goes through Windows mixer if you use Windows. So be careful.)

You should be able to automate the complete data acquisition process and compute the transfer function using LabVIEW. Save the transfer function data for post-processing (i.e. fitting calculations).
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Thanks for response. I think I've accomplished what you described, NTK, so I guess I'm on track. Here's a section of the screen after a test. I did a nearfield measurement of some little full range Dayton drivers I use as desktop speakers. The sine sweep only lasted 1 second to speed things along but of course that's easy to adjust for more serious measurements. I'm using a Behringer mic and M-Audio M-Track digital audio interface so that loopback measurements will be convenient. I'm not sure how to do that with a usb-mic.

Screen Shot 2021-01-31 at 12.37.47 PM.png

Panel #1 shows the calculated stimulus waveform in dark red (it's there just so I can debug things) and the response recorded using the microphone in yellow, both in the time domain. Panel #2 shows the resulting impulse response in yellow and associated step response in dark red (plotted in fill mode so it's easier to visually separate from the impulse). In both panels I also show time windows in light blue. I need one for panel #1 for now but will likely disable it for real measurements. Panel #3 shows the magnitude response in yellow. The red cursor's position is reported in the little indicators below the panel. I included the wavelength associated with the frequency because I often find I want to calculate where a reflection might be coming from, spatially.

This was all done without a loopback. The calculated stimulus as opposed to the measured stimulus, was used. I finally figured out what was keeping me from recording two audio channels, so once I move the Mac laptop I'm using out into the workshop, I'll have a convenient way to substitute a measurement of the stimulus sent to the amplifier for the calculated stimulus. What I have in mind matches the Signal Flow Diagram (thanks for that) so I'm optimistic. If all goes as hoped, that should give me reliable delay information. For some reason in my current set-up, the impulse appears at the extreme end of the time window so there's something funny with the relative timing of the stimulus generation and response measurement. I'm hoping that solves itself when I implement the loopback. I fudged it for the screenshot above by rotating the impulse response array to put the impulse somewhere reasonable.

The bit of LabVIEW code I'm using to calculate the transfer function and impulse response is shown below. I need to try setting the inverse fourier transform vi (virtual instrument) to 1D complex instead of 1D real and see what happens. I'm normalizing the height of the impulse to simplify displaying it along with the adjustable time window, but of course I can record the raw impulse instead. It sounds from NTK's response like I need to record the input to the inverse fourier transform vi--the complex response function--for maximum convenience when doing the spherical harmonics fits.

Screen Shot 2021-01-31 at 12.38.19 PM.png


Next steps are to see if my loopback plan bears fruit, and attach the molded acme nuts to the stepper-spindle systems so I can test the motion. That'll be a nail biter! Unfortunately, some of that hardware activity will be tricky with one hand (still in a sling) so I'm not sure how much progress to expect on that front.

Thanks for the continued interest. This little project has been a good way for me to bone up on LabVIEW in preparation for using it to teach a course in the spring (if the Covid gods allow).

Few
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
I managed to do a bit of milling machine work so that I could test out the telescoping pole method of mounting the stepper/spool assemblies. It works great! Very easy to install and position, and plenty firm enough so that it won't move around as the mic is repositioned. Here's a quick photo of an assembly held against the ceiling of my shop. The other two are good to go as well.
stepper on a pole.jpg


I'm running out of excuses for putting off testing the cable-based positioning system. I still need to make three long cables to connect the stepper drivers to the steppers. With that accomplished I think I can spool up some fishing line on each of the three spools, push the stepper assemblies up against the ceiling, and connect the three lines to a weight that substitutes for a microphone (no point in smashing the mic as I discover the errors in my code!). I fully expect to discover several errors in the code controlling the steppers so I think I'll take on this next step when I'm a bit fresher.

Few
 
OP
NTK

NTK

Major Contributor
Forum Donor
Joined
Aug 11, 2019
Messages
2,724
Likes
6,027
Location
US East
@Few I think what you have are looking good, and I am glad we are in broad agreement :)

Comments about the LabVIEW code on constructing the impulse response: I am not so sure about using only half of the FFT coefficients to calculate the transfer function, and then construct the impulse response by taking the inverse FFT. By using only half of the transfer function coefficients (see below), it will reduce the number of samples of the resulting impulse response by half. I think it has the effect of down-sampling (i.e. return only every other samples of) the impulse response. However, this wasn't too important as what we need is the transfer function to calculate the fitting function coefficients. When we calculate the fitting coefficients, we will calculate one frequency at a time (but will use all the spatial locations).

Screen Shot 2021-01-31 mod.png


On whether we need to use the complex inverse FFT (instead of "1D Real"), I checked the LabVIEW documentation (and ran a test). The complex instance is only required if the inverse FFT will return complex numbers. Since we are calculating the impulse response — a time domain entity, the expected results are real numbers only. Therefore the "1D real" instance should be the correct one to use. If we calculate using the complex instance, the returned values will have the same real values and zero for all the imaginary values.

Wish you have a speedy recovery from your surgery.
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Good catch regarding the truncation of the Fourier-transformed signal. I did that at an early stage to eliminate the redundant part of a plot and then later went back to insert the impulse response calculation, losing track of the truncation in the process. I'll try using the full FFT; I'll be interested to see what effect it has. It makes sense that all the coefficients should be used.

Thanks for the real/complex clarification. That'll save me some digging!

Have you tried "matricizing" the fitting process? I'd likely rely on Matlab if I can make it work, and of course their core religious belief is "linear algebra good, loops bad." If every frequency is fit separately, and one or two thousand measurements are made, I can see why some computer cranking time is sometimes required for the fit!

Thanks for the well wishes. Recovery seem to be progressing pretty well.

And thanks for the support on the LabVIEW development.
 
OP
NTK

NTK

Major Contributor
Forum Donor
Joined
Aug 11, 2019
Messages
2,724
Likes
6,027
Location
US East
...
Have you tried "matricizing" the fitting process? I'd likely rely on Matlab if I can make it work, and of course their core religious belief is "linear algebra good, loops bad." If every frequency is fit separately, and one or two thousand measurements are made, I can see why some computer cranking time is sometimes required for the fit!
...

I wrote my simulation code in Python, which has the same issue as MATLAB regarding loops. I did tried my best to vectorize the code.

The part that I used a for-loop extensively is when assembling the spherical wave expansion matrix (the matrix Ψ, see the opening post "Part 4" pdf). A for-loop is used to generate the matrix one column at a time, and the number of columns is 2*(N+1)^2, where N is the expansion order. I'd expect for most smaller speakers, N ≤ 15. (Per Klippel, the recommended number of measurement points is 1.5X the number of columns in matrix Ψ.)

The most computational intensive task is to compute the fitting coefficients using least squares, which is calculated with matrices using a single function call in Python or MATLAB. I'd estimate a recent mid-range PC, say 6-8 cores, should take seconds on the average to compute each frequency. For 20 Hz to 20 kHz (10 octaves), 1/20 octave frequency resolution, we'll need to compute ~200 frequencies, and I'd estimate the post-proessing time would be in the order of an hour.

Let me know if you need assistance coding the fitting coefficients solver in MATLAB. My MATLAB skills are very basic, but I think I should be able to come up with the basic solver.
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Thanks. That's helpful information, and I certainly appreciate the assistance.

I eliminated the Fourier coefficient-lopping step you pointed out. I'm not set up for reproducible scans where I'm fiddling, so it's hard to say how much difference it makes in practice. I agree that keeping all coefficients makes more sense so I'll just go with that.

I've only stuck a small toe briefly into Python, and that was 2 years ago. I didn't realize it is as loop-o-phobic as Matlab.

If I beat the odds, and end up with a collection of measurements to test things, could I share them with you (NTK) to see if things are on track? If so, what format should I save files in? I’d like to have that in hand before worrying about converting the processing to Matlab.

By the by, do the measurements need to be taken between two concentric spherical shells, or might cylinders or planes work?
 
OP
NTK

NTK

Major Contributor
Forum Donor
Joined
Aug 11, 2019
Messages
2,724
Likes
6,027
Location
US East
If I beat the odds, and end up with a collection of measurements to test things, could I share them with you (NTK) to see if things are on track?
Certainly. Will be more than happy to help :)

If so, what format should I save files in? I’d like to have that in hand before worrying about converting the processing to Matlab.
I think exporting the measurements as a series of 2-channel WAV files (one file each for the measurements at each location) is probably the simplest. You can use the LabVIEW VI "Sound File Write Simple VI" to export the WAV files. WAV files are a lot smaller than exporting as numbers in text files (e.g. exporting the complex transfer function values). Converting them to FLAC's will save some room but will be an extra step outside of LabVIEW. Of course we will need the info to decipher which file is for which measurement location, and the scaling factors to convert the waveform amplitudes to volts (for the reference input) and sound pressures (for the mic measurements).

[Edit] To save even more space and post-processing time, I think we can export the transfer functions as single channel impulse response WAV files.
By the by, do the measurements need to be taken between two concentric spherical shells, or might cylinders or planes work?
I think concentric spheres (and in this case approx. half spheres) is probably the best, but am not sure. I'd like to run some simulations to compare. I should be able to get some results by this coming weekend.
 
Last edited:

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Thanks for your willingness to assist.

Can you clarify the 2-channel aspect of the WAV file? Is one the mic's response and the other loopback signal (reference)? I was imagining using LabVIEW to calculate the response function and just saving that as a file, but I can certainly record the reference and mic signals instead. I already have the "Sound file write simple vi" in the code so it will be easy to change how it's used. I'm mostly curious why you suggest the two WAV file channels rather than a pre-computed frequency response, either magnitude and phase or complex-valued.

Also, to streamline the debugging process, I was thinking it would be a smaller bite to chew if just a series of horizontally displaced points were used rather than a full surface. Would this lower dimensional example be harder to deal with on your end? I think Earl Geddes uses horizontal position scans and fits them with associated Legendre polynomials for his horizontal directivity measurements, so the basic approach seems sound.
 
OP
NTK

NTK

Major Contributor
Forum Donor
Joined
Aug 11, 2019
Messages
2,724
Likes
6,027
Location
US East
Thanks for your willingness to assist.

Can you clarify the 2-channel aspect of the WAV file? Is one the mic's response and the other loopback signal (reference)? I was imagining using LabVIEW to calculate the response function and just saving that as a file, but I can certainly record the reference and mic signals instead. I already have the "Sound file write simple vi" in the code so it will be easy to change how it's used. I'm mostly curious why you suggest the two WAV file channels rather than a pre-computed frequency response, either magnitude and phase or complex-valued.

Also, to streamline the debugging process, I was thinking it would be a smaller bite to chew if just a series of horizontally displaced points were used rather than a full surface. Would this lower dimensional example be harder to deal with on your end? I think Earl Geddes uses horizontal position scans and fits them with associated Legendre polynomials for his horizontal directivity measurements, so the basic approach seems sound.
I was editing my previous response when you were posting. I think we can export the impulse response.

[Edit] My reasoning is to save space and bandwidth for the file transfers. If we use complex numbers, in binary format we'll need 16 bytes for each Complex64 FFT coefficient, versus 3 bytes (24 bit) for the impulse response in WAV. If we export using human readable numbers, the delta will be even larger.

I think a flat plane measurement grid may work. I'll run simulations to test, and will give an update probably this weekend. I'll also try and see how a horizontal line scan will work too.
 
Last edited:

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
Sounds good on all fronts. Exporting the impulse response would be great for me as well, because I use that to design finite impulse response filters.

Lots of wheel-spinning today but I think I've ultimately made some loudspeaker measurement software progress. The current form is event-driven, so it won't burn up computer cycles just monitoring the user interface. That should make it easier to combine it with the code driving the stepper motors. I need to do an actual test of the loopback method of obtaining a reference signal. I hope it just works! There's a ton of timing jitter when using the calculated waveform as a reference because I don't have firm control of relative timing of the sound generation and sound recording. I'm hopeful that recording two channels, and using one as the reference and the other as the response, will iron that out without surprises.

As a sanity check I used REW (top) and my software (bottom) to measure the same speaker. Sweep times and windowing are different, but the similarities are encouraging.

Screen Shot 2021-02-02 at 5.06.53 PM.png

Screen Shot 2021-02-02 at 5.05.46 PM.png


Few
 

Few

Member
Joined
Oct 27, 2020
Messages
93
Likes
97
...and I just demonstrated that the loopback signal fixes the timing issues. The impulse arrives at the same time that REW gives, and also matches my meter stick. Hurray!

Next step: programmatically make a sequence of measures and store them in some sensible way that will work for the processing stage.

Or, suck it up and see if the stepper systems together move the mic along the intended trajectory.
 
Top Bottom