-
Notifications
You must be signed in to change notification settings - Fork 0
Basic Usage
To start getting results, all you need to know is PyAngstrom's
analyze_recording!
You can import it like so
from pyangstrom import analyze_recordingTo use analyze_recording, you only need two pieces of data -- a thermal video
of your sample material and a configuration file specifying how to analyze the
video. (Currently, this library can only read the CSV exports of FLIR thermal
cameras. If you need support for a different format of thermal video, please
submit an issue with the title "Thermal Video
Request: [the format of your thermal video]" and add more details in the
description. We apologize for the inconvenience of this requesting system, as we
do not have the resources to revamp it yet.)
The thermal video and configuration file are respectively passed into
analyze_recording as a path recording_path and as either a dict or another
path config.
For example, if you had a directory Rec-000001 with CSV temperature files in
it:
C:\Users\Name\Documents\Rec-000001\
Rec-000001_1.csv
Rec-000001_2.csv
Rec-000001_3.csv
...
you would pass in r"C:\Users\Name\Documents\Rec-000001\" for recording_path.
(Confused about the "r" before the quotes? Read this:
https://realpython.com/python-raw-strings/.)
Next, you pass in a specifically formatted dict (we will go over the exact
format below) or the path to a JSON file with the same information into
config. For example, if you had a configuration file Rec-000001_config.json
located in folder C:\Users\Name\Documents, you would pass
r"C:\Users\Name\Documents\Rec-000001_config.json" in for config.
In summary, to use analyze_recording, you need to call it with some code that
looks like this (raw string not used here because not all markdown renderers
recognize it):
analyze_recording(
"C:\\Users\\Name\\Documents\\Rec-000001",
"C:\\Users\\Name\\Documents\\Rec-000001_config.json",
)It will return different values depending on exactly how you have configured it.
Now, what exactly does Rec-000001_config.json look like?
Here's the moment you have all been waiting for: a full example of a configuration file!
// Rec-000001_config.json
{
"experimental_setup": {
"heating_frequency_hertz": 0.1,
"meters_per_pixel": 2.5e-05,
"material_properties": {
"specific_heat_capacity_J__kg_K": 385.0,
"density_kg__m3": 8960.0
}
},
"region_information": {
"geometry": {
"min_x_pixels": 348,
"max_x_pixels": 521,
"min_y_pixels": 103,
"max_y_pixels": 311,
"heat_source_x_pixels": 558
},
"structure": {
"average_out_span": true,
"num_deinterleaving_groups": 5
}
},
"signal_processor": {
"name": "fft",
"apply_filter": false
},
"solver": {
"name": "log_lopez-baeza",
"guesses": {
"thermal_diffusivity_log10_m2__s": -5,
"convective_heat_transfer_coefficient_log10_W__m2_K": -2
},
"parameters": {
"r_meters": 0.00137,
"length_meters": 0.0408
}
},
"fitter": {
"name": "nelder-mead",
"parameters": {
"properties_to_use": "phase-amplitude"
}
}
}Now, if you are using this library, you probably know that performing the
Angstrom method requires a few steps. analyze_region runs your thermal video
through a pipeline that is broken up into three stages:
- Crop out the region of the video you actually want to analyze.
- Use signal processing to extract out temperature amplitude ratios and phase differences.
- Fit a heat model to the ratios and differences to compute your final thermal conductivity!
You specify exactly how analyze_region performs each of these stages in
config. config itself is also split into multiple sections. We will go over
each section in detail below, but you can bookmark the documentation for the
Config type definition
as a quick reference for later. (Each section features snippets of
Rec-000001_config.json but rewritten in Python, as that is the main focus of
this wiki. They look similar, but watch out for the differences!)
This section contains information that is often used throughout the entire pipeline.
{
'experimental_setup': {
'heating_frequency_hertz': 0.1,
'meters_per_pixel': 2.5e-05,
'material_properties': {
'specific_heat_capacity_J__kg_K': 385.0,
'density_kg__m3': 8960.0,
},
},
}Its fields are described in the ExperimentalSetup
documentation,
but 'meters_per_pixel' may need more explanation. It refers to the real-world
width, in meters, that one pixel of your video covers on the material sample. In
other words, it links the resolution of your video to the physical size of what
you are filming.
In this section, you specify the region or regions you want to crop out of the video.
{
'region_information': {
'geometry': {
'min_x_pixels': 348,
'max_x_pixels': 521,
'min_y_pixels': 103,
'max_y_pixels': 311,
'heat_source_x_pixels': 558,
},
'structure': {
'average_out_span': True,
'num_deinterleaving_groups': 5,
},
},
}There are several formats you can use. This snippet specifies a single rectangular region, heated by a line-source from the positive x-direction, that will have its temperatures averaged along the y-axis and then split up again into 5 groups, where each point of temperature is 5 pixels apart from the next point in its group.
The Config documentation somewhat lists all the formats you can use, but the
first thing to take note of is that in 'region_information', you can tell
analyze_region to extract either one region (such as a rectangular cutout) or
multiple regions (such as different sectors of an annulus). You specify just one
region by assigning to 'region_information' a dict in the format of
RegionConfig,
which is what the above snippet does. You can specify multiple regions by using
the
RegionBatchConfig
format or assigning to 'region_information' a list of dicts, which can
either be in RegionConfig or RegionBatchConfig format.
Next, RegionConfig and RegionBatchConfig both have a field in which you put
geometry (geometry and geometries, respectively). Geometry can either be
rectangular
(CartesianGeometry)
or circular
(PolarGeometry).
You assign geometry a dict in one of these formats and you assign
geometries a list of dicts in these formats. Both region config variants
also have a structure field, which gives you a handful of options to
manipulate and reorganize your temperatures to be easier to use, all listed
under the RegionStructure
documentation.
As a word of caution, your results may come out with different groupings in terms of their array dimensions or how they are nested in lists depending on the splitting and aggregation options you use, so you may have to do some inspection to see exactly how your results are structured.
In this section, you specify exactly how you want to extract amplitude ratios and phase differences from the temperatures you have cropped out.
{
'signal_processor': {
'name': 'fft',
'apply_filter': False,
},
}This snippet tells analyze_region to use a fast fourier
transform
to process the temperature data stream and to not apply any filter
preprocessing.
You can use one of the built-in signal processors by finding it in the wiki
reference
page
and assigning the corresponding string to 'name'. You can also find more
details about the other fields in the SignalProcessorInformation
documentation.
In this section, you specify your heat model and provide any additional information it would need to be fit to your amplitude ratios and phase differences.
{
'solver': {
'name': 'log_lopez-baeza',
'guesses': {
'thermal_diffusivity_log10_m2__s': -5,
'convective_heat_transfer_coefficient_log10_W__m2_K': -2,
},
'parameters': {
'r_meters': 0.00137,
'length_meters': 0.0408,
},
},
}This snippet tells analyze_region to use a model in which heat propagates
linearly across a sample measured in Cartesian coordinates and only allows the
log of the unknowns to be varied in
fitting.
This model also requires constants r and length to be specified for you to
use it.
Similar to using built-in signal processors, you can find a model on the
Sample Solutions page and then enter its 'name' into this section. Each
model takes in initial 'guesses' for each of the unknowns that need to be
solved for, as well as constant 'parameters' needed to initialize the model,
both of which are described under that model's wiki section.
In this section, you specify exactly how you want to fit your heat model to your amplitude ratios and phase differences.
{
'fitter': {
'name': 'nelder-mead',
'parameters': {
'properties_to_use': 'phase-amplitude',
},
},
}This snippet tells analyze_region to use the Nelder-Mead method to minimize
squared
error.
This built-in fitting method also gives the option to choose which signal
properties to use to calculate the error. This snippet chooses to use both
amplitude ratios and phase differences.
Following the pattern established in Signal
Processor
and
Solver,
you can once again find one of the Built-in Fitting
Methods
and copy over its 'name'. Some may have 'parameters' that change how they
work. You can see what they are and whether they are required or optional on the
wiki page.
Knowing how to set recording_path and config already allows you to make full
use of analyze_recording's analysis capabilities, but analyze_recording also
sports a few more parameters that may make it more convenient or helpful to use.
They are listed below in order of what may be more relevant to use to what is
probably less relevant to most, but it is worth reading about and being aware of
all of them anyways.
analyze_recording returns the final results of its processing as just numbers.
If you set return_visualization=True, however, each result object will be
paired with a graphic that tries to visualize it with intuitive and detailed
graphs. You can see how to use these graphics in our full example in
Python.
Directly loading the FLIR camera's CSV files for each run of analyze_recording
can be time consuming. To address this, analyze_recording has a feature to
save this thermal camera data into a more efficient file format that takes only
a fraction of the time to load. To use this feature, set recording_cache_path
to a directory in which you would like to save these new files.
analyze_recording will save to this directory when processing a recording the
first time, and it will try to find the cache file in this directory for every
subsequent run.
As of this repository's latest version, this feature has not been implemented yet.
analyze_recording will normally try to catch exceptions and return whatever
results it has calculated so far (to save you time from rerunning all your
analysis), but setting debug=True will allow exceptions to bypass
analyze_recording's error handling and show themselves in full. Though, this
option is really only helpful for developers.
Now that you are fully acquainted with analyze_recording, here's a script that
you can almost basically copy into Python and run as is! (You would still need
to have a folder with data and remove the one commented line.) Keep in mind that
this uses a different config than what is shown in config's
Format,
so you can see variations of each section.
import matplotlib.pyplot as plt
from pyangstrom import analyze_recording
from pyangstrom.helpers import calc_thermal_conductivity
results, figures = analyze_recording(
'C:\\Users\\Name\\Documents\\Rec-000002',
{
'experimental_setup': {
'heating_frequency_hertz': 0.1,
'meters_per_pixel': 2.5e-05,
'material_properties': {
'specific_heat_capacity_J__kg_K': 385.0,
'density_kg__m3': 8960.0,
},
},
'region_information': [
{
'geometries': [
{
'center': {
'x_pixels': 358.0,
'y_pixels': 217.0,
},
'min_r_pixels': 55.0,
'max_r_pixels': 105.0,
'num_r': 50,
'min_theta_degrees': 0.0,
'max_theta_degrees': 45.0,
'num_theta': 180,
},
{
'center': {
'x_pixels': 358.0,
'y_pixels': 217.0,
},
'min_r_pixels': 55.0,
'max_r_pixels': 105.0,
'num_r': 50,
'min_theta_degrees': 45.0,
'max_theta_degrees': 90.0,
'num_theta': 180,
},
... # NOTE: Remaining geometries left out for brevity
],
'structure': {
'average_out_span': True,
'num_deinterleaving_groups': 5,
},
'average_over_regions': True,
},
],
'signal_processor': {
'name': 'fft',
'apply_filter': False,
},
'solver': {
'name': 'log_kil',
'guesses': {
'thermal_diffusivity_log10_m2__s': -5,
'convective_heat_transfer_coefficient_log10_W__m2_K': 1,
},
'parameters': {
'sample_thickness_meters': 0.00158,
'heating_source_radius_meters': 0.0013,
'outer_boundary_radius_meters': 0.048,
},
},
'fitter': {
'name': 'nelder-mead',
'parameters': {
'properties_to_use': 'phase-amplitude',
},
},
},
return_visualization=True,
recording_cache_path='C:\\Users\\Name\\Documents\\pyangstrom_cache',
)
for r in results:
k = calc_thermal_conductivity(
10**r.unknowns_solutions['thermal_diffusivity_log10_m2__s'],
specific_heat_capacity_J__kg_K=385.0,
density_kg__m3=8960.0,
)
h = 10**r.unknowns_solutions['convective_heat_transfer_coefficient_log10_W__m2_K']
print(
f'conductivity {k} m^2/s\n'
f'coefficient {h} W/m^2K'
)
plt.show()Take note of how this example passes config in directly as a dict instead
and how 'region_information' uses the list[RegionBatchConfig] format
(though, with only one RegionBatchConfig in the list). It also uses the
'log_kil' heat model, which needs different parameters than
'log_lopez-baeza'.
This example also includes optional arguments. We are specifying a directory in
which to save thermal video cache files with recording_cache_path. And
return_visualization causes analyze_recording to not only return its normal
results but to generate visualizations using
Matplotlib and pair them up with the results in a
tuple. (The actual visualization objects are lists of
Figures, arranged in the
same way as the lists of result objects.)
If analyze_recording finishes running successfully, results should be a
list of
FittingResults
(More result object types are explained in the Advanced Usage guide).
FittingResults have an attribute unknowns_solutions, a dict with the same
fields as 'solver''s 'guesses', but with values that have been computed from
the actual data. The example loops over each FittingResult, pulling out each
value and using them to calculate final numbers that are more understandable.
Here,
calc_thermal_conductivity
is also used, one of the functions provided by pyangstrom for convenience,
which can be imported from the pyangstrom.helpers module. Lastly, the example
calls plt.show(), which tells Matplotlib to actually show the new
visualizations.
And with that, we have gotten through all of Basic Usage! It may have seemed like a lot, but I have no doubt you will eventually come around to needing even more functionality. When that time arrives, please read on with the Advanced Usage guide, where there are juicy details about how to customize PyAngstrom, how it works under the hood, and other "hidden" features not mentioned here. May your thermal analysis experiments run smoothly and advance knowledge for all!