I can’t focus my shadowgraph!

Maybe this is happening to you at this very moment: You build a shadowgraph, spend hours or days aligning the optics and finally get the camera installed. You put a regular camera lens, used in photography, to preserve the image quality as much as possible. You start focusing the focal ring of the lens such that it focuses on the test section where the shadowgraph object will be. But you can’t seem to get it in focus, no matter what. You spin the focal ring, frantically, back and forth. No position of the focal ring focuses the damn shadowgraph! Oh. My. God. You suddenly come to the realization. This will not work. Days of alignment to waste. Now what?!

The story above happened to me all too many times, so I decided to share my experience and solution with the world. Spoiler and TLDR: Just put a divergent lens in front of the camera!

Back to basics

So I’ll first set the scope of this discussion to a Focused Shadowgraph, which is the most typical shadowgraph encountered in aerodynamics labs. The focused shadowgraph is comprised of the following elements:

The image above represents the typical focusing shadowgraph system. It looks like a Z-type Schlieren apparatus, but is not to be confused: The Focusing Shadowgraph creates a conjugate focal plane at the camera location M*, forming a copy of the shadowgram at M in the camera sensor.

The optical setup shown uses two optical elements to focus the shadowgram plane M into the camera sensor plane M*: A focusing mirror (typically the same mirror specs as the collimating mirror); and the camera lens. The fact there are two focusing optics places a strong limitation when it comes to getting the focus at the plane M.

optical calculations

Since we’re focusing at plane M, we can consider only the optics between plane M and the camera, for our focusing calculations:

We have an intermediary conjugate plane between the mirror and the camera, whose distance can easily be found with the thin lens equation:

\displaystyle \frac{1}{f_{Mir}} =  \frac{1}{d_M}  +  \frac{1}{d_1}

Consider that when we’re focusing the lens, usually L=d_1+d_2 + d_S is fixed, since the camera sensor position is not moving.

To make the math a little easier to handle, we need to allow the camera to become out-of-focus, as we will be dealing with some singular points in this calculation. So let’s define the size of the circle of confusion. I’ll “zoom into” the camera so this becomes clearer:

In this configuration, the camera is out-of-focus and the lens focuses at d_I, making a point light source (i.e., a small feature or edge in the model) look like a circle with the diameter D_{CoC}, also known as the “circle of confusion”. The circle of confusion size is:

\displaystyle \frac{D_{Lens}}{d_I}=\frac{D_{CoC}}{d_S-d_I}

\displaystyle D_{CoC} = (d_S-d_I) \frac{D_{Lens}}{d_I}

The image is in perfect focus when D_{CoC} =0 which, as expected, leads to d_I=d_S.

Now we can use the thin lens equation to find d_I:

\displaystyle \frac{1}{f_{Lens}} =  \frac{1}{d_2}  +  \frac{1}{d_I}

Here things get a little dicy, because we have many ways of solving this problem. So let’s say we wanted to find the position of the conjugate focal plane d_M. Here’s a little diagram that may make it easier to go through the math:

The constants are shown in green, and the two variables we want to work with are shown in blue (d_S) and red (D_{CoC}). First, let’s assume we want everything in focus – i.e. D_{CoC}=0. Then we can plot d_M=f(d_S) for a given system. For example, say for a realistic system we have L=1150 mm, f_{Lens}=105 mm, D=35 mm, f_{Mir}=1000 mm:

The focus problem

The previous plot shows us something quite remarkable: For positive d_S-f_{Lens}, d_M is always less than f_{Mir}. Note, this is not specific for this system I calculated. It will always have to be the case.

Well, let’s look at a regular lens used in photography. For simplicity, we’ll use a lens with fixed focal length and only control over the focus ring. This lens, even though it is a compound system of lenses (usually with only two elements), can be replaced by a single “effective lens”, for the purposes of the thin lens equation calculation. If the lens is focusing at infinity, its distance from the sensor is exactly f_{Lens}. And if the lens is to focus any closer than infinity, the lens distance from the sensor d_S>f_{Lens}. Thus, d_S-f_{Lens}>0.

This places a great limitation on the “focused shadowgraph” ability to focus. The farthest it can focus from the Focusing Mirror is exactly the focusing mirror’s focal length, f_{Mir}. This makes sense, though. A point-like object placed exactly at the focal point of the focusing mirror will produce a parallel beam of light towards the camera, which will look like it’s coming from infinity. Mathematically, we can simply follow the equations:

For D_{CoC}=0, d_I=d_S. Then:

\displaystyle d_2=\frac{d_S f_{Lens}}{ d_S - f_{Lens} }

\displaystyle d_1=L-d_2-d_S = L - \frac{d_S f_{Lens}}{ d_S - f_{Lens} }-d_S

Well, when focusing at infinity, d_S=f_{Lens}, and thus d_1 \rightarrow \infty.

Then we can easily find that:

\displaystyle \frac{1}{d_M}=\frac{1}{f_{Mir}} - \frac{1}{d_1}

But 1/d_1=0, thus:

\displaystyle d_M=f_{Mir}

I like the interpretation with the circle of confusion, since it gives a sense of how the shadowgraph focusing looks like. For the same setup described, let’s look at the circle of confusion size for various lens distances:

SOLUTION #1 – FOCUS BEYOND INFINITY!

Yes, you read it right: Your lens setting focusing at infinity is limited. So you have to focus BEYOND infinity. Sounds crazy?

Well, I 3D printed a lens holder for a Nikon camera mount (see Thingiverse file here) that accepts a single 2″ lens. I used, in my case, a 125mm achromatic lens for this purpose. So this is a single-element lens, but now I designed such that its distance to the sensor is less than 125mm (less than its focal length). This would mean this lens would never focus in regular conditions, since it’s trying to focus beyond infinity. However, in the shadowgraph, we have the mirror as an extra optical element, which allows this lens to focus properly. Let me know if you found this idea useful, I’d love to hear your thoughts!

sOLUTION #2 – ADD A DIVERGING LENS

Another option (I hadn’t tried this yet): Just add a divergent lens in front of the camera lens! The divergent lens will “correct for” the focusing effect of the focusing mirror, extending the focal distance. I’ll leave out a drawing here of the setup; but I’ll leave the optical calculations to your specific setup.

[WIP] Machine Learning to Active Flow Control – Supersonic Nozzle Aeroacoustics!

Just wanted to put this out as this work in progress evolves! This is something really cool that I hope will make some interesting impacts in the active flow control community.

In 2020, I’ve built and tested a solenoid array driver to individually toggle individually 108 solenoids. This work was published here in the AIAA Scitech 2021 conference. You can access my personal version of the paper on ResearchGate, if you don’t have an AIAA subscription. In summary, we utilized this individually addressable solenoid array to tackle the active flow control actuator placement problem, which turns out is rather difficult because flows display very non-linear behavior. We found an unintuitive pattern of actuators that improved the cost function (circulation of the vortex in the wake of a cylinder, which is proportional to drag); something we would never have guessed.

So now we are going to attempt to apply this technique to an even more difficult flow control problem: Supersonic jet noise suppression. The principle is the same, we have several channels that we can address individually, and we will use an algorithm that measures the overall sound pressure level (OASPL) of a supersonic jet and tries to minimize it by changing the actuator locations and parameters. This is how the actuator array looks like:

This is a work-in-progress post. As things progress, I’ll update this. I’m excited to see the results!

Why are shadowgraph LED lenses so hard to focus?

I’m typing this out of a frustration that I’m sure many of my colleagues have already felt when assembling a shadowgraph or a Schlieren flow visualization system: Adjusting the LED focusing lenses! Let’s look at the optics of this problem and try to see the rather unintuitive trade-offs we are making when adjusting these lenses in practice.

The objective function

There are two objective functions that are usually desirable when focusing an LED system: Firstly, we want to collect as much light as possible. Second, we want to focus the LED to a point as small as possible, because we want to pass this light through a pinhole. In fact, the two objectives are the same: Focusing to a pinhole without cutting much light is the same as maximizing the amount of light (first objective). Thus, there’s really only one objective function. Let’s look at the standard collimator arrangement utilized in a Z-type shadowgraph:

Light losses

There are three locations where light can be lost that we need to consider in this type of setup:

  1. Light that is not collected by the lens
  2. Light that is blocked by the pinhole
  3. Light that is not collected by the parabolic mirror

If you are not thinking of these issues while setting up your shadowgraph, then you will lose a lot of light – perhaps more than you can afford to. The result, then, is an alignment struggle!

The reason this problem is rather unintuitive is because we usually don’t think about (3) because we’re focused into getting as much light into the pinhole. But the light lost in the parabolic mirror (3) really is the key to designing the optimal shadowgraph LED lens!

the ideal shadowgraph collector – single lens design

Let’s look at this problem backwards: Start with a parallel beam coming into the parabolic mirror. This beam will focus at where the pinhole should be, which only depends on the parabolic mirror focal length. The convergence angle of the beams, however, depends on the f-number of the parabolic mirror. As we’re going to see, the f-number of the mirror is crucial here.

We seek to put a lens after the focal point such that it focuses at the pinhole location with a beam convergence exactly equal to the f-number of the mirror. If we do so, there will be no loss of light at the parabolic mirror, meaning we literally eliminated a whole source of loss of light!

Let’s do some basic optics math to understand what are the parameters of this problem. We start assuming the f-number n_{mirror} of the mirror is fixed, since the mirror is usually the most expensive – and less interchangeable – part of the shadowgraph. Then, we just need to select a lens diameter D_{LENS} and focal length f to focus the LED positioned at d_L to a point at d_I from the lens. The LED will be considered a circular source of diameter D_{LED}:

Using the thin lens equation, we have the following relationship between the LED distance d_L and the image distance d_I:

\displaystyle \frac{1}{f}=\frac{1}{d_L}+ \frac{1}{d_I}

I’ll isolate the LED distance for now, as it is an important variable when aligning the lens assembly:

\displaystyle d_L=\frac{d_I f}{d_I-f}

We know that the beam downstream of the lens has to have a defined f-number n_{mirror} :

\displaystyle \frac{d_I}{D_{LENS}}= n_{mirror}

\displaystyle d_I= n_{mirror}  D_{LENS}

Thus, we get an equation for the LED distance d_L as a function of known variables:

\displaystyle \boxed{d_L=\frac{ n_{mirror}  D_{LENS}  f}{ n_{mirror}  D_{LENS} -f}}

Well, we technically only know n_{mirror} . In fact, D_{LENS} and f are the lens parameters we’re after. Now let’s look at the illumination by examining the light cone half-angle \theta that the lens collects:

\displaystyle  \boxed{\tan{\theta}=\frac{D_{LENS}-D_{LED}}{2d_L}}

The cone half-angle is related to the solid angle \Omega by the following relation:

\displaystyle  \Omega=2\pi\bigg(1-\cos{\frac{\theta}{2}}\bigg)

Well, most LED emitters (chip-on-board) are plane emitters. I am not considering, for simplicity purposes, the ones that have a built-in lens. Those usually have poor optical quality for shadowgraph applications and should be avoided, anyways.

Since the solid angle of a plane emitter is 2\pi, then we get that the intensity collected by a LED lens is:

\displaystyle  \boxed{\eta=\frac{I_{LENS}}{I_{LED}}=1-\cos{ \frac{\theta}{2} }}

This is what we want to maximize, which means we want to maximize \theta. One might think the obvious way to increase \theta is to increase the lens diameter. But it’s not that simple! Let’s rearrange the first boxed equation to see why:

\displaystyle d_L=\frac{ n_{mirror}  D_{LENS}  f}{ n_{mirror}  D_{LENS} -f}

Let’s multiply and divide the right-hand side by D_{LENS}:

\displaystyle d_L=\frac{ n_{mirror}  f}{ n_{mirror}  -f/D_{LENS}}

We’ll call f/D_{LENS}=n_{lens}, the f-number of the lens.

\displaystyle d_L=\frac{ n_{mirror}  f}{ n_{mirror}  - n_{lens} }

Divide both sides by D_{LENS} again, now:

\displaystyle \frac{d_L}{D_{LENS}}=\frac{ n_{mirror}  f/D_{LENS}}{ n_{mirror}  - n_{lens} }

\displaystyle \boxed{\frac{d_L}{D_{LENS}}=\frac{ n_{mirror}  n_{lens}}{ n_{mirror}  - n_{lens} }}

Which basically means that for a given lens f-number, the LED distance from the lens scales linearly by the constant in the right-hand side. Thus, increasing the lens diameter without changing its f-number will simply move the lens farther from the LED, cancelling out the effect of light collection.

Thus, the lens f-number is really the only relevant variable in determining the light collection efficiency \eta – assuming the lens is reasonably larger than the LED. Let’s plot the trend!

The plot above is for the following parameters: D_{LENS}=25 mm, D_{LED}=5 mm, n_{mirror}=5. Note the efficiency is inversely proportional to the f-number of the lens n_{lens}. Also, the spot size at the focal point D_F is also smallest at the lowest f-number. This is great, because both objectives converge. A low f-number lens will accomplish the highest collection efficiency and the smallest spot size, which is precisely what we want for a shadowgraph.

Below, I’m plotting the same trend for a mirror f-number of 10. As we can see, the collection efficiency is weakly dependent on the mirror f-number; which is very likely to be between 5 and 10 for a typical shadowgraph. The spot size is even smaller for the higher f-number mirror, which is even more beneficial.

Unfortunately, the collection efficiency for a single-lens system is really limited to low single-digit percent because lenses with f-numbers of 1 or less are pretty hard to manufacture. Especially achromatic lenses with low spherical aberration, which are required for shadowgraphs with white LED light sources. But the lesson to be learned here is very simple: Just get your lowest f-number lens and make sure the beam f-number is close to the mirror f-number. Higher collection efficiencies might be possible with several lenses, but I haven’t really looked carefully into the math. Coming up, perhaps! In any case, hope this helps a fellow researcher!

Transform Your Camera Tripod Into an EPIC Timelapse Panorama Slider!

Have you ever wanted to make a nice timelapse where you have some camera motion? If you look in the market, there’s some (rather expensive) motorized sliders that you can buy. These usually go for $300-$600, but they don’t have much travel. For example, this model has a 31.5″ (0.8m) travel and costs $258. This one is $369 and has a travel of 47″ (1.2m). I’m sure they’ve got much better construction and much nicer features than what I’ll present here.

But truth of the matter is – we are makers and we like to make our own equipment! So I came up with this while discussing with my friend how to make a timelapse where the camera circles around a subject. Since the radius is usually large, we would need ludicrously large equipment, and obviously it wouldn’t fit in our car. So the obvious alternative is to “loosen up” the requirement of rigidity of the setup and let the camera shake as it moves. Because at the end of the day, we’re in the computing era and we can fix the footage later, right? Well, see the video below for yourself! (Also in the end there’s a little compilation of a few timelapses I was able to take with this rig)

Also, if you look at the BOM; I’ve spent about $50 (plus the tripod) for what is effectively infinite travel – as long as there’s no obstacles in the way and the terrain is smooth enough. A much better deal in my opinion! I’ve tested this design only on pavement and stone sidewalks, and it works “okay”. It is wonderful in cement pavement. But it will fail in gravel, grass or anything too rough – the wheels I designed are simply too small. But perhaps this can prompt you to make a similar design for your own application!

So you can watch the video below or just follow the instructable images. The system is pretty straightforward. Enjoy!

Supplies:

  • 1x NEMA 17 Stepper motor (Link) [$5 ea]
  • 6x 625zz (5x16x5 mm) bearings (Link) [$6.28 /10pcs]
  • 1x 5mm shaft (Link) [$6.89]
  • 1x Bluetooth HC-05 Serial module (Link) [$5 ea]
  • 1x NEMA 17 to 5mm shaft coupling (Link) [$2.58 ea]
  • Lots of M3 screws (Link) [$11/box]
  • 2x 18650 cells (Scrap from laptop)
  • 1x Arduino Nano (Link) [$5.33 ea]
  • 1x A4988 stepper driver (Link) [$1.20 ea]
  • ~0.2kg of ABS filament [$4] – DON’T USE PLA if you intend to leave this in your car!
  • [Optional] 3.5mm female jack (Link) [$4 ea] for shutter release
  • [Optional] Shutter release cable (Link) [$7 ea] – MAKE SURE YOU BUY THE CORRECT CABLE FOR YOUR CAMERA!

So total estimated cost, without random materials like PCB, wires, solder, etc is about $47 (without the optionals). Might not be the cheapest project, but considering there’s not really any options to do this on the cheap (to my knowledge), this is quite decent!

Print the Parts!

Alright – So the first step is to print the design. I published the design in Thingiverse, both STL files and STEP files if you perhaps want to modify the design for your own necessity. The design I came up with is a clamp mechanism that simply adds wheels to each leg of the tripod. The front “driver” wheel has a stepper motor and the board that controls everything.

https://www.thingiverse.com/thing:4599836

Make the Driven Wheels

he driven wheels are actually quite straightforward to assemble. Screw the clamps to the main part and hammer the 5mm pin for the wheel in place. The wheel is bolted together for increased contact surface. Put the bearings on it and stick it to the shaft! If you want, you can use an end cap to prevent the wheel from falling off. My bearings were well-stuck to the shaft, so I skipped that part, but the caps are in the Thingiverse design.

Make the Driver Assembly

The top part of the driver assembly is the same as the other wheels. The “foot” mounts on the swivel plate, which has two arc-shaped slots for the driver assembly. The first two pictures show the first iteration of the driver, but I ended up revising it (last picture) to improve stability. The second version is the one published on Thingiverse.

Tripod Is Fully Converted! Now to the Brain:

So I’m using an Arduino Nano for this project. The first iteration used the paintbrush schematic in the latter pictures, but I finally found some time to make a PCB design of it. Link to the EasyEDA project below:

https://easyeda.com/fzigunov/timelapse_cart

As you can see, we just connect the components together. The arduino serves 2 purposes: Step the stepper and enable an interface with the Bluetooth. The interface will be done with an app, which saves us the trouble of building the buttons/etc that goes into making an interface. It also gives us a lot of freedom to change what the system does!

I added in a revision a feature for connecting a shutter release cable to your camera, which usually converts your camera connector into a microphone 3.5mm jack. With this cable, the Arduino will be able to trigger the camera. This can be used for night timelapses, so we are not driving the tripod while the camera is exposing. It’s an optional feature, though.

Download the App to Configure the Timelapse Parameters

So I built a little app with MIT app inventor (see file attached, I had to “hack” the upload due to file extension restrictions in the Instructables website. Change the extension from txt to zip). You can upload the *.aia file to MIT app inventor to see how the app is built now, and you can install the *.apk file on your phone if you want to use it [the interface might be a little jagged in your phone because I’m not a professional app developer!]. If you’re afraid of installing outside apps on your phone (which you should be), then you can compile the MIT app inventor project and get a QR code, which you can use to install the app on your phone instead.

The app basically builds a string of 4 bytes that is sent to the Bluetooth HC05 device through the Serial interface. This 4-byte string has encoded in it the 5 parameters of the system, as follows:

VVVVVVVV VVVVVVVV MDDDDDDD SWWWWWWW

Where VVVVVVVV VVVVVVVV is a 16 bit integer that encodes the 10*velocity inputted by the user in the app, M is a bit encoding whether the motor is on or off, DDDDDDD is a 7 bit integer with a time (in seconds) for driving the system in stop-and-go mode, S is the bit that turns on the stop-and-go mode, and WWWWWWW is the 7 bit integer with the wait time of the stop-and-go mode.

I encoded it like that because the MIT app inventor has a built-in function that sends this 4-byte string. This means I can send one command only, without having to handle a pipeline or anything like that. Then the Arduino just needs to decode this and set the parameters for the stepper, as we’ll see in the next step!

Program the Arduino

Well, there’s not much here. The firmware is attached. It’s basically the byte manipulation I discussed in the last step! I also implemented the shutter release. This should be able to trigger the camera for beautiful long exposure photos and eliminates the need for an intervalometer (as the Arduino itself can serve as an intervalometer).

Post-processing for Stabilization of the Footage

As discussed, we can’t really do much mechanically to prevent shaking. Perhaps larger wheels with a softer material will shake a little less, but they become unwieldy when storing the parts and I don’t think they would stabilize the footage to the point of no need for post-processing. If you do build a variant with larger wheels, I’d like to hear from you if you could skip the post-processing step!

I used Adobe Lightroom to convert the pictures and then Adobe Premiere to post-process the footage. Warp Stabilizer does the job incredibly well – I was stunned! If you use a large value for smoothness (like 100% or more), the stabilization is really decent. Since the warp stabilizer filter in Premiere is quite simple to use, I believe I can’t really add much here. Just apply it to your footage and enjoy the result!

Thanks for reading this – please let me know if you found this useful and if you build one for yourself! I would love to see footage you generated with this idea!!

(Optional) Adapt for a 3D Printer

Another thing that this timelapse system can do is a camera circling around a 3D printer. You need to use a connection to the 3D printer, in this case. Just connect the printer trigger signal to the D6 pin in the Arduino and use the code attached instead. Now, when the printer is done with the layer and parked somewhere, you can usually add a custom M42 G code for toggling a pin in the printer board that will acknowledge the Arduino to move the camera and take a picture.

See below what can be done!

Using randomized snapshot POD to overcome SVD memory issues

Introduction

For those acquainted with POD (Proper Orthogonal Decomposition), it’s very easy to throw POD at everything data analysis related. It’s such a powerful technique! For those who aren’t acquainted, I really recommend. I’ll introduce with a refresher. If you’re good, follow to the next section! We can decompose a set of N dimensional data points, which we will call here X, into three matrices. Since I’m not too fond of the “fancy mathematical jargon”, let’s just start with a practical example. I have a movie of particle image velocimetry (PIV), which is a data set that contains the information of a flow in a plane where I was looking at. This movie is a vector field, meaning it is a 2D set of data (like a screen), but each “pixel” has three numbers to describe the information contained (Velocity measured, in x, y and z direction). See the movie below and think this could very well be simulation data or any other data set!

Therefore, the movie is a 4D data set: Let’s count the dimensions: (1) Pixels in the X direction, (2) pixels in the Y direction, (3) vector component (x, y or z) and (4) time. Since POD can only handle normal matrices, we have to do some remodeling of the data set to fit matrix algebra, which can only handle 2D arrays of numbers. In order to do that, we need to flatten all dimensions but one. Which one should be left unflattened is up to you, but in “movies”, it makes a lot of sense to leave the time dimension unflattened, since we know that things are changing through time. Technically, you could do the POD in the spatial dimension instead, and perhaps get some insight from it, too, but for this example let’s stick to the more intuitive case where dimensions (1, 2, 3) are flattened into a column vector and dimension (4), the time dimension, is left unflattened.

If we do that, we can construct a data matrix X, which has dimensionality p\times q. p, the number of rows of X, is the number of entries necessary to build the flattened snapshot of the movie (in our case, dimensions 1, 2, 3 are flattened in the p direction, so p is the number of elements in each of those dimensions multiplied together). q is the number of time snapshots in the movie. This matrix can be decomposed into three matrices, which – without getting too much in the detail – are related to solving the eigenvalue problem of X. Since X is p\times q, we can’t technically solve an eigenvalue problem, but instead we can find the singular values (and corresponding vectors) of this matrix – hence POD is also called Singular Value Decomposition. These are as important as eigenvectors, in the sense that they form a set of basis vectors, othonormal in nature, that optimally span the space X. In lay words: The singular vectors of X are a set of nice pictures that represent the most variance in X, and the singular values are the square root of this variance – meaning if X has most of its content changing in a certain way, POD will capture that in its first few singular vectors/values.

POD is usually represented as this decomposition:

\displaystyle X_{p\times q} = U_{p\times q} S_{q\times q} V^T_{q\times q}

Where U_{p\times q} is the “mode matrix”, and each of its columns contains the flattened version of the mode – which can be unpacked by reversing the process of flattening used to generate the columns of X. S_{q\times q} is a diagonal matrix with the singular values, and the modern SVD algorithms (like svd() in Matlab) return S_{q\times q} in descending order (i.e., the first diagonal entry is the most important singular value). What we’re actually after here – for the current discussion, at least – is V^T_{q\times q}. This is the “right singular vector matrix”, and each of its rows contains a series of coefficients that, when multiplied by the corresponding mode column, gives the “movie” of only that mode playing. It, in a sense, is a “time series matrix” when the unflattened q dimension is time, and its coefficients can be analyzed to interpret what each mode is doing to the system under analysis. For example, you can try to take the Fourier Transform of a row of V to understand if there’s any periodic behavior related to the corresponding mode in U. It’s quite useful!

Some caveats and my two cents

Performing SVD in low-rank systems (i.e., when most of the energy in the eigenvalues of S is contained within the first few entries) can be quite insightful, but sometimes we need long time series to get converged statistics (say, for example in the case of Fourier Analysis of V, we need as many entries in V as possible). This is particularly the case in experiments, where noise can contaminate the spectrum and spectral averaging can “clean up” our data by a good amount. In general, Fourier analysis needs long data sets to capture periodicity with a good amount of certainty. Therefore, we would like to perform SVD in the whole X matrix so we can get the whole V matrix, right? Well, yes, but it is not uncommon to run out of memory! For example, doing SVD on one of our data sets where X was 100,000\times 10,000 flooded the 128GB memory of our data processing computer! SVD is, unfortunately, an algorithm that needs quite a bit of memory – more specifically, we need \mathcal{O}(pq^2) memory, where q is the shorter dimension. But if we assume (really, not a bad assumption in many cases) that the system is low-rank (say, only the first ~300 modes really matter), we could potentially perform SVD in the 100,000\times 300 matrix, which is quite doable even in a laptop because the memory complexity scales with q^2. The problem, is obviously, that now our V matrix has only 300\times 300 entries, which is not enough to do good Fourier analysis on. So what can we do to solve this?

Well, let’s remember that each column of U is a basis vector to describe the data set. Let’s say we compute a cheaper mode matrix like the big matrix U – let’s call it R_{p\times r} (where r is the number of reduced dimensions used, in our example r=300, whereas q=10,000). We can project every snapshot (column) of X back into R to get its entry in V. To see the math better, let’s show how it works in matrix algebra:

\displaystyle X_{p\times q} = U_{p\times q} S_{q\times q} V^T_{q\times q}

Each column entry of X is a flattened snapshot. Let’s look at how we generate one snapshot x_{p\times 1} from the SVD:

\displaystyle x_{p\times 1} = U_{p\times q} S_{q\times q} v^T_{q\times 1}

So we multiply the full mode matrix U_{p\times q} and singular value matrix S_{q\times q} by a column vector that corresponds to the contribution of each mode, v^T_{q\times 1}. Note the q dimensions all cancel out, so we can “stick” our reduced matrix R_{p\times r} and its corresponding singular vectors \mathcal{S}_{r\times r} in the mix, right? Let’s do that:

\displaystyle x_{p\times 1} = R_{p\times r} \mathcal{S}_{r\times r} \nu^T_{r\times 1}

Where \nu^T_{r\times 1} are the time coefficients of the particular snapshot we’re looking at (and in a sense, is what we’re after). Let’s do some math now – premultiply both sides by R^T_{r\times p}:

\displaystyle R^T_{r\times p} x_{p\times 1} = \underbrace{R^T_{r\times p} R_{p\times r}}_{I_{r\times r}} \mathcal{S}_{r\times r} \nu^T_{r\times 1}

We get an identity matrix because R_{p\times r} is orthonormal. So let’s pre-multiply everything by the inverse of \mathcal{S} once more to get rid of it:

\displaystyle \mathcal{S}^{-1}_{r\times r} R^T_{r\times p} x_{p\times 1} = \nu^T_{r\times 1}

Or, more neatly:

\displaystyle \boxed{\nu^T_{r\times 1} = \underbrace{\mathcal{S}^{-1}_{r\times r} R^T_{r\times p}}_{\textrm{Cheap SVD}} x_{p\times 1}}

This is actually quite neat. A column vector of the reduced rank right singular vector matrix \nu^T_{r\times 1} is obtainable from ANY corresponding snapshot x_{p\times 1} by projecting it onto the subspace of R_{p\times r}. This means we can obtain R_{p\times r} cheaply by simply randomly choosing a fraction of our data set to compose X, and then perform this projection to the remainder of the data set in order to get all the columns of V^T_{r\times q}, for the first modes at least. This would be a snapshot-by-snapshot process, without the memory overhead of SVD. Of course, you can use some more “mature” algorithms, like randomized SVD, but for me the issue is that you need to load the data matrix twice: Once to produce the randomized range finder, and another time to compute the randomized SVD. When you can’t even fit the data set in memory and the data transfer time is really long, you don’t want to duplicate the loading process of the data matrix X. This approach, although approximate, removes that need.

Of course, you don’t get the full benefit of SVD. In the end, R_{p\times r} is an approximation of U_{p\times q}, thus the projection will leave some stuff out. R_{p\times r} also is using less snapshots to be constructed, so you’ll have an error related to the modes themselves with respect to U_{p\times q}. But when lack of memory literally prevents you from doing SVD altogether and you’re most interested in analyzing V^T_{r\times q} (i.e., only the first r modes of V^T), then you can still do the analysis to a pretty decent extent. Also, it might be a compelling way of storing time-resolved, 3D computational results without all the hard drive storage necessary (like a compression). So let’s look at some really nasty, noise contaminated, experimental data sets:

Results

Ok, so we’re looking at the wake of a NACA0020 airfoil that I used in a study I’m working on. The airfoil is at 0º angle of attack, but it still sheds coherent structures because of the shear layer instability. We want to pick up what are the frequencies of these coherent structures with Time-Resolved PIV, but this technique – even though it’s amazing – is a little tough to get to low noise levels. The individual vectors in the snapshots have uncertainties of the order of 10% of the mean flow! But as we will see, this is cake for POD – as long as there’s low-rank behavior happening.

So we construct the X matrix by randomly sampling vector fields from the full data set. I used randperm() in Matlab for this part. Since the computer I’m using can handle up to about 3500 snapshots, we will look at 3500 snapshots (the full SVD) versus 350 snapshots (the reduced SVD), and then project the full X matrix onto the subspace of R to get the time coefficients of the first 350 modes.

Comparison of the time series of the first POD mode of the wing at Re_D=60,000 (Re_c=47000); “Full POD” corresponding to 3500 snapshots; “Random POD” corresponding to 350 snapshots and the projection method described here

As shown in the figure here, there’s not really much difference between the time series of the reduced, “random” POD, versus the full-fledged POD with 3500 snapshots. The difference in SVD computation, however, is quite a big deal:

Data Matrix X sizeMemory Consumption (Matlab SVD ‘econ’)Computational Time
Full POD190872\times35005.7 GB252 s
Reduced POD190872\times350too small to measure (<100MB)7.1 s

SVD memory complexity for the case studied

As we can see, the difference is quite large in this “toy, but practical case”. Perhaps we could use more snapshots in the reduced POD case, but I also wanted to push it a little. The mode shapes look indistinguishable from each other, but of course we could get an euclidean distance metric (I didn’t really bother). Looking at the spectrum, we can see that the dynamics are pretty much indistinguishable in the first modes:

I’m not fully into the CFD business, but I think this simple technique could be used to compress CFD time series data, since we already know most flows do display low-rank behavior (and we are already doing these decompositions anyways to find this low-rank behavior!). In other words, I think one could: (1) run a DNS/LES solution until their statistics are converged (as is usual in the business), (2) run for some period of time while saving enough random snapshots to generate the snapshot matrix – you still need to run for a long-enough time, though – and then (3) perform POD on the snapshot matrix, and finally (4) run for as long as necessary, and project every snapshot onto this random POD basis to get the V matrix (low memory consumption). This enables one to save the V matrix, along with the first few modes of R onto a file, and in the future reconstruct the entire simulation time series (to reasonable accuracy) for further analysis. Obviously the analysis will be limited to the compression accuracy and the time span of the capture process, so one has to be aware of that!

Well, perhaps I’ll try that in the future. But for now, I’ll leave the idea floating so someone can perhaps find some use to it.

Thermal Stacks, Transmission Lines, high power LED’s and Temperature Sensitive Paints (TSP)

I’m writing this because even though it’s already 2020, this kind of stuff still cannot be found anywhere in the internet!

Stacking layers of materials is something we all do in so many engineering applications! Electronic components, batteries, constructions panels, ovens, refrigerators and so many other layered materials that are inevitably under heat transfer. We want to predict the temperatures on the stack, at all layers, to ensure the materials are going to withstand the transfer of heat. In order to do that, any engineer worth their salt will already have used the Thermal/Electrical Circuit Analogy. And it works wonders!

But what if we want to do transient analyses? What if the materials are going to be stressed by some quick burst of power; or some sequence of bursts at a certain frequency? Of course, we can always just do some FEM and solve our issue – but one might find that this can become a multi-scale problem if there’s low frequencies AND high frequencies involved.

This is commonly the case in semiconductors. Applications I’m familiar with are related to LED pulsing, but I’m sure one will find many others. Another more obscure application I found in my research has to do with unsteady measurements of surface temperature when fluid is flowing on a surface. Some frequencies will be too fast and the stack of materials will not respond, so how do we proceed in that scenario? How to predict the temperature rises and – more importantly – understand what we need to change in the design in order to improve its frequency response?

Well, it turns out we can extend the thermal circuit analogy to transients by including the component’s thermal capacitance. Most layers in a stack would then be easily lumped into RC low-pass filters. This is the “basic approach” and it works – to a point.

So let’s examine it, to understand its pros and also its limitations:

The thermal capacitor

Capacitance in electrical circuits is the ability of a given electrical component to store charge. In the thermal analogy, this “charge” is heat – and the thermal capacitance is just the mass of the component times its heat capacity (C=m \times c_p). If we look at the energy conservation equation for a lumped element:

\displaystyle q = m c_p \frac{\partial T}{\partial t}

Which means that, for a given heat flow q, a small capacitance C leads to a large rate of temperature rise (large dT/dt). I will make this problem more 1-dimensional to consider the case where the stack of layers is much thinner than wide, because that’ll lead to interesting observations when we drop the “lumped element” part of this model. For now, let’s simply divide both left-hand and right-hand sides by the sheet area A, to get everything in terms of heat fluxes:

\displaystyle \frac{q}{A} = q" = \frac{m}{A} c_p \frac{\partial T}{\partial t}

\displaystyle q" = \frac{\rho A L}{A} c_p \frac{\partial T}{\partial t}

\displaystyle q" = \rho c_p L \frac{\partial T}{\partial t}

The terms \rho c_p L then are what we will call the specific component’s capacitance (C^*), in the SI units of J/m2.K. One can then represent a layer of a stack like the following RC circuit:

Obviously, this single-layer model is rather simple and does not constitute of much of an issue. The RC circuit has a time constant, \tau=R^*C^*, where R^*=L/k. You can check the units: R^* has units of m2.K.s/J, which times the units of C^* gives us a time constant in seconds. The cut-off frequency is f_{cutoff}=1/\tau, and we get a -20dB/decade low-pass filtering behavior.

It is really worth observing, though, that the capacitor is not connected to T_2, but to an elusive “ground” temperature. This is because, as long as you have a non-zero \partial T/\partial t, you will have heat transfer to the thermal capacitance. Therefore, the ground level can be considered absolute zero temperature – for didactic purposes. The temperature of this ground level is not important, though: since capacitors always block DC, its absolute value will never play a role.

Stacking them up (plus all the ways you will mess this up)

For thermal stacks, it is not straightforward how to assemble the circuits together. Do we put the RC circuits in series with each other? As it turns out – not really. To understand why, let’s think about what happens in a two-layer stack:

Looking at the picture above, we have a stack of two layers and 3 different circuits that could (potentially) represent it. The circuit (a) represents how we would construct the thermal RC network using the same strategy as for the single layer explained before. (a.1) is simply another representation of the same circuit, perhaps less “bulky”. The circuits (b) and (c) are wrong because they do not represent the thermal equations that describe the stack. Let’s see why:

The first layer of the stack has an input heat flux of q_1", which according to the energy conservation equation applied to this lumped element, can be split into the heat flux that stays in the element (q_{c1}") and the heat flux that goes through the element (q_i"). This heat flux then goes to the second layer and splits again into q_{c2}" and q_2". The energy conservation equations here are equivalent to the Kirchoff current laws applied to the nodes at T_1 and T_i in the circuit representation (a):

\displaystyle q_1"=q_i" + q_{c1}"

\displaystyle q_i"=q_2" + q_{c2}"

This sounds easy because you already have the answer spoon-fed to you. But if you were left to your devices, I would bet many of you (including past me) would come up with the circuit representations (b) and (c). (b) doesn’t make any sense because capacitors block DC, therefore there would be no DC heat flux through the stack – total non-sense!

The circuit in (c) also does not make sense, but it is not clear why at a first glance. If you follow Kirchoff’s laws, however, you will see that (c) cannot be right, because in the node at T_i the heat flux equation would have to be q_1" + q_{c1}=q_i" + q_{c2}" – which is simply not the correct energy balance.

It is not really very intuitive that the capacitor of the first layer of the stack should be connected to ground, instead of T_i. In fact, I made quite a few times this mistake. But looking at the energy balance, we can’t really deny there is a correct equivalent circuit.

We can also solve the full heat pde with circuits!

Ok, so we tackled the single wall and the stacked double-wall problem. I think having gone through how this can go wrong, you can now build this to multi-walled systems easily. As you probably already realized, each new layer will behave as a new first-order system, and some very interesting behavior can appear as extra poles are introduced by the new layers. One thing, however, that is worth noting, is that this approach completely fails at high enough frequencies.

To understand why, let’s think about it a little further. If the temperature oscillations in T_1 are high frequency (i.e., their period is below the R^* C^* time constant), the lumped element model would predict a decay rate of -20dB/decade, which is what is expected from a standard first-order system.

But the problem in the (zero-dimensional) lumped element model is that the whole element’s temperature is assumed to be a constant value. At high enough frequencies, this won’t be the case anymore. We can see why the lumped element model becomes inaccurate by modeling the standard 1D heat equation over a slab:

\displaystyle -\frac{\partial T}{\partial x} = R' q"

\displaystyle -\frac{\partial q"}{\partial x} = C' \frac{\partial T}{\partial t}

The negative sign in the left-hand side is related to the direction of the coordinate system. One can recover the same equations by distributing the lumped element model related to each layer into the following circuit:

Where R'=1/k (thermal resistance per unit length) and C'=\rho c_p (thermal capacitance per unit length). This circuit immediately follows from the circuit presented in (a.1) in the previous figure; since one can consider a single layer can be decomposed into an infinite stack of infinitely thin layers. Not all mechanical engineers will recognize, however, that this corresponds to a (simple) version of the 1-dimensional transmission line model. Robertson and Gross (1958, “An Electrical-Analog Method for Transient Heat-Flow Analysis”, Journal of Research of the National Bureau of Standards) did recognize this in their paper, for example. Funnily enough, their figure shows they also got the RC network wrong, since the first resistor is shown between the first capacitor and T1 – an indicator of how tricky this business can be!

A thermal layer is actually a transmission line

I invite you to read the article on Wikipedia about transmission lines if you’re not familiar with this concept, or read the book “Time-Harmonic Electromagnetic Fields”, by Harrington, 1961. Transmission line is an electrical model for pairs of conductors at high frequencies. At high enough frequencies, the pair of conductor’s distributed capacitance and inductance creates waves inside the conductor, which can be modeled by the wave equation. The element of the electrical transmission line is displayed below (figure from the Wikipedia article):

The electrical transmission line follows the 1-dimensional damped wave equation, which is derived from the Telegrapher’s equations:

\displaystyle -\frac{\partial V}{\partial x} = L' \frac{\partial I}{\partial t} + R' I

\displaystyle -\frac{\partial I}{\partial x} = C' \frac{\partial V}{\partial t} + G' V

We can easily see this is the wave equation by taking the Fourier Transform of the two equations:

\displaystyle -\frac{\partial V}{\partial x} = (j\omega L'+ R') I

\displaystyle -\frac{\partial I}{\partial x} = (j\omega C'+ G') V

And then replacing, say, the x derivative of the first equation in the second:

\displaystyle -\frac{\partial^2 V}{\partial x^2} = (j\omega L'+ R') \frac{\partial I}{\partial x}

\displaystyle \frac{\partial I}{\partial x} = -\frac{1}{j\omega L'+ R'} \frac{\partial^2 V}{\partial x^2} = (j\omega C'+ G') V

\displaystyle \frac{\partial^2 V}{\partial x^2} - (j\omega C'+ G')(j\omega L'+ R') V = 0

\displaystyle \frac{\partial^2 V}{\partial x^2} + \omega^2 C' L' V - j\omega (L'G'+ C'R') V - R' G' V = 0

Taking the IFT:

\displaystyle \frac{\partial^2 V}{\partial x^2} - C' L' \frac{\partial^2 V}{\partial t^2} - (L'G'+ C'R') \frac{\partial V}{\partial t} - R' G' V = 0

Which, obviously, is the wave equation. It’s damped by the distributed resistance R' and conductance G'. If we come back to the thermal stack and consider there’s no conductance (G'=0) and no inductance (L'=0), we recover the heat equation:

\displaystyle \frac{\partial^2 V}{\partial x^2} - C'R' \frac{\partial V}{\partial t} = 0

Where the thermal diffusivity is \alpha=1/C'R' = k/\rho c_p ; as expected.

how this interpretation can be useful

Ok, by now you might be finding this all quite trivial and, perhaps, an over-complication of the heat transfer problem. Why would one need to invoke the far more complex “transmission line” to describe the behavior of such a simple system? Well, it basically allows us to easily determine the temperature transfer functions at different points in the stack (perhaps, easily is not the best word, but with a couple easily-programmable equations), without having to solve the differential equations numerically. Plus, it allows us a very cool insight about the behavior of the themal stack at higher frequencies. As it turns out, at high enough frequencies the first layer’s characteristic impedance – a material property – dominates the transfer function.

Thermal transmission lines in practice: the pulsed led

Let’s first analyze the following case that I find is the most practical for high frequency thermal stacks: An electronic power dissipation device that sources power in short bursts. I mentioned in a previous post that you can massively overdrive LEDs to produce a lot more light than “designed” for short bursts, which enables one to expose high speed cameras – like a camera flash. We’ll look at the Luminus Devices Phlatlight CBT-140 for this analysis. The reason why AC thermal analysis is important in pulsed LEDs is because, even though the mean temperatures of each component might be within spec due to the high thermal capacitance of the heat sink, the power burst will temporarily increase the temperature of the LED die, and we obviously also don’t want that to exceed the specs of the LED. Concerns about thermal expansion will not be addressed in this discussion – but you should also do your research on that!

The CBT-140 die looks like shown below. The named squares in the electrical analogy (bottom right) represent the “transmission lines” for each component.

We will consider the die is made of sapphire (many high power LED dies are made of it). This might be incorrect for this model – but I could not find any specs on that. The die has 0.31mm thickness; whereas the copper has 3.44mm thickness. The aluminium heat sink is pretty large. For the sake of this analysis we’ll consider 10mm. As we’ll detail later – it won’t matter much for the AC analysis.

So what we want to find is the “input impedance” as seen by the current source just above the die in the figure. The current source is a heat flux source, which in this case would be a square wave with some (low) duty cycle, since power is generated by the (micrometer thin) LED just above the sapphire die. Because there’s a cascade of 3 “coupled transmission lines”, we have to use the transmission line input impedance formula three times. From Wikipedia:

\displaystyle Z_a = Z_{0,a}\frac{1+\Gamma_L e^{-2\gamma l_a}}{1-\Gamma_L e^{-2\gamma l_a}}

Where Z_a is the input impedance as seen by the node at T_a and \Gamma_L=(Z_L-Z_0)/(Z_L+Z_0) is the reflection coefficient due to the impedance mismatch of the aluminium slab and the convective boundary (also the load impedance) R_{conv}=Z_L. Z_0 in this case is the aluminium’s characteristic impedance, which in general has the form:

\displaystyle Z_0 = \sqrt{\frac{R'}{j\omega C'}} = \sqrt{\frac{1}{j\omega (k \rho c_p)}}

Note the characteristic impedance is inversely proportional to the square root of the frequency. This will explain the “half-order” decay (-10dB/decade) behavior in the frequency domain we’ll see later (in contrast with a first-order expected from these RC networks). The square root of 1/j predicts a phase lag of 45º at high frequencies (not 90º!). Also referring to the Wikipedia article, the propagation constant \gamma is a material property:

\displaystyle \gamma = \sqrt{j\omega R' C'} = \sqrt{j\omega \alpha^{-1}}

As we discussed, the math is not the “prettiest”, but this can all easily be hidden behind an Excel or Matlab formula. In this case, using the properties of the three materials shown in the table below and a convection coefficient of h=100 W/m^2 K \rightarrow R_{conv}=0.01 m^2 K/W, we get:

Aluminium 6061CopperSapphire
k180 W/m K287 W/m K34.6 W/m K
c_p1256 J/Kg K376 J/Kg K648 J/Kg K
\rho2710 Kg/m38800 Kg/m33930 Kg/m3
Z_04.04\times 10^{-5} \sqrt{-j\omega^{-1}}3.24\times 10^{-5} \sqrt{-j\omega^{-1}}1.06\times 10^{-4} \sqrt{-j\omega^{-1}}
\gamma137.5 \sqrt{j\omega}107.4 \sqrt{j\omega}271.3 \sqrt{j\omega}

In order to find the “input impedance” at the node T_c, we use the Z_a as the input load (Z_L), and then iterate. Since we’re looking for the maximum temperature in the stack, T_d, let’s calculate the overall input impedance of the stack Z_d:

In this case we are driving the LED with a 500 nanosecond square pulse that repeats at 100 kHz. The drive current of the LED is 200A, and given the die area of 14 mm2 and a voltage drop of 20V in the LED, we have an instantaneous power of 285 MW/m2. That’s a lot of power!! Well, as it turns out, the mean flux of power (in this case, at a duty cycle of 5%, 14.2 MW/m2) appears in the spectrum at the DC component, but the sharp bursts of power also generate incredibly high amounts of high frequency power flux that really need to be considered.

Looking at the figure above, the solid, thick black line is the actual frequency transfer function of the whole thermal stack. The dashed blue line represents the lumped element assumption and it is a good model until about a frequency of 0.05 Hz. It then starts to fail when the aluminium starts to kill the waves very close to its surface due to its “large characteristc impedance”, (Z_0). You can think about it like; its large capacitance combined with its (relatively) low conductivity prevents the thermal oscillations on one side of the material to immediately propagate to the opposite side – invalidating the lumped element assumption.

This issue happens once again for the copper (not clear exactly where) and then finally for the die itself (the sapphire) above the frequency of 40 Hz. Then the characteristic impedance of the sapphire dominates the transfer function – i.e., the sapphire is thick enough to be effectively “infinite”, as far as high frequency heat transfer is concerned (the sapphire is 0.31mm thick!!). The temperature waves then decay inside the sapphire, and very little oscillations can be detected at its opposite side. At those frequencies, it doesn’t matter anymore which material you put at the interface. It will not see any temperature oscillations.

All of this insight we get without needing to numerically solve the heat equation is quite fascinating. We now know that at high frequencies, the dominant part of the frequency response is a material property – meaning that a material choice here is crucial for high frequency heat transfer!

How important? Well, let’s run the numbers and see what the wave looks like. I removed the DC part of the wave, because this LED really needs some thermal mass attached to it (the aluminium block) as no amount of convection or heat-sinking will get rid of this insane amount of power. Therefore, let’s only focus on the oscillatory part of the wave:

We can see that we predict an overtemperature of almost 25 K for the die surface for this case. This is on top of the die heating up from the constant heat flux at DC. It is quite a lot and could (in fact, DOES) easily lead to die failure if one only reads the copper temperature. Therefore, one needs to account for this overtemperature when designing an emergency shutoff system – otherwise, it’ll only think about shutting off 25 degrees after the LED failed!

Temperature sensitive paint – high frequency measurements

So this one is quite an interesting application from the research standpoint! We use temperature sensitive paints to perform measurements in aerodynamic models. We paint an aerodynamic surface with this special paint, and it fluoresces under UV illumination, emitting a strong (usually red) light signal at colder temperatures and a weaker signal as the paint surface becomes hotter. An example of supplier of these paints is given here. Though this is quite a specialized application used mostly in high end aerodynamics research, there’s still a lot of interest into understanding its behavior.

So let’s say we want to perform unsteady measurements of heat transfer coefficient at the surface. We put the surface under a flow of nominally known temperature (for this example, a jet impinging on a surface) and then we use the TSP technique to image the temperature map over the impinging surface; getting a full temperature map. As the flow oscillates, we have fluctuations of this convection coefficient – which translate to measured fluctuations in temperature. Obviously, we might not be able to see them if the temperature does not fluctuate much because the substrate of the surface has too much thermal capacitance (as discussed throughout this article). In fact, now we know we have waves of temperature going through the material, which will be rapidly decaying. It might perhaps be the case that the waves are so weak that we cannot detect them. Therefore, we need to assess whether we can measure these waves by comparing the expected signal generated by the oscillations with the dynamic range of our camera.

Let’s start with a rather simplistic setup – to illustrate the issue. Say we have an impinging jet as in the figure below. The impinging jet is the flowing arrows at T_{\infty}.

A “thin” layer of temperature sensitive paint is painted on top of a 10mm thick aluminium plate. The layer of paint, although thin, will have an effect on the transfer function. Here’s what happens as we change the paint thickness. The solid black line represents a reasonable paint thickness (5 microns).

As we can see, the transfer function is highly dependent on the thickness of the paint: If the paint is too thin, we get dominance of the aluminium block on the transfer function, which reduces the signal gain very significantly at higher frequencies. As the paint layer thickens, it starts dominating the transfer function – but knowing the paint thickness might be a challenge.

A solution to this issue is to use an insulating film of similar properties to the paint binder (in this case, the binder used for the calculations was a Polyacrylic Acid polymer). Most importantly, if the two materials have similar characteristic impedances (Z_0), then the transfer function obtained will not be as dependent on the paint thickness.

Polyacrylic acid has the following thermal properties (sources here and here). The film considered here is a PET film (this one).

Polyacrylic acidPET Film
k0.543 W/m K0.21 W/m K
c_p1248 J/Kg K1465 J/Kg K
\rho1440 Kg/m31170 Kg/m3
Z_01.01\times 10^{-3} \sqrt{-j\omega^{-1}}1.67\times 10^{-3} \sqrt{-j\omega^{-1}}
\gamma1819 \sqrt{j\omega}2856 \sqrt{j\omega}

As we can see, the thermal impedance of the two materials is somewhat similar. This means less reflection will occur at the interface; which will help with a reduced dependence of the transfer function on the paint coat thickness. The circuit analyzed becomes the following:

This graph shows a great improvement; because the transfer function at higher frequencies is less dependent in the paint thickness. Not perfect – this would only be possible with a perfect match of thermal impedances. Nevertheless, this can definitely be used to make some measurements.

As a remark – the frequencies of interest in this work are around 20 kHz. The gain is then about -38dB (5 microns paint thickness); which is defined as 20 \log_{10}[(T_p-T_h)/(T_\infty -T_h)]. This corresponds to a signal gain of 0.011 – or; for every 1 degree of temperature fluctuation in T_\infty, we get one hundreth of a degree of fluctuation in the paint surface temperature; which is quite a small signal. Since the TSP gives a signal of about 1.4%/ºC, we are talking about an intensity signal of I/I_0 = 0.014 \times 0.011 = 1.54 \times 10^ {-4}, or 0.6 counts/ºC of a 12-bit camera where I_0 exactly saturates the camera (most likely not). I expect this paint measurement system to (hardly) detect temperature fluctuations of 10ºC pk-pk; considering good post-processing and noise reduction to reject camera noise and a very tame signal (like a pure frequency).

I’ll post updates as we perform experiments!

Tying it all back to the fourier number

So we see this interesting transfer function that switches between the lumped RC circuit assumption (with a -20dB/decade decay) to the continuous transmission line (with a -10dB/decade decay). Why does that happen and where is the “kink” in the graph?

Well, we’ll see this ties back to the thermal theory; once we find the kink frequency: The kink is where the -20dB/decade and the -10dB/decade cross. At the -20dB/decade regime, a slab of material has behaves as a capacitor and its thermal impedance is:

\displaystyle Z_C=\frac{1}{j \omega C} = \frac{1}{j \omega C' L}

We have the definition of C' in the previous sections – so let’s focus on the math. The thermal impedance of the slab in the -10dB/decade regime is simply its characteristic impedance (another interpretation is that in the -10dB/decade regime the slab is effectively infinite).

\displaystyle Z_0=\sqrt{\frac{R'}{j \omega C'} }

The kink is located about where |Z_C|=|Z_0|:

\displaystyle \bigg|\sqrt{\frac{R'}{j \omega C'} }\bigg| = \bigg|\frac{1}{j \omega C' L}\bigg|

\displaystyle \frac{R'}{\omega C'} = \frac{1}{\omega^2 C'^2 L^2}

This gives us the radian frequency of the kink:

\displaystyle \omega_{kink}=\frac{1}{L^2} \frac{1}{R' C'}

Now you should already be recognizing that we have an interesting non-dimensional coming up, as \alpha = 1/R' C':

\displaystyle \omega_{kink}=\frac{\alpha}{L^2} \rightarrow \boxed{f_{kink}=\frac{\alpha}{2 \pi L^2}}

The non-dimensional is; obviously; the Fourier number:

\displaystyle Fo=\frac{\alpha}{\omega_{kink} L^2}=1

We usually see the Fourier number with a time in the numerator (Fo=\alpha t/L^2), but this is the same kind of transient phenomenon. If the Fourier number is larger than 1, the “time scales” are large (low frequencies) and the heat transfer of the slab can be modeled by a simple capacitor. If the Fourier number is smaller than 1, then the “time scales” are small (high frequencies) and the heat transfer needs the heat equation to be modeled, which we are simply doing by using the transmission line model. The analogy is quite powerful and enables simple, quick analysis of these systems.

I boxed the f_{kink} equation because it is quite useful to determine whether our AC analysis needs to consider the transmission line model; knowing the frequencies of interest. Hope this provides the insight you needed for your analyses!

Sound Visualization: The theory works! – Part IV

So in this (last) episode of our quest to visualize sound we have to do some sound-vis experiment; right? Well, I did the experiment with an ultrasonic manipulator I was working on a couple months ago. I built a Z-Type shadowgraph (turns out I didn’t have enough space on the optical table for a knife edge because the camera I used is so enormous) with the following characteristics (see part II for nomenclature):

\displaystyle f_2=2m

\displaystyle g=1m

\displaystyle L=0.13m

For this first experiment I used a phased array device with 64 ultrasonic transducers:

When I give all transducers the same phase, they are supposed to produce a plane-like wave. This is how the wave looks like in this shadowgraph setup:

Where the oscillation levels are plus and minus 50 levels from the background level. Thus, we have N_{lv}=100 and the expected pressure fluctuation at 40kHz is 257 Pa, corresponding to a SPL of 142.2dB. Quite loud!

A measurement with a very good microphone (B&K 4939) gave me a pressure fluctuation of 230 Pa – which is quite close to the expected value from the shadowgraph!

I made a little video explaining the details of the setup and there’s some really nice footage of acoustic manipulators I built on it. Perhaps you can find some inspiration on it:

So this post was rather short. Most of the content is in the video, so I hope you have a look!

Sound Visualization: Nonlinearities – Part III

As discussed in Parts I and II, we established that we can use a Schlieren or a shadowgraph apparatus to visualize sound waves. The shadowgraph is not as interesting an instrument, due to its stronger high-pass behavior. Nevertheless, both instruments are viable as long as one makes it sensitive enough to see the waves.

When reading the previous posts, the keen reader might be weary of my isothermal assumption when applying the ideal gas law. Shouldn’t temperature also be a spatial wave? The consequence, obviously, would be that the waves become sharper with increasing loudness and easier to visualize as the non-linearity kicks in. The reader would be rather right, the non-linearity effect can be significant in some cases. But for reasonable sound visualization, the pressure fluctuation amplitude has to be above about 1 order of magnitude of the ambient pressure in order for this effect to change the wave enough. Let’s look into the math:

For a compressible flow, assuming isentropic sound waves, we have:

\displaystyle \frac{\rho}{\rho_a} = \bigg(\frac{P}{P_a} \bigg)^{1/\gamma}

Where \gamma is the specific heat ratio for the gas under analysis. A pressure wave of the form P=P_a + P_0 e^{i(\omega t-kx)} then becomes a density wave of the form:

\displaystyle \rho=\rho_a \bigg[1+\frac{P_0}{P_a} e^{i(\omega t - kx)} \bigg]^{1/\gamma}

Taking the x derivative:

\displaystyle \frac{\partial \rho}{\partial x} = -\frac{i\rho_a P_0/P_a e^{i\omega t} (k/\gamma) \big[1+(P_0/P_a) e^{i(\omega t-kx)}\big]}{P_o/P_a e^{i\omega t} + e^{i kx}}

Staring at this expression for long enough reveals we can separate the non-linearity term from the remaining terms:

\displaystyle \frac{\partial \rho}{\partial x} \frac{\gamma}{\rho_a k} = -\frac{i P_0/P_a e^{i\omega t} \big[1+(P_0/P_a) e^{i(\omega t-kx)}\big]}{P_o/P_a e^{i\omega t} + e^{i kx}}=N(P_0)

The non-linear function N(P_0) represents the wave steepening as the amplitude becomes sufficiently high. Looking at the phasor in the denominator (P_o/P_a e^{i\omega t} + e^{i kx}) we see the derivative operator split the time fluctuations from the spatial component of the fluctuation. For our detectability purposes, what really matters is the minimum and maximum value of N(P_0) to get a sense of a peak-to-peak amplitude. In this case, the phasor minimum amplitude happens at:

\displaystyle \min |N(P_0)|=\frac{P_0/P_a \big[1-P_0/P_a \big]^{1/\gamma}}{1+P_0/P_a}

Similarly, the maximum happens when the phasor at the denominator minimum point:

\displaystyle \max |N(P_0)|=\frac{P_0/P_a \big[1+P_0/P_a \big]^{1/\gamma}}{1-P_0/P_a}

Note this value can even be zero, at about 194dB SPL, in which case these equations blow up to infinity. Nevertheless, the difference gives us the peak-to-peak amplitude of the non-linear derivative of density:

\displaystyle N_{pk-pk}=\frac{P_0}{P_a} \frac{\big[1+P_0/P_a \big]^{1/\gamma} - \big[1-P_0/P_a \big]^{1/\gamma}}{1-(P_0/P_a)^2}

Finding the minimum SPL as a function of wavelength is not as simple, since the non-linear function makes it difficult to isolate P_0. However, we can do the opposite – isolate the frequency and plot the points with the axes flipped. To do so, let’s isolate the wavenumber:

\displaystyle k=\frac{2}{\rho_a} \frac{\partial \rho}{\partial x}\bigg|_{\min} \frac{\gamma}{N_{pk-pk}}

The factor of 2 comes from the fact that the calculations performed in the previous section considered the amplitude of the sine wave, not its peak-to-peak value. Now we can replace the equations for the Schlieren sensitivity to obtain:

\displaystyle F=\frac{c}{\pi \rho_a } \frac{\gamma}{N_{pk-pk}} \bigg[\frac{1}{G(\lambda)} \frac{n_0}{L} \frac{a}{f_2} \frac{N_{lv}}{2^{n_{bits}-1}} \bigg] (Schlieren)

For the shadowgraph, a second derivative needs to be taken. But as shown in the chart below, the non-linearity only becomes relevant above about 180dB. In the case you get to these SPL values, you probably have a lot more to worry on the compressibility side of things. But it comes as good news that we can use a simple relation (like the one derived in Part I) to draw insight about sound vis.

Comparison of minimum sensitivity for the linear (black) relationship derived in Part I and the compressible, non-linear relation derived here. Parameters are the same: f_2=2 m, a=1 mm, L=0.1 m and N_{lv}=5

Schlieren vs Shadowgraph for Sound Visualization – Part II

This continues our saga we started at Part I (spoiler alert: you’re probably better off with a Schlieren). Thanks to a good discussion with my graduate school friend Serdar Seckin, I got curious about applying the same sensitivity criterion to a shadowgraph system. Turns out, Settles’ book also has the equations for contrast in the case of a shadowgraph (equation 6.10). It is even simpler, since the contrast is a purely geometrical relation:

\displaystyle C_x=\frac{\Delta E_x}{E}=\frac{\partial \epsilon}{\partial x} g

Where g is the distance between the “screen” (or camera focal plane, in case of a focused shadowgraph) and the Schlieren object. Since the ray deflection occurs in the two directions perpedicular to the optical axis (x and y), we get a contrast in the x direction (C_x) and another in the y direction (C_y). The actual contrast seen in the image ends up being the sum of the two:

\displaystyle C = C_x + C_y=g \bigg(\frac{\partial \epsilon}{\partial x} + \frac{\partial \epsilon}{\partial y}\bigg)

Since the ray deflection \epsilon is dependent on the Schlieren object (as discussed in Part I), we can plug its definition to get:

\displaystyle C = \frac{L g}{n_0} \nabla_{xy}^2 n

Which is the “Laplacian” form of the Shadowgraph sensitivity. Laplacian between quotes, since it does not depend on the z derivative. We can plug in the Gladstone-Dale relation and the ideal gas law to isolate the pressure Laplacian:

\displaystyle \nabla_{xy}^2 P = \frac{C R T}{G(\lambda)} \frac{n_o}{L g}

Replacing the traveling wave form P=P_0 \exp(i[\omega t - \kappa_x x - \kappa_y y]), now obviously considering the two-dimensional wavenumber in the directions perpendicular to the optical axis:

\displaystyle P_0 = -\frac{\big(\nabla_{xy}^2 P \big)\exp(-i[\omega t - \kappa_x x - \kappa_y y])}{\kappa_x^2 + \kappa_y^2} = -\frac{\big(\nabla_{xy}^2 P \big) P \exp(-i[\omega t - \kappa_x x - \kappa_y y])}{\kappa_{xy}^2}

Where \kappa_{xy}^2 is the squared wavenumber vector magnitude, projected in the x,y plane. Applying the same criterion of N_{lv} levels for minimum contrast, we get the following relation for the minimum detectable pressure wave:

\displaystyle P_{min} = \frac{RT}{G(\lambda)} \frac{n_0}{Lg} \frac{N_{lv}}{2^{n_{bits}-1}} \frac{1}{\kappa_{xy}^2}

Which we can easily convert to minimum SPL based on the wave frequency F:

\displaystyle \boxed{SPL_{min} = 20\log_{10} \bigg(\frac{RTc^2}{4\pi^2 P_{ref}G(\lambda)} \frac{n_0}{Lg} \frac{1}{F^2} N_{lv}\bigg)- 6.02(n_{bits}-1)}

design consequences

The boxed formula for shadowgraph is very similar to the one for Schlieren found in Part 1. By far, the most important point is the dependence on 1/F^2 [Shadowgraph] instead of 1/F [Schlieren]. This is obvious, since Schlieren detects first derivatives of pressure, whereas Shadowgraph detects second derivatives, popping out an extra F factor.

From a detector apparatus perspective, however, this is not of the most desirable features: The shadowgraph acts as a second-order high-pass spatial filter, highlighting high frequencies and killing low frequencies. The Schlieren has a weaker, first-order high pass filtering behavior. But this means they have a crossing point, a frequency F where the sensitivity is the same for both. The apparatus parameters are different, however we can do the exercise for the rather realistic apparatus given in Part 1. If we make g=0.5 m (i.e., the focal plane is 0.5 meters from the Schlieren object), we get the following curve for a 12-bit camera:

Minimum detectable sound levels – Schlieren versus Shadowgraph. Schlieren parameters: f_2=2 m, a=1 mm. Shadowgraph has g=0.5 m. Both consider N_{lv}=5 and L=0.1 m.

If the news weren’t all that great for the Schlieren apparatus, the Shadowgraph is actually worse: The crossing point for this system occurs at F=200 kHz. There might be applications where these ultrasound frequencies are actually of interest, but I believe in most fluid dynamics problems the Schlieren apparatus is the to-go tool. Remembering that, even though I show SPL values above 170dB in this chart, the calculations considered a constant-temperature ideal gas, which is not the case anymore at those non-linear sound pressure levels.

With this, I’m declaring Schlieren a winner for sound-vis.

Seeing Sound Waves with your Schlieren apparatus – Part I

Tell me: Would you be excited to see sound? Well, I sure damn was when I first attempted to see the sound produced by an ultrasonic transducer! And still am, to be honest! So let’s learn how to do it with a Schlieren apparatus and the sensitivity considerations necessary in the design of a Schlieren optical system. For this, I’ll use my handy Schlieren and Shadowgraph techniques by no one else than the great Prof. Gary Settles. My PhD advisor, Prof. Alvi, was his PhD student – so I should get this right!

I’m a practical engineer, but I’ll derive the formulas in this section. If you want, you can skip ahead to the next section where I apply them and produce nice design charts.

the math

If you would like more details on the physics, please refer to Settles. This is more of a derivation section. We’ll start with the Gladstone-Dale law, which relates the index of refraction of a gas to its density:

\displaystyle n-1 = G(\lambda) \rho

Where n is the index of refraction, G(\lambda)=2.2244\times10^{-4}\big[1+(6.37132\times 10^{-8}/\lambda)^2\big] m^3/Kg (for air) is the wavelength-dependent Gladstone-Dale constant and \rho is the density of the gas.

Assuming a parallel light beam, the beam deflection \epsilon of a uniform Schlieren object of length L is given by:

\displaystyle \epsilon = \frac{L}{n_0} \frac{\partial n}{\partial x}

Where x is the direction of deflection. This deflection is magnified in the focal point of the optical apparatus mirror/lens close to the camera/screen; where the knife-edge is placed, according to:

\displaystyle \Delta a=f_2 \epsilon

Where \Delta a is the change in the focal point location in the direction perpendicular to the knife edge and f_2 is the focal length of the second optical element (lens/mirror). Then, the contrast change C observed in the camera/screen is given by Equation 3.6. in Settles’ book:

\displaystyle C=\frac{\Delta E}{E} = \frac{f_2 \epsilon}{a}

We can use the ideal gas law to combine the expressions as a function of \partial P/\partial x:

\displaystyle \frac{\partial P}{\partial x} = \frac{RT}{G(\lambda)} \frac{a}{f_2} \frac{n_0}{L} C

We can then assume we are looking for sinusoidal sound waves of the form P(x,t)=P_0 \exp(i[\omega t - \kappa x]):

\displaystyle \frac{\partial P}{\partial x} = i\kappa P_0 \exp(i[\omega t - \kappa x])

OK. Now let’s stop here for a while. I think it goes without saying you’ll probably need a high speed camera to see the sound waves, as they aren’t among the mundane things you can use your regular DSLR to observe. Given that, we can consider whichever camera you’ll use has some bit depth n_{bits}. When setting up your Schlieren apparatus, you’ll probably use half of the dynamic range of the camera for the “background” frame. This means, your intensity E is about half of the dynamic range of the camera. In bit count, you’ll have \displaystyle E=N_{BG}=2^{n_{bits}-1} as the background, undisturbed luminance level. Now, let’s assume you need at least \Delta E = N_{lv} levels to distinguish the signal from the noise. Maybe you have some de-noising method, like POD, that improves your SNR and your sensitivity. How loud do the sound waves need to be in order to produce a N_{lv} signal given you have a N_{BG} background luminance?

Let’s isolate P_0:

\displaystyle P_0 = \frac{\partial P}{\partial x} \frac{1}{\kappa} \underbrace{\big\{-i\exp(-i[\omega t - \kappa x])\big\}}_{\text{included in } N_{lv}} = RT \frac{1}{\kappa} \frac{1}{G(\lambda)} \frac{a}{f_2} \frac{n_0}{L} C

Using our bit depth, we get the minimum pressure disturbance to be:

\displaystyle P_{min} = RT \frac{1}{\kappa} \frac{1}{G(\lambda)} \frac{a}{f_2} \frac{n_0}{L} \frac{N_{lv}}{2^{n_{bits}-1}}

Converting to sound pressure level (SPL):

\displaystyle SPL_{min} = 20 \log_{10} \bigg(\frac{P_{min}}{P_{ref}} \bigg) = 20 \log_{10}\bigg({\underbrace{\frac{RT}{P_{ref}}}_{1/\rho_{ref}} \frac{1}{\kappa} \frac{1}{G(\lambda)} \frac{a}{f_2} \frac{n_0}{L} \frac{N_{lv}}{2^{n_{bits}-1}}}\bigg)

\displaystyle SPL_{min} = 20 \log_{10}\bigg(\frac{RT}{P_{ref}}\frac{1}{\kappa} \frac{1}{G(\lambda)} \frac{a}{f_2} \frac{n_0}{L} N_{lv}\bigg) - 20 (n_{bits}-1) \log_{10}(2)

Evaluating the \log_{10}(2) and replacing \kappa = 2\pi F/c:

\displaystyle \boxed{SPL_{min} = 20 \log_{10}\bigg(\frac{cRT}{2\pi P_{ref}} \frac{1}{G(\lambda)} \frac{1}{F} \frac{a}{f_2} \frac{n_0}{L} N_{lv}\bigg) - 6.02(n_{bits}-1)}

A capital F is used for frequency to eliminate confusion with f, which in this context is the mirror focal length. If you know the background level, N_{BG}, then you might want to expose it in the formula instead of the bit depth of the camera pixels:

\displaystyle SPL_{min} = 20 \log_{10}\bigg(\frac{cRT}{2\pi P_{ref}} \frac{1}{G(\lambda)} \frac{1}{F} \frac{a}{f_2} \frac{n_0}{L} \bigg) + 20 \log_{10}\bigg(\frac{N_{lv}}{N_{BG}}\bigg)

usage in design

The boxed formula is extremely useful for sound visualization design, as it allows us to define whether we can even see the sound waves we want to. First, a few remarks: I separated the bit depth because the 6 n_{bits} appears in so many places. In this case, we have it with a negative sign, which is awesome, since in the end we want to minimize SPL_{min} to maximize sensitivity. The first fraction inside the \log() is a constant, dependent on the gas and the reference pressure. For air at 25ºC, cRT/2\pi P_{ref} = 2.335\times 10^{11} m^4/Kg\cdot s.

Note that the minimum SPL is inversely proportional to the frequency F. This means, higher frequencies are easier to see. Ultrasonic frequencies, in particular, are somewhat straightforward to see, as we will discuss. Let’s plot SPL_{min} as a function of frequency for a typical large-scale Schlieren apparatus:

Sensitivity of an air-based Schlieren aparatus with f_2=2 m, a=1 mm, L=0.1 m and N_{lv}=5

The black line represents the bit depth of most contemporary scientific cameras. As you can see, the news aren’t that great: For low frequencies, we have to scream really loud to see anything – and this is after blowing up the image such that we can only see 5 levels! For example, for a frequency of 5kHz we have about 128dB of minimum sound pressure level to be perceived by our camera. It’s not impossible, and with the advent of new data processing techniques like POD it is well feasible. But wouldn’t it be great to have 4 more bits per pixel (red dashed line)? That would bring the minimum SPL to 104dB, which would enable the visualization of a lot of phenomena (and even a rock concert!).

Well, I hope this helps you design your own Schlieren apparatus. Or maybe you lose hope altogether and quit – but at least this saved you time! If you want to design your own Schlieren setup to visualize sound waves, you can download the code that generated the chart above here. Anyhow, here’s a little video of how sound waves look like for a really loud (~140dB, ~5kHz) supersonic jet: