Working with Imperial and FPS Units¶
Try it live on Compiler Explorer
Overview¶
Many engineering domains, particularly naval and aerospace applications, use the imperial foot-pound-second (FPS) unit system. This example demonstrates seamless interoperability between imperial/FPS units and SI, using World War II battleship specifications as a practical case study.
Key Concepts¶
Multi-System Definitions¶
Real-world applications often need to work with data defined in different unit systems:
// Some basic specs for the warship
struct Ship {
quantity<isq::length[ft]> length;
quantity<isq::length[ft]> draft;
quantity<isq::length[ft]> beam;
quantity<isq::speed[ft / s]> speed;
quantity<isq::mass[lb]> mass;
quantity<isq::length[in]> mainGuns;
quantity<isq::mass[lb]> shellMass;
quantity<isq::speed[ft / s]> shellSpeed;
quantity<isq::power[ft * pdl / s]> power;
};
The Ship structure naturally expresses specifications in FPS units, as they would appear
in historical naval documentation.
Transparent Unit Conversion¶
The example shows how to display the same quantity in multiple unit systems simultaneously:
// Print 'q' in its current units and print its value cast to the units in each of Us
template<Unit auto... Us, Quantity Q>
auto fmt_line(const Q& q)
{
return MP_UNITS_STD_FMT::format("{:22:N[.2f]}", q) +
(MP_UNITS_STD_FMT::format(",{:20:N[.2f]}", value_cast<Us>(q)) + ...);
}
This fmt_line helper function prints a quantity in its native units plus converted to
alternative systems, making it easy to compare specifications across different engineering
traditions.
Real-World Application¶
The example models three WWII battleships, each defined in their historically appropriate units:
// KMS Bismark, using the units the Germans would use, taken from Wiki
auto bismark = Ship{.length{251. * m},
.draft{9.3 * m},
.beam{36 * m},
.speed{56 * km / h},
.mass{50'300 * t},
.mainGuns{380 * mm},
.shellMass{800 * kg},
.shellSpeed{820. * m / s},
.power{110.45 * kW}};
// USS Iowa, using units from the foot-pound-second system
auto iowa = Ship{.length{860. * ft},
.draft{37. * ft + 2. * in},
.beam{108. * ft + 2. * in},
.speed{33 * kt},
.mass{57'540 * imperial::long_ton},
.mainGuns{16 * in},
.shellMass{2700 * lb},
.shellSpeed{2690. * ft / s},
.power{212'000 * hp}};
// HMS King George V, using units from the foot-pound-second system
auto kgv = Ship{.length{745.1 * ft},
.draft{33. * ft + 7.5 * in},
.beam{103.2 * ft + 2.5 * in},
.speed{28.3 * kt},
.mass{42'245 * imperial::long_ton},
.mainGuns{14 * in},
.shellMass{1590 * lb},
.shellSpeed{2483. * ft / s},
.power{110'000 * hp}};
Notice:
- KMS Bismarck: Defined in SI/metric units (meters, kg, km/h) as used by Germany
- USS Iowa & HMS King George V: Defined in FPS units (feet, inches, pounds, knots) as used by USA and UK
- All mixed types work seamlessly without manual conversions
Multi-Column Output¶
The print_details function demonstrates displaying quantities in original, alternative imperial, and SI units:
// Print the ship details in the units as defined in the Ship struct, in other si::imperial units, and in SI
void print_details(std::string_view description, const Ship& ship)
{
const auto waterDensity = 62.4 * isq::density[lb / cubic(ft)];
std::cout << MP_UNITS_STD_FMT::format("{}\n", description);
std::cout << MP_UNITS_STD_FMT::format("{:20} : {}\n", "length", fmt_line<yd, m>(ship.length))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "draft", fmt_line<yd, m>(ship.draft))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "beam", fmt_line<yd, m>(ship.beam))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "mass", fmt_line<imperial::long_ton, t>(ship.mass))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "speed", fmt_line<kt, km / h>(ship.speed))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "power", fmt_line<hp, kW>(ship.power))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "main guns", fmt_line<in, mm>(ship.mainGuns))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "fire shells weighing",
fmt_line<imperial::long_ton, kg>(ship.shellMass))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "fire shells at", fmt_line<mph, km / h>(ship.shellSpeed))
<< MP_UNITS_STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line<m3, l>(ship.mass / waterDensity));
}
Sample Output:
KMS Bismark, defined in appropriate units from the SI system
length : 823.49 ft, 274.50 yd, 251.00 m
draft : 30.51 ft, 10.17 yd, 9.30 m
beam : 118.11 ft, 39.37 yd, 36.00 m
mass : 110892517.88 lb, 49505.59 t, 50300.00 t
speed : 51.04 ft/s, 30.24 kn, 56.00 km/h
power : 2621018.31 ft pdl/s, 148.12 hp(I), 110.45 kW
main guns : 14.96 in, 14.96 in, 380.00 mm
fire shells weighing : 1763.70 lb, 0.79 t, 800.00 kg
fire shells at : 2690.29 ft/s, 1834.29 mi/h, 2952.00 km/h
volume underwater : 1777123.68 ft³, 50322.54 m³, 50322538.73 L
Why This Matters¶
- Legacy Data: Integrate historical or international data expressed in various unit systems
- Industry Standards: Naval, aerospace, and construction industries often use imperial/FPS units
- International Collaboration: Teams across different countries can work with their native units
- No Manual Conversions: The library handles all conversions automatically with full type safety
This capability is essential for applications that must bridge different engineering traditions or work with legacy specifications while maintaining modern safety standards.