quanta 0.1.0
Type-safe units for temperature, frequency, electrical and spatial quantities, modeled after std::chrono
Loading...
Searching...
No Matches
decibel.hpp
Go to the documentation of this file.
1#pragma once
2
57#include <cassert>
58#include <cmath>
59#include <quanta/electro.hpp>
60
61namespace quanta::electro {
62
63// ============================================================================
64// Gain: a dimensionless logarithmic ratio
65// ============================================================================
66
75 static constexpr const char* symbol = "dB";
76};
77
79template<typename Rep, typename Precision = std::ratio<1>>
81
88
89// ============================================================================
90// References
91// ============================================================================
92
106 using precision = std::milli;
107 static constexpr int factor = 10;
108 static constexpr const char* symbol = "dBm";
109};
110
114 using precision = std::ratio<1>;
115 static constexpr int factor = 10;
116 static constexpr const char* symbol = "dBW";
117};
118
122 using precision = std::ratio<1>;
123 static constexpr int factor = 20;
124 static constexpr const char* symbol = "dBV";
125};
126
130 using precision = std::milli;
131 static constexpr int factor = 20;
132 static constexpr const char* symbol = "dBmV";
133};
134
138 using precision = std::micro;
139 static constexpr int factor = 20;
140 static constexpr const char* symbol = "dBµV";
141};
142
// end of References group
144
152template<typename Reference>
153concept decibel_reference = requires {
154 typename Reference::unit;
155 typename Reference::precision;
156 { Reference::factor } -> std::convertible_to<int>;
157 { Reference::symbol } -> std::convertible_to<const char*>;
158} && (Reference::factor == 10 || Reference::factor == 20);
159
161template<typename Reference>
162inline constexpr bool is_power_reference_v = false;
163
164template<decibel_reference Reference>
165inline constexpr bool is_power_reference_v<Reference> = Reference::factor == 10;
166
168template<typename Reference>
169inline constexpr bool is_field_reference_v = false;
170
171template<decibel_reference Reference>
172inline constexpr bool is_field_reference_v<Reference> = Reference::factor == 20;
173
174// ============================================================================
175// level
176// ============================================================================
177
178template<typename Reference, typename Rep, typename Precision = std::ratio<1>>
179class level;
180
185template<typename T>
186struct is_level : std::false_type {};
187
188template<typename Reference, typename Rep, typename Precision>
189struct is_level<level<Reference, Rep, Precision>> : std::true_type {};
190
191template<typename T>
192inline constexpr bool is_level_v = is_level<T>::value;
193
211template<typename Reference, typename Rep, typename Precision>
212class level {
213 static_assert(decibel_reference<Reference>, "Reference must satisfy the decibel_reference concept");
214
215public:
217 using reference = Reference;
219 using rep = Rep;
221 using precision = typename Precision::type;
224
226 constexpr level() = default;
227 level(const level&) = default;
228
237 template<typename Rep2>
238 requires std::convertible_to<const Rep2&, rep> && (treat_as_inexact_v<rep> || !treat_as_inexact_v<Rep2>)
239 constexpr explicit level(const Rep2& r)
240 : _o(static_cast<rep>(r)) {}
241
243 constexpr explicit level(const offset& o)
244 : _o(o) {}
245
251 template<typename Rep2, typename Precision2>
252 requires std::convertible_to<gain<Rep2, Precision2>, offset>
255
257 template<typename Rep2, typename Precision2>
258 requires(!std::is_same_v<level, level<Reference, Rep2, Precision2>>) &&
259 (!std::convertible_to<gain<Rep2, Precision2>, offset>) &&
260 std::constructible_from<offset, gain<Rep2, Precision2>>
261 constexpr explicit level(const level<Reference, Rep2, Precision2>& l)
262 : _o(offset(l.offset_from_reference())) {}
263
264 ~level() = default;
265 level& operator=(const level&) = default;
266
268 constexpr offset offset_from_reference() const { return _o; }
269
271 constexpr rep count() const { return _o.count(); }
272
281 constexpr level operator-() const { return level(-_o); }
282 constexpr level operator+() const { return *this; }
283
284 constexpr level& operator+=(const offset& o) {
285 _o += o;
286 return *this;
287 }
288
289 constexpr level& operator-=(const offset& o) {
290 _o -= o;
291 return *this;
292 }
293
295 static constexpr level reference_level() noexcept { return level(offset::zero()); }
296
298 static constexpr level min() noexcept { return level(offset::min()); }
299
301 static constexpr level max() noexcept { return level(offset::max()); }
302
303private:
304 offset _o{};
305};
306
312template<typename ToLevel, typename Reference, typename Rep, typename Precision>
313 requires(!std::is_same_v<typename ToLevel::reference, Reference>) ||
314 detail::_quantity_cast_requirements<gain<Rep, Precision>, typename ToLevel::offset>
315constexpr ToLevel level_cast(const level<Reference, Rep, Precision>& l) {
316 // The constraint admits a cast between references, so that this reports it.
317 static_assert(
318 std::is_same_v<typename ToLevel::reference, Reference>, "level_cast cannot convert between different references"
319 );
320 return ToLevel(quantity_cast<typename ToLevel::offset>(l.offset_from_reference()));
321}
322
328template<typename ToLevel, typename Reference, typename Rep, typename Precision>
329constexpr ToLevel floor(const level<Reference, Rep, Precision>& l) {
330 static_assert(std::is_same_v<typename ToLevel::reference, Reference>, "floor cannot convert between references");
331 return ToLevel(floor<typename ToLevel::offset>(l.offset_from_reference()));
332}
333
339template<typename ToLevel, typename Reference, typename Rep, typename Precision>
340constexpr ToLevel ceil(const level<Reference, Rep, Precision>& l) {
341 static_assert(std::is_same_v<typename ToLevel::reference, Reference>, "ceil cannot convert between references");
342 return ToLevel(ceil<typename ToLevel::offset>(l.offset_from_reference()));
343}
344
346template<typename ToLevel, typename Reference, typename Rep, typename Precision>
347constexpr ToLevel trunc(const level<Reference, Rep, Precision>& l) {
348 static_assert(std::is_same_v<typename ToLevel::reference, Reference>, "trunc cannot convert between references");
349 return ToLevel(trunc<typename ToLevel::offset>(l.offset_from_reference()));
350}
351
357template<typename ToLevel, typename Reference, typename Rep, typename Precision>
358constexpr ToLevel round(const level<Reference, Rep, Precision>& l) {
359 static_assert(std::is_same_v<typename ToLevel::reference, Reference>, "round cannot convert between references");
360 return ToLevel(round<typename ToLevel::offset>(l.offset_from_reference()));
361}
362
363// ============================================================================
364// Affine arithmetic: level +/- gain -> level, level - level -> gain
365// ============================================================================
366
368template<typename R1, typename P1, typename R2, typename P2>
369using _common_gain = std::common_type_t<gain<R1, P1>, gain<R2, P2>>;
373template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
374constexpr auto
376 using cg = _common_gain<Rep1, Precision1, Rep2, Precision2>;
378 return cl(cg(l.offset_from_reference()) + cg(g));
379}
380
382template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
383constexpr auto
387
389template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
390constexpr auto
392 using cg = _common_gain<Rep1, Precision1, Rep2, Precision2>;
394 return cl(cg(l.offset_from_reference()) - cg(g));
395}
396
404template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
408
409template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
413
414template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
415 requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
419
420// ============================================================================
421// Linear domain conversions (not constexpr before C++26)
422// ============================================================================
423
425template<typename Offset>
426constexpr double _db_value(const Offset& o) {
427 return quantity_cast<gain<double>>(o).count();
428}
429
430// The inverse of _db_value, rounding to nearest (ties to even, matching
431// round<>) for integral reps. This exists because quantity_cast truncates when converting
432// from an inexact rep, and truncation would round e.g. -73.5 dB the wrong way.
433template<typename Offset>
434inline Offset _db_offset(double db) {
435 if constexpr (treat_as_inexact_v<typename Offset::rep>) {
436 return quantity_cast<Offset>(gain<double>(db));
437 } else {
438 using p = typename Offset::precision;
439 const double ticks = db * static_cast<double>(p::den) / static_cast<double>(p::num);
440 double rounded = std::floor(ticks);
441 const double frac = ticks - rounded;
442 if (frac > 0.5 || (frac == 0.5 && std::fmod(rounded, 2.0) != 0.0)) {
443 rounded += 1.0;
444 }
445 // Saturate rather than cast an out-of-range value (including an
446 // infinity), which is undefined. min() is a power of two and so exact
447 // as a double; max() converts exactly or rounds up to a power of two,
448 // and in both cases every smaller double fits the rep.
449 using rep = typename Offset::rep;
450 if (rounded >= static_cast<double>(std::numeric_limits<rep>::max())) {
451 return Offset(std::numeric_limits<rep>::max());
452 }
453 if (rounded <= static_cast<double>(std::numeric_limits<rep>::min())) {
454 return Offset(std::numeric_limits<rep>::min());
455 }
456 return Offset(static_cast<rep>(rounded));
457 }
458}
475template<typename Reference, typename Rep, typename Precision>
478 return linear(std::pow(10.0, _db_value(l.offset_from_reference()) / Reference::factor));
479}
480
507template<typename ToLevel, typename Unit, typename Rep, typename Precision>
508inline ToLevel to_level(const quantity<Unit, Rep, Precision>& q) {
509 using ref = typename ToLevel::reference;
510 static_assert(
511 std::is_same_v<typename ref::unit, Unit>, "to_level: quantity unit does not match the level reference"
512 );
513
515 const double ratio = quantity_cast<linear>(q).count();
516 if (!(ratio > 0.0)) {
517 if constexpr (std::floating_point<typename ToLevel::rep>) {
518 if (std::isnan(ratio)) {
519 return ToLevel(std::numeric_limits<typename ToLevel::rep>::quiet_NaN());
520 }
521 assert(ratio >= 0.0 && "to_level: quantity must be non-negative and not NaN");
522 return ToLevel(-std::numeric_limits<typename ToLevel::rep>::infinity());
523 } else {
524 assert(ratio >= 0.0 && "to_level: quantity must be non-negative and not NaN");
525 return ToLevel::min();
526 }
527 }
528 return ToLevel(_db_offset<typename ToLevel::offset>(ref::factor * std::log10(ratio)));
529}
530
540template<typename Rep, typename Precision>
542 return std::pow(10.0, _db_value(g) / 10.0);
543}
544
554template<typename Rep, typename Precision>
556 return std::pow(10.0, _db_value(g) / 20.0);
557}
558
560inline gain<double> power_gain(double ratio) {
561 assert(ratio > 0.0 && "power_gain: ratio must be positive");
562 return gain<double>(10.0 * std::log10(ratio));
563}
564
566inline gain<double> amplitude_gain(double ratio) {
567 assert(ratio > 0.0 && "amplitude_gain: ratio must be positive");
568 return gain<double>(20.0 * std::log10(ratio));
569}
570
587template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
590 using cg = _common_gain<Rep1, Precision1, Rep2, Precision2>;
592 return to_level<result>(to_linear(a) + to_linear(b));
593}
594
595// ============================================================================
596// Type aliases
597// ============================================================================
598
605template<typename Rep, typename Precision = std::ratio<1>>
607
609template<typename Rep, typename Precision = std::ratio<1>>
611
613template<typename Rep, typename Precision = std::ratio<1>>
615
617template<typename Rep, typename Precision = std::ratio<1>>
619
621template<typename Rep, typename Precision = std::ratio<1>>
623
638
// end of LevelTypes group
640
641// ============================================================================
642// String conversion and formatting
643// ============================================================================
644
660template<typename Precision>
661struct quantity_suffix<decibel_unit, Precision> {};
662
664// The number of decimal places needed to render a count at the given precision
665// as a fixed-point decimal, or -1 when the precision is not 1, 1/10, 1/100, ...
666consteval int _decimal_places(intmax_t num, intmax_t den) {
667 if (num != 1) {
668 return -1;
669 }
670 int places = 0;
671 while (den % 10 == 0) {
672 den /= 10;
673 ++places;
674 }
675 return den == 1 ? places : -1;
676}
677
678template<typename Precision>
679inline constexpr bool _is_decimal_precision = _decimal_places(Precision::num, Precision::den) >= 0;
680
681// A count at the given precision, in decibels, as a double.
682template<typename Precision, typename Rep>
683constexpr double _db_double(const Rep& count) {
684 return static_cast<double>(count) * Precision::num / Precision::den;
685}
686
687// A count at the given precision rendered without a format spec, in decibels.
688// Integer counts are shown exactly with one decimal place per decade of
689// precision ("10.50"); floating-point counts in the shortest fixed notation
690// that round-trips (never scientific).
691template<typename Precision, typename Rep>
692inline std::string _format_db(const Rep& count) {
693 static_assert(_is_decimal_precision<Precision>, "precision cannot be rendered as a fixed-point decimal");
694 if constexpr (std::floating_point<Rep>) {
695 Rep value = count;
696 if constexpr (Precision::den != 1) {
697 value /= static_cast<Rep>(Precision::den);
698 }
699 return _fixed_string(value);
700 } else if constexpr (treat_as_inexact_v<Rep>) {
701 return _fixed_string(_db_double<Precision>(count));
702 } else {
703 constexpr int places = _decimal_places(Precision::num, Precision::den);
704 if constexpr (places == 0) {
705 return std::to_string(count);
706 } else {
707 const bool negative = count < Rep(0);
708 // Compute the magnitude in unsigned arithmetic so that the most
709 // negative representable count does not overflow on negation.
710 const unsigned long long magnitude =
711 negative ? 0ULL - static_cast<unsigned long long>(count) : static_cast<unsigned long long>(count);
712
713 const unsigned long long whole = magnitude / Precision::den;
714 const unsigned long long frac = magnitude % Precision::den;
715
716 std::string frac_digits = std::to_string(frac);
717 frac_digits.insert(0, static_cast<size_t>(places) - frac_digits.size(), '0');
718
719 return (negative ? "-" : "") + std::to_string(whole) + "." + frac_digits;
720 }
721 }
722}
731template<typename Rep, typename Precision>
732 requires _is_decimal_precision<typename Precision::type>
734 return _format_db<typename Precision::type>(g.count()) + decibel_unit::symbol;
735}
736
744template<typename Rep, typename Precision>
745 requires _is_decimal_precision<typename Precision::type>
747 return _fixed_string(_db_double<typename Precision::type>(g.count())) + decibel_unit::symbol;
748}
749
756template<typename Rep, typename Precision>
757 requires _is_decimal_precision<typename Precision::type>
759 return to_string(g, base_unit);
760}
761
765template<typename Reference, typename Rep, typename Precision>
766 requires _is_decimal_precision<typename Precision::type>
767inline std::string to_string(const level<Reference, Rep, Precision>& l) {
768 return _format_db<typename Precision::type>(l.count()) + Reference::symbol;
769}
770
778template<typename Reference, typename Rep, typename Precision>
779 requires _is_decimal_precision<typename Precision::type>
781 return _fixed_string(_db_double<typename Precision::type>(l.count())) + Reference::symbol;
782}
783
790template<typename Reference, typename Rep, typename Precision>
791 requires _is_decimal_precision<typename Precision::type>
793 return to_string(l, base_unit);
794}
795
796} // namespace quanta::electro
797
798namespace std {
799
800template<typename Reference, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
801struct common_type<
802 quanta::electro::level<Reference, Rep1, Precision1>,
803 quanta::electro::level<Reference, Rep2, Precision2>> {
804private:
805 using common_offset =
806 std::common_type_t<quanta::electro::gain<Rep1, Precision1>, quanta::electro::gain<Rep2, Precision2>>;
807
808public:
810};
811
812} // namespace std
813
814#if CONFIG_QUANTA_STD_FORMAT
816namespace quanta::electro {
817
818// Shared formatter for gains and levels. "{}" renders the exact value as a
819// fixed-point decimal ("10.50dB"). A non-empty spec controls only how the
820// value (in decibels, as double) is rendered, never the unit:
821// std::format("{:.1f}", 1050_cdB) == "10.5dB". The 'b' and 's' markers are
822// accepted for consistency with the other quantities; decibels have no other
823// unit, so they render in the same unit, and with nothing after the marker
824// the value is rendered in the shortest fixed notation that round-trips:
825// std::format("{:b}", 1050_cdB) == "10.5dB".
826template<typename Precision>
827struct _db_formatter {
828private:
829 std::formatter<double> _num;
830 bool _has_spec = false;
831 bool _marker = false;
832
833public:
834 constexpr auto parse(std::format_parse_context& ctx) {
835 _marker = detail::_parse_unit_marker(ctx, "bs") != detail::_unit_form::own;
836 auto it = ctx.begin();
837 if (it == ctx.end() || *it == '}') {
838 return it;
839 }
840 _has_spec = true;
841 return _num.parse(ctx);
842 }
843
844 template<typename Rep, typename FormatContext>
845 auto format(const Rep& count, const char* symbol, FormatContext& ctx) const {
846 auto out = ctx.out();
847 if (_has_spec) {
848 out = _num.format(_db_double<Precision>(count), ctx);
849 } else if (_marker) {
850 out = std::format_to(out, "{}", _fixed_string(_db_double<Precision>(count)));
851 } else {
852 out = std::format_to(out, "{}", _format_db<Precision>(count));
853 }
854 return _format_append(out, symbol);
855 }
856};
857
858} // namespace quanta::electro
861namespace std {
862
863// See quanta::electro::_db_formatter: "{}" -> "10.50dB", "{:.1f}" -> "10.5dB".
864template<typename Rep, typename Precision>
865 requires quanta::electro::_is_decimal_precision<typename Precision::type>
866struct formatter<quanta::electro::quantity<quanta::electro::decibel_unit, Rep, Precision>, char>
867 : quanta::electro::_db_formatter<typename Precision::type> {
868 template<typename FormatContext>
869 auto format(
871 FormatContext& ctx
872 ) const {
873 return quanta::electro::_db_formatter<typename Precision::type>::format(
875 );
876 }
877};
878
879// See quanta::electro::_db_formatter; the level's reference symbol is appended
880// ("13.01dBm", "{:.1f}" -> "13.0dBm").
881template<typename Reference, typename Rep, typename Precision>
882 requires quanta::electro::_is_decimal_precision<typename Precision::type>
883struct formatter<quanta::electro::level<Reference, Rep, Precision>, char>
884 : quanta::electro::_db_formatter<typename Precision::type> {
885 template<typename FormatContext>
886 auto format(const quanta::electro::level<Reference, Rep, Precision>& l, FormatContext& ctx) const {
887 return quanta::electro::_db_formatter<typename Precision::type>::format(l.count(), Reference::symbol, ctx);
888 }
889};
890
891} // namespace std
892#endif
893
894namespace quanta {
895inline namespace literals {
896inline namespace electro_literals {
897
899template<char... Digits>
900constexpr quanta::electro::decibels operator""_dB() {
901 return detail::check_overflow<quanta::electro::decibels, Digits...>();
902}
903
905template<char... Digits>
907 return detail::check_overflow<quanta::electro::centidecibels, Digits...>();
908}
909
911template<char... Digits>
912constexpr quanta::electro::dbm operator""_dBm() {
913 return quanta::electro::dbm(detail::check_overflow<quanta::electro::decibels, Digits...>());
914}
915
917template<char... Digits>
918constexpr quanta::electro::centi_dbm operator""_cdBm() {
919 return quanta::electro::centi_dbm(detail::check_overflow<quanta::electro::centidecibels, Digits...>());
920}
921
923template<char... Digits>
924constexpr quanta::electro::dbw operator""_dBW() {
925 return quanta::electro::dbw(detail::check_overflow<quanta::electro::decibels, Digits...>());
926}
927
929template<char... Digits>
930constexpr quanta::electro::dbv operator""_dBV() {
931 return quanta::electro::dbv(detail::check_overflow<quanta::electro::decibels, Digits...>());
932}
933
935template<char... Digits>
936constexpr quanta::electro::dbmv operator""_dBmV() {
937 return quanta::electro::dbmv(detail::check_overflow<quanta::electro::decibels, Digits...>());
938}
939
941template<char... Digits>
942constexpr quanta::electro::dbuv operator""_dBuV() {
943 return quanta::electro::dbuv(detail::check_overflow<quanta::electro::decibels, Digits...>());
944}
945
946#if QUANTA_HAS_UTF8_LITERALS
948template<char... Digits>
949constexpr quanta::electro::dbuv operator""_dBµV() {
950 return quanta::electro::dbuv(detail::check_overflow<quanta::electro::decibels, Digits...>());
951}
952#endif
953
954} // namespace electro_literals
955} // namespace literals
956
957namespace electro {
958using namespace literals::electro_literals;
959} // namespace electro
960} // namespace quanta
An absolute point on a logarithmic scale, relative to a reference.
Definition decibel.hpp:212
constexpr level(const level< Reference, Rep2, Precision2 > &l)
Converts from a level with the same reference.
Definition decibel.hpp:253
constexpr level operator+() const
Definition decibel.hpp:282
constexpr level(const level< Reference, Rep2, Precision2 > &l)
Explicit constructor for lossy precision conversions.
Definition decibel.hpp:261
constexpr level(const offset &o)
Constructs from an offset relative to the reference.
Definition decibel.hpp:243
constexpr level & operator-=(const offset &o)
Definition decibel.hpp:289
level & operator=(const level &)=default
constexpr rep count() const
Returns the raw offset count, in units of Precision.
Definition decibel.hpp:271
constexpr level operator-() const
Reflects the level about its reference point.
Definition decibel.hpp:281
gain< Rep, Precision > offset
The gain type measuring the offset from the reference.
Definition decibel.hpp:223
constexpr level(const Rep2 &r)
Constructs from an offset count in dB.
Definition decibel.hpp:239
Rep rep
The representation type.
Definition decibel.hpp:219
static constexpr level max() noexcept
Returns the maximum representable level.
Definition decibel.hpp:301
constexpr level()=default
Constructs a level at the reference point (0 dB offset).
level(const level &)=default
static constexpr level min() noexcept
Returns the minimum representable level.
Definition decibel.hpp:298
constexpr offset offset_from_reference() const
Returns the offset from the reference point.
Definition decibel.hpp:268
static constexpr level reference_level() noexcept
Returns the reference point itself (a 0 dB offset).
Definition decibel.hpp:295
Reference reference
The reference tag type.
Definition decibel.hpp:217
typename Precision::type precision
The offset precision, in dB, as a std::ratio.
Definition decibel.hpp:221
constexpr level & operator+=(const offset &o)
Definition decibel.hpp:284
A quantity of an electrical unit with a representation and precision.
Definition electro.hpp:245
constexpr rep count() const
Returns the tick count.
Definition electro.hpp:324
Concept for decibel reference tags.
Definition decibel.hpp:153
Electrical unit types and arithmetic, modeled after std::chrono.
dbm_level< int64_t, std::centi > centi_dbm
Power level in dBm, with 0.01 dB precision.
Definition decibel.hpp:627
dbv_level< int64_t > dbv
Voltage level in dBV, with 1 dB precision.
Definition decibel.hpp:631
level< microvolt_reference, Rep, Precision > dbuv_level
A level referenced to 1 µV.
Definition decibel.hpp:622
dbm_level< int64_t > dbm
Power level in dBm, with 1 dB precision.
Definition decibel.hpp:625
level< millivolt_reference, Rep, Precision > dbmv_level
A level referenced to 1 mV.
Definition decibel.hpp:618
level< milliwatt_reference, Rep, Precision > dbm_level
A level referenced to 1 mW.
Definition decibel.hpp:606
dbuv_level< int64_t > dbuv
Voltage level in dBµV, with 1 dB precision.
Definition decibel.hpp:635
dbuv_level< int64_t, std::centi > centi_dbuv
Voltage level in dBµV, with 0.01 dB precision.
Definition decibel.hpp:637
level< volt_reference, Rep, Precision > dbv_level
A level referenced to 1 V.
Definition decibel.hpp:614
level< watt_reference, Rep, Precision > dbw_level
A level referenced to 1 W.
Definition decibel.hpp:610
dbmv_level< int64_t > dbmv
Voltage level in dBmV, with 1 dB precision.
Definition decibel.hpp:633
dbw_level< int64_t > dbw
Power level in dBW, with 1 dB precision.
Definition decibel.hpp:629
Electrical unit types and utilities.
Definition decibel.hpp:61
constexpr ToLevel ceil(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward positive infinity.
Definition decibel.hpp:340
gain< double > power_gain(double ratio)
The gain corresponding to a linear power ratio (10*log10(ratio)).
Definition decibel.hpp:560
constexpr bool is_power_reference_v< Reference >
Definition decibel.hpp:165
gain< int64_t > decibels
Gain with 1 dB precision.
Definition decibel.hpp:83
gain< int64_t, std::centi > centidecibels
Gain with 0.01 dB precision.
Definition decibel.hpp:85
constexpr auto operator-(const level< Reference, Rep1, Precision1 > &l, const quantity< decibel_unit, Rep2, Precision2 > &g)
Applies a loss to a level.
Definition decibel.hpp:391
auto add_powers(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Combines the powers of two uncorrelated signals.
Definition decibel.hpp:589
constexpr bool is_power_reference_v
True if the reference measures a power quantity (10*log10).
Definition decibel.hpp:162
constexpr ToLevel level_cast(const level< Reference, Rep, Precision > &l)
Converts a level to a different precision or representation.
Definition decibel.hpp:315
quantity< decibel_unit, Rep, Precision > gain
A logarithmic ratio with configurable representation and precision.
Definition decibel.hpp:80
ToLevel to_level(const quantity< Unit, Rep, Precision > &q)
Converts a linear quantity to a level.
Definition decibel.hpp:508
constexpr ToLevel round(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding to nearest (ties to even).
Definition decibel.hpp:358
double amplitude_ratio(const quantity< decibel_unit, Rep, Precision > &g)
The linear amplitude ratio a gain represents (10^(dB/20)).
Definition decibel.hpp:555
constexpr ToLevel trunc(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward zero (as level_cast does).
Definition decibel.hpp:347
constexpr bool is_field_reference_v
True if the reference measures a field quantity (20*log10).
Definition decibel.hpp:169
constexpr bool is_level_v
Definition decibel.hpp:192
std::string to_string(const quantity< decibel_unit, Rep, Precision > &g)
Converts a gain to a string, e.g.
Definition decibel.hpp:733
constexpr bool is_field_reference_v< Reference >
Definition decibel.hpp:172
double power_ratio(const quantity< decibel_unit, Rep, Precision > &g)
The linear power ratio a gain represents (10^(dB/10)).
Definition decibel.hpp:541
constexpr auto operator<=>(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Definition decibel.hpp:416
auto to_linear(const level< Reference, Rep, Precision > &l)
Converts a level to the equivalent linear quantity.
Definition decibel.hpp:476
gain< int64_t, std::milli > millidecibels
Gain with 0.001 dB precision.
Definition decibel.hpp:87
gain< double > amplitude_gain(double ratio)
The gain corresponding to a linear amplitude ratio (20*log10(ratio)).
Definition decibel.hpp:566
constexpr bool operator==(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Definition decibel.hpp:410
constexpr auto operator+(const level< Reference, Rep1, Precision1 > &l, const quantity< decibel_unit, Rep2, Precision2 > &g)
Applies a gain to a level.
Definition decibel.hpp:375
constexpr ToLevel floor(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward negative infinity.
Definition decibel.hpp:329
Type-safe units modeled after std::chrono.
Definition core.hpp:90
constexpr base_unit_t base_unit
Selects the base-unit form in to_string().
Definition core.hpp:140
constexpr bool treat_as_inexact_v
Definition core.hpp:119
Tag type selecting the base-unit form, see base_unit.
Definition core.hpp:124
A dimensionless logarithmic ratio, measured in decibels.
Definition decibel.hpp:74
static constexpr const char * symbol
Definition decibel.hpp:75
Trait to detect level specializations.
Definition decibel.hpp:186
Reference of 1 µV, for dBµV.
Definition decibel.hpp:136
static constexpr const char * symbol
Definition decibel.hpp:140
Reference of 1 mV, for dBmV.
Definition decibel.hpp:128
static constexpr const char * symbol
Definition decibel.hpp:132
Reference of 1 mW, for dBm.
Definition decibel.hpp:104
static constexpr const char * symbol
Definition decibel.hpp:108
Trait giving the display suffix for a (unit, precision) pair.
Definition electro.hpp:1087
Reference of 1 V, for dBV.
Definition decibel.hpp:120
static constexpr const char * symbol
Definition decibel.hpp:124
static constexpr int factor
Definition decibel.hpp:123
Voltage, measured in volts.
Definition electro.hpp:174
Reference of 1 W, for dBW.
Definition decibel.hpp:112
static constexpr const char * symbol
Definition decibel.hpp:116
static constexpr int factor
Definition decibel.hpp:115
Power, measured in watts.
Definition electro.hpp:189
Tag type selecting the scaled form, see scaled.
Definition core.hpp:145