phydat.h

Generic data container for physical data interface.

PHYDAT_DIM

The fixed number of dimensions we work with.

1
(3U)

We use a fixed number of 3 dimensions, as many physical values we encounter can be expressed this way. In practice we have e.g. readings from accelerometers, gyros, color sensors, or set data for RGB LEDs.

When expressing 1-dimensional data we just ignore the 2 higher dimension. This leads to a slight overhead of some byte of memory - but we benefit from a unified data structure for passing around physical data.

PHYDAT_SCALE_STR_MAXLEN

The maximum length of a scaling string.

1
(sizeof("*E-128\0"))
PHYDAT_MIN

Minimum value for phydat.h::phydat_t::val.

1
(INT16_MIN)
PHYDAT_MAX

Maximum value for phydat.h::phydat_t::val.

1
(INT16_MAX)
enum @200
UNIT_UNDEF
unit undefined
UNIT_NONE
data has no physical unit
UNIT_TEMP_C
degree Celsius
UNIT_TEMP_F
degree Fahrenheit
UNIT_TEMP_K
Kelvin.
UNIT_LUX
Lux (lx)
UNIT_M
meters
UNIT_M2
square meters
UNIT_M3
cubic meters
UNIT_G
gravitational force
UNIT_DPS
degree per second
UNIT_GR
grams - not using the SI unit (kg) here to make scale handling simpler
UNIT_A
Ampere.
UNIT_V
Volts.
UNIT_GS
gauss
UNIT_DBM
decibel-milliwatts
UNIT_BAR
Beer?
UNIT_PA
Pascal.
UNIT_CD
Candela.
UNIT_BOOL
boolean value [0|1]
UNIT_CTS
counts
UNIT_PERCENT
out of 100
UNIT_PERMILL
out of 1000
UNIT_PPM
part per million
UNIT_PPB
part per billion
UNIT_TIME
the three dimensions contain sec, min, and hours
UNIT_DATE
the 3 dimensions contain days, months and years
void phydat_dump(phydat_t * data, uint8_t dim)

Dump the given data container to STDIO.

Parameters

data:data container to dump
dim:number of dimension of data to dump

const char * phydat_unit_to_str(uint8_t unit)

Convert the given unit to a string.

Parameters

unit:unit to convert

Return values

  • string representation of given unit (e.g. V or m)
  • NULL if unit was not recognized
char phydat_prefix_from_scale(int8_t scale)

Convert the given scale factor to an SI prefix.

The given scaling factor is returned as a SI unit prefix (e.g. M for Mega, u for micro, etc), or \0 otherwise.

Parameters

scale:scale factor to convert

Return values

  • SI prefix if applicable
  • \0 if no SI prefix was found
void phydat_fit(phydat_t * dat, const int32_t * values, unsigned int dim)

Scale integer value(s) to fit into a phydat_t.

Inserts the values in the given dat so that all dim values in values fit inside the limits of the data type, [phydat.h::PHYDAT_MIN, phydat.h::PHYDAT_MAX], and updates the stored scale factor. The value is rounded to the nearest integer if possible, otherwise away from zero. E.g. 0.5 and 0.6 are rounded to 1, 0.4 and -0.4 are rounded to 0, -0.5 and -0.6 are rounded to -1.

1
2
3
int32_t values[] = { 100000, 2000000, 30000000 };
phydat_t dat = { .scale = 0 };
phydat_fit(&dat, values, 3);

Note

Unless compiled with -DPHYDAT_FIT_TRADE_PRECISION_FOR_ROM=0, this function will scale the value -32768, even though it would fit into a phydat_t. Statistically, this precision loss happens in 0.00153% of the calls. This optimization saves a bit more than 20 bytes.

Parameters

dat:the value will be written into this data array
values:value(s) to rescale
dim:Number of elements in values

struct phydat_t

Generic data structure for expressing physical values.

Physical data is expressed in a 3-dimensional touple of values. In addition to the data fields, this struct contains further the (physical) unit and the scale factor of the data. The unit is expressed as constant. The scale factor is expressed as power of 10 (10^factor).

The combination of signed 16-bit numbers with and the scale factor gives us a very high dynamic range (from -32*10^-131 to 32*10^130). In a wider sense we are saving the values as fixed floating points…

The scale factor is identical for all 3 values.

In a traditional (scientific) computational system the obvious choice for the used data type would be to use floats. We are however on heavily resource constrained (even 8-bit) embedded systems, so we use int16_t here. As most sensor are in some way ADC based, they normally do not use a higher accuracy than 12-14bit, so using 16-bit integers to represent this data is good enough in most cases.

int16_t val()

the 3 generic dimensions of data

uint8_t unit

the (physical) unit of the data

int8_t scale

the scale factor, 10^*scale*