7. API reference

The core of the simulator is composed from the following modules:

cycles

data for all cycles and utilities to identify them

datamodel

Defines schema, defaults and validations for data consumed/produced by Experiment.

experiment

(TO BE DEFUNCT) The core that accepts a vehicle-model and wltc-classes, runs the simulation and updates the model with results.

cycler

code for generating the cycle

engine

formulae for engine power & revolutions and gear-box

vehicle

formulae for cycle/vehicle dynamics

vmax

formulae estimating v_max from wot

downscale

formulae downscaling cycles based on pmr/test_mass ratio

nmindrive

Calculate/Validate n_min_drive parameters, defined mostly in Annex 2-2.k.

invariants

definitions & idempotent formulae for physics/engineering

autograph

Harvest functions & annotate their dependencies to build pipelines.

io

utilities for starting-up, parsing, naming, indexing and spitting out data

utils

software utils unrelated to physics or engineering

cli

(OUTDATED) command-line entry-point for launching this wltp tool

plots

(OUTDATED) code for plotting diagrams related to wltp cycles & results

idgears

(OUTDATED, irrelevant) Detects vehile’s gear-ratios from cycle-data and reconstructs the gears-profile by identifying the actual gears used.

7.1. Module: wltp.cycles

data for all cycles and utilities to identify them

wltp.cycles.crc_velocity(V: Iterable, crc: Union[int, str] = 0, full=False)str[source]

Compute the CRC32(V * 10) of a 1Hz velocity trace.

Parameters
  • V – velocity samples, to be rounded according to wltp.invariants.v_decimals

  • crc – initial CRC value (might be a hex-string)

  • full – print full 32bit number (x8 hex digits), or else, just the highest half (the 1st x4 hex digits)

Returns

the 16 lowest bits of the CRC32 of the trace, as hex-string

  1. The velocity samples are first round to v_decimals;

  2. the samples are then multiplied x10 to convert into integers (assuming v_decimals is 1);

  3. the integer velocity samples are then converted into int16 little-endian bytes (eg 0xC0FE –> (0xFE, 0xC0);

  4. the int16 bytes are then concatanated together, and

  5. fed into ZIP’s CRC32;

  6. the highest 2 bytes of the CRC32 are (usually) kept, formated in hex (x4 leftmost hex-digits).

wltp.cycles.cycle_checksums(full=False) → pandas.core.frame.DataFrame[source]

Return a big table with cumulative and simple SUM & CRC for all class phases.

Parameters

full – CRCs contain the full 32bit number (x8 hex digits)

wltp.cycles.cycle_phases() → pandas.core.frame.DataFrame[source]

Return a textual table with the boundaries of all phases and cycle phasings

wltp.cycles.identify_cycle_v(V: Iterable)[source]

Finds the first left-top CRC matching the cycle/part/kind of the given Velocity.

Parameters

V – Any cycle or parts of it (one of Low/Medium/High/Extra High phases), or concatenated subset of the above phases, but in that order.

Returns

a 3 tuple (class, part, kind), like this:

  • (None,     None,   None): if no match

  • (<class>,  None,  <phasing>): if it matches a full-cycle

  • (<class>, <part>, <phasing>): if it matches a part

  • (<class>, <PART>, <phasing>): (CAPITAL part) if it matches a part cumulatively

where <phasing> is one of

  • V

  • A0 (offset: 0, length: -1)

  • A1 (offset: 1, length: -1)

wltp.cycles.identify_cycle_v_crc(crc: Union[int, str]) → Tuple[Optional[str], Optional[str], Optional[str]][source]

see identify_cycle_v()

7.2. Module: wltp.datamodel

Defines schema, defaults and validations for data consumed/produced by Experiment.

The datamodel-instance is managed by pandel.Pandel.

wltp.datamodel._get_model_schema(additional_properties=False)dict[source]
Parameters

additional_properties (bool) – when False, 4rd-step(validation) will scream on any non-schema property found. The json-schema(dict) for input/output of the WLTC experiment.

Note

Do not modify, or they will affect all future operations

wltp.datamodel._get_wltc_schema()dict[source]

The json-schema for the WLTC-data required to run a WLTC experiment.

Note

Do not modify, or they will affect all future operations

wltp.datamodel.get_class(class_id: Union[str, int], mdl=None)dict[source]

Fetch the wltc-data for a specific class.

Parameters

class_id – one of ‘class1’, …, ‘class3b’ or its index 0,1, … 3

wltp.datamodel.get_class_part_names(cls_name=None)[source]
Parameters

cls_name (str) – one of ‘class1’, …, ‘class3b’, if missing, returns all 4 part-names

wltp.datamodel.get_class_parts_limits(wltc_class: Union[str, int], edges=False)[source]

Parses the supplied in wltc_data and extracts the part-limits for the specified class-name.

Parameters
  • wltc_class – one of ‘class1’, …, ‘class3b’ or its index 0,1, … 3

  • edges – when True, embeds internal limits inside [0, …, len]

Returns

a list of ints with the part-limits, ie for class-3a these are 3 numbers (or 5 if edge)

Example:

>>> from wltp import datamodel
>>> import pandas as pd
>>> cls = 'class2'
>>> part_limits = datamodel.get_class_parts_limits(cls)
>>> part_limits
[589, 1022, 1477]
>>> part_limits = datamodel.get_class_parts_limits(cls, edges=True)
>>> part_limits
[0,  589, 1022, 1477, 1801]

And these are the limits for acceleration-dependent items:

>>> cls_data = datamodel.get_wltc_data()['classes'][cls]
>>> V = pd.DataFrame(cls_data['v_cycle'])
>>> V.groupby(pd.cut(V.index, part_limits)).sum()
              v_cycle
(0, 589]      11162.2
(589, 1022]   17054.3
(1022, 1477]  24450.6
(1477, 1801]  28869.8
wltp.datamodel.get_class_pmr_limits(edges=False)[source]

Parses the supplied in wltc_data and extracts the part-limits for the specified class-name.

Parameters

edges – when True, embeds internal limits into (0, len)

Returns

a list with the pmr-limits (2 numbers)

wltp.datamodel.get_class_v_cycle(wltc_class: Union[str, int]) → pandas.core.series.Series[source]

Fetch the v-cycle for a class with the proper t in index.

Parameters

wltc_class – one of ‘class1’, …, ‘class3b’ or its index 0,1, … 3

Returns

a series containing \(length + 1\) samples, numbered from 0 to length, where length is the duration of the cycle in seconds.

wltp.datamodel.get_model_base()dict[source]

The base model for running a WLTC experiment.

It contains some default values for the experiment but this model is not valid - you need to override its attributes.

Returns

a tree with the default values for the experiment.

wltp.datamodel.get_model_schema(additional_properties=False)[source]

Schema of the input data; you may freely modify them.

wltp.datamodel.get_wltc_data()[source]

The WLTC-data required to run an experiment (the class-cycles and their attributes)..

Prefer to access wltc-data through get_class(), or from datamodel['wltc_data'],

Returns

a tree

wltp.datamodel.get_wltc_schema()[source]

Schema of the wLTC data; you may freely modify them.

wltp.datamodel.merge(a, b, path=[])[source]

‘merges b into a

wltp.datamodel.upd_default_load_curve(mdl, engine_type='petrol')[source]

Some default ‘full-load-curve’ for the vehicles

wltp.datamodel.validate_model(mdl, additional_properties=False, iter_errors=False, validate_wltc_data=False, validate_schema=False)[source]
Parameters

iter_errors (bool) – does not fail, but returns a generator of ValidationErrors

>>> validate_model(None)
Traceback (most recent call last):
jsonschema.exceptions.ValidationError: None is not of type 'object'
...
>>> mdl = get_model_base()
>>> err_generator = validate_model(mdl, iter_errors=True)
>>> sorted(err_generator, key=hash)
[<ValidationError:
...
>>> mdl = get_model_base()
>>> mdl.update({
...     "unladen_mass":1230,
...     "test_mass":   1300,
...     "p_rated": 110.625,
...     "n_rated": 5450,
...     "n_idle":  950,
...     "n_min":   500,
...     "gear_ratios":[120.5, 75, 50, 43, 33, 28],
...     "f0": 100,
...     "f1": 0.5,
...     "f2": 0.04,
... })
>>> mdl = upd_default_load_curve(mdl);
>>> err_generator = validate_model(mdl, iter_errors=True)
>>> list(err_generator)
[]
wltp.datamodel.yield_n_min_errors(mdl)[source]

7.3. Module: wltp.experiment

(TO BE DEFUNCT) The core that accepts a vehicle-model and wltc-classes, runs the simulation and updates the model with results.

Attention

The documentation of this core module has several issues and needs work.

7.3.1. Notation

  • ALL_CAPITAL variables denote vectors over the velocity-profile (the cycle),

  • ALL_CAPITAL starting with underscore (_) denote matrices (gears x time).

For instance, GEARS is like that:

[0, 0, 1, 1, 1, 2, 2, ... 1, 0, 0]
 <----   cycle time-steps   ---->

and _GEARS is like that:

 t:||: 0  1  2  3
---+-------------
g1:|[[ 1, 1, 1, 1, ... 1, 1
g2:|   2, 2, 2, 2, ... 2, 2
g3:|   3, 3, 3, 3, ... 3, 3
g4:|   4, 4, 4, 4, ... 4, 4 ]]

7.3.2. Major vectors & matrices

V: floats (#cycle_steps)

The wltp-class velocity profile.

_GEARS: integers (#gears X #cycle_steps)

One row for each gear (starting with 1 to #gears).

_N_GEARS: floats (#gears X #cycle_steps)

One row per gear with the Engine-revolutions required to follow the V-profile (unfeasible revs included), produced by multiplying V * gear-rations.

_GEARS_YES: boolean (#gears X #cycle_steps)

One row per gear having True wherever gear is possible for each step.

See also

,datamodel for in/out schemas

class wltp.experiment.Experiment(mdl, skip_model_validation=False, validate_wltc_data=False, additional_properties=True)[source]

Bases: object

Runs the vehicle and cycle data describing a WLTC experiment.

See wltp.experiment for documentation.

__init__(mdl, skip_model_validation=False, validate_wltc_data=False, additional_properties=True)[source]
Parameters
  • mdl – trees (formed by dicts & lists) holding the experiment data.

  • skip_model_validation – when true, does not validate the model.

  • additional_properties – when false; strict checks screams if unknown props in model

run()[source]

Invokes the main-calculations and extracts/update Model values!

@see: Annex 2, p 70

wltp.experiment.applyDriveabilityRules(V, A, GEARS, CLUTCH, driveability_issues)[source]

@note: Modifies GEARS & CLUTCH. @see: Annex 2-4, p 72

wltp.experiment.gearsregex(gearspattern)[source]
Parameters

gearspattern

regular-expression or substitution that escapes decimal-bytes written as: \g\d+ with adding +128, eg:

\g124|\g7 --> unicode(128+124=252)|unicode(128+7=135)

wltp.experiment.rule_a(bV, GEARS, CLUTCH, driveability_issues, re_zeros)[source]

Rule (a): Clutch & set to 1st-gear before accelerating from standstill.

Implemented with a regex, outside rules-loop: Also ensures gear-0 always followed by gear-1.

NOTE: Rule(A) not inside x2 loop, and last to run.

wltp.experiment.rule_c2(bV, A, GEARS, CLUTCH, driveability_issues, re_zeros)[source]

Rule (c2): Skip 1st-gear while decelerating to standstill.

Implemented with a regex, outside rules-loop: Search for zeros in _reversed_ V & GEAR profiles, for as long Accel is negative. NOTE: Rule(c2) is the last rule to run.

wltp.experiment.run_cycle(V, A, P_REQ, gear_ratios, n_idle, n_min_drive, n_rated, p_rated, load_curve, mdl)[source]

Calculates gears, clutch and actual-velocity for the cycle (V). Initial calculations happen on engine_revs for all gears, for all time-steps of the cycle (_N_GEARS array). Driveability-rules are applied afterwards on the selected gear-sequence, for all steps.

Parameters
  • V – the cycle, the velocity profile

  • A – acceleration of the cycle (diff over V) in m/sec^2

Returns

CLUTCH: a (1 X #velocity) bool-array, eg. [3, 150] –> gear(3), time(150)

Return type

array

wltp.experiment.step_rule_b1(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule (b1): Do not skip gears while accelerating.

wltp.experiment.step_rule_b2(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule (b2): Hold gears for at least 2sec when accelerating.

wltp.experiment.step_rule_c1(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule (c1): Skip gears <3sec when decelerating.

wltp.experiment.step_rule_d(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule (d): Cancel shifts after peak velocity.

wltp.experiment.step_rule_e(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule (e): Cancel shifts lasting 5secs or less.

wltp.experiment.step_rule_f(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule(f): Cancel 1sec downshifts (under certain circumstances).

wltp.experiment.step_rule_g(t, pg, g, V, A, GEARS, driveability_issues)[source]

Rule(g): Cancel upshift during acceleration if later downshifted for at least 2sec.

7.4. Module: wltp.cycler

code for generating the cycle

class wltp.cycler.CycleBuilder(*velocities: Union[pandas.core.series.Series, pandas.core.frame.DataFrame], **kwargs)[source]

Bases: object

Specific choreography of method-calls required, see TCs & notebooks.

A: pd.Series = None[source]

A column derived from V, also within cycle, populated on construction, and used in subsequent calculations.

V: pd.Series = None[source]

A column within cycle populated from the last velocity given in the cstor. to use in subsequent calculations.

__init__(*velocities: Union[pandas.core.series.Series, pandas.core.frame.DataFrame], **kwargs)[source]

Initialize cycle with the given velocities and acceleration of the last one.

Parameters

velocities

named series, e.g. from get_class_v_cycle(), all sharing the same time-index The last one is assumed to be the “target” velocity for the rest of the cycle methods.

If they are a (dataframe, series, series), they are assigned in cycle, V and A respectively, and no other processing happens.

_combine_all_gear_flags(gflags) → pandas.core.series.Series[source]
Parameters

gflags – the initial-gear rule flags grouped for one specific gear

Returns

(must return) a boolean series, or else, groupby does nothing!!

_combine_ok_n_gear_flags(gflags) → pandas.core.series.Series[source]
Parameters

gflags – the initial-gear rule flags grouped for each gear (except g0)

Returns

(must return) a boolean series, or else, groupby does nothing!!

add_columns(*columns: Union[pandas.core.frame.DataFrame, pandas.core.series.Series])[source]

Concatenate more columns into cycle.

Parameters

columns – must have appropriate columns, ie. 2-level (item, gear).

add_wots(gwots: pandas.core.frame.DataFrame)[source]

Adds the gwots joined on the v_cap column of the cycle.

Parameters

gwots – a dataframe of wot columns indexed by a grid of rounded velocities, as generated by interpolate_wot_on_v_grid(), and augmented by calc_p_avail_in_gwots().

calc_initial_gear_flags(*, g_vmax: int, n95_high: float, n_max_cycle: float, nmins: wltp.nmindrive.NMinDrives) → pandas.core.frame.DataFrame[source]

Heavy lifting calculations for “initial gear” rules of Annex 2: 2.k, 3.2, 3.3 & 3.5.

Returns

a dataframe with nullable dtype int8 with -1 for NANs (for storage efficiency) and hierarchical columns, with NANFLAG`(1) wherever a gear is allowed, for a specific rule (different sets of rules per gear). Push it to :meth:`combine_ok_n_gear_flags() & combine_ok_n_p_gear_flags().

Conditions consolidated & ordered like that:

0  RULE      CONDITION                ALLOWED GEAR           COMMENTS
==========  =======================  =====================  ============================================
ok-p               p_avail >= p_req  g > 2                  # 3.5

                              ... AND ...

MAXn-a                  n ≤ n95_high  g < g_vmax             # 3.3
MAXn-b              n ≤ n_max_cycle  g_vmax ≤ g             # 3.3

                              ... AND ...

MINn-ud/hc      n_mid_drive_set ≤ n  g > 2                  # 3.3 & 2k (up/dn on A ≷ -0.1389, hot/cold)
MINn-2ii      n_idle ≤ n, stopdecel  g = 2                  # 3.3 & 2k (stopdecel)
MINn-2iii          0.9 * n_idle ≤ n  g = 2 + clutch         # 3.3 & 2k
c_initacell               initaccel  g = 1                  # 3.2 & 3.3c (also n ≤ n95_high apply)
c_a            1.0 ≤ v & !initaccel  g = 1                  # 3.3c (also n ≤ n95_high apply)

                              ... AND ...

stop              !initaccel, v < 1  g = 0, n = n_idle      # 3.2

                               NOT HERE:

min-2i          1.15 * n_idle  ≤  n  g = 2 <-- 1            # 3.3 & 2k, driveabilty (needs init-gear)
c_b                      n < n_idle  n/clutch modifs        # 3.3 & 2k1, driveability!
too_low_p                                                   # Annex 1-8.4 (full throttle)
combine_ok_n_gear_flags(flags: pandas.core.frame.DataFrame)[source]

Merge together all N-allowed flags using AND+OR boolean logic.

Returns

an int8 dataframe with 1 where where the gear can apply, 0/NANFLAG otherwise.

combine_ok_n_p_gear_flags(flags: pandas.core.frame.DataFrame)[source]

Merge together N+P allowed flags using AND+OR boolean logic.

Returns

an int8 dataframe with 1 where where the gear can apply, 0/NANFLAG otherwise.

cycle: pd.DataFrame = None[source]

The instance that is built.

flat_cycle(df) → pandas.core.frame.DataFrame[source]

return a copy of cycle passed through flatten_columns()

make_gmax0(ok_gears: pandas.core.frame.DataFrame)[source]

the first estimation of gear to use on every sample

Not exactly like AccDB:

  • no g1–>g2 limit.

validate_nims_t_cold_end(t_cold_end: int, wltc_parts: Sequence[int])[source]

Check t_cold_end falls in a gap-stop within the 1st phase.

Todo

Incorporate validate_nims_t_cold_end() properly in validations pipeline.

wltp.cycler.NANFLAG = -1

The value representing NANs in “bool” int8 arrays (Int8 cannot write in HDF5 by tables lib)

class wltp.cycler.PhaseMarker(running_threshold: float = 1.0, phase_repeat_threshold: int = 2, up_threshold: float = - 0.1389)[source]

Bases: object

Identifies consecutive truths in series

_identify_consecutive_truths(col: pandas.core.series.Series, right_edge: bool) → pandas.core.series.Series[source]

Detect phases with a number of consecutive trues above some threshold.

Parameters
  • col – a boolean series

  • right_edge – when true, the col includes +1 sample towards the end

Example:

from cycler import PhaseMarker
cycle = pd.DataFrame({
            'v': [0,0,3,3,5,8,8,8,6,4,5,6,6,5,0,0],
        'accel': [0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0],
       'cruise': [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0],
        'decel': [0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,0],
           'up': [0,0,1,1,1,1,1,1,0,1,1,1,1,0,0,0],
    'initaccel': [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
    'stopdecel': [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0],
})
pm = PhaseMarker()

def phase(cond):
    return pm._identify_consecutive_truths((cycle.v > 1) & cond, True).astype(int)

RUN = cycle['v'] >= 1
A = (-cycle.v).diff(-1)  # GTR's acceleration definition
assert (phase(RUN & (A > 0)) == cycle.accel).all()
assert (phase(RUN & (A == 0)) == cycle.cruise).all()
assert (phase(RUN & (A < 0)) == cycle.decel).all()

Adapted from: https://datascience.stackexchange.com/a/22105/79324

add_class_phase_markers(cycle: pandas.core.frame.DataFrame, wltc_parts: Iterable[int], *, right_edge=True) → pandas.core.frame.DataFrame[source]

Adds low/mid/hight/extra high boolean index into cycle, named as p1, …

Parameters
add_phase_markers(cycle: pandas.core.frame.DataFrame, V: pandas.core.series.Series, A: pandas.core.series.Series) → pandas.core.frame.DataFrame[source]

Adds accel/cruise/decel/up phase markers into the given cycle,

based V & A columns of a cycle generated by emerge_cycle().

phase_repeat_threshold: int = 2

(positive) consider at least that many consecutive samples as belonging to a long_{stop/acc/cruise/dec} generated column, e.g. for phase_repeat_threshold=2 see the example in _identify_consecutive_truths(). if 0,unspecified (might break)

running_threshold: float = 1.0

The vehicle is stopped when its velocity is below this number (in kmh), by Annex 2-4 this is 1.0 kmh.

up_threshold: float = -0.1389

the acceleration threshold(-0.1389) for identifying n_min_drive_up/down phases, defined in Annex 2-2.k

wltp.cycler.calc_acceleration(V: Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float]) → numpy.ndarray[source]

According to formula in Annex 2-3.1

Returns

in m/s^2

Attention

the result in the last sample is NAN!

wltp.cycler.calc_ok_p_rule(cycle, gidx)[source]

Sufficient power rule for gears > g2, in Annex 2-3.5.

TODO: Separate calc_p_remain() not used yet

wltp.cycler.calc_p_remain(cycle, gidx)[source]

Return p_avail - p_req for all gears > g2 in gwot

TODO: Separate calc_p_remain() not used yet

wltp.cycler.timelens(cond, shift=1)[source]

Include earlier + later values for some condition index.

Utility for when reviewing cycle trace “events”, to look at them in context.

7.5. Module: wltp.engine

formulae for engine power & revolutions and gear-box

wltp.engine.calc_n95(wot: pandas.core.frame.DataFrame, n_rated: int, p_rated: float) → Tuple[float, float][source]

Find wot’s n95_low/high (Annex 2-2.g).

Split P_norm in 2 sections around n_rated, and interpolate separately each section.

Wot

Must contain n & p_norm.

Returns

a tuple with (low, hgh); both can be np.NAN if failed to find (error info-logged)

wltp.engine.calc_p_avail_in_gwots(gwots, *, SM) → pandas.core.frame.DataFrame[source]
Parameters

gwots – a df with 2-level multiindex columns, having at least (g1, ‘p’), and optionally (‘g1’, ‘ASM’)) for each gears (as returned by interpolate_wot_on_v_grid()).

Todo

Encapsulate GridWots in a class, like Cycler.

wltp.engine.calc_p_available(P: Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float], f_safety_margin, ASM: Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float, None] = 0) → Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float][source]

Calculate p_available according to Annex 2-3.4.

Parameters
  • P – power (usually from WOT)

  • f_safety_margin – usually 0.1

  • ASM – in % (e.g. 0.10, 0.35), not enforcing any of GTR’s restrictions (e.g. <= 50%)

Returns

same units as P

wltp.engine.interpolate_wot_on_v_grid(wot: pandas.core.frame.DataFrame, n2v_ratios) → pandas.core.frame.DataFrame[source]

Return a new linearly interpolated df on v with inv.v_decimals.

Parameters

df

A df containing at least n (in RPM); any other column gets interpolated.

Attention

Do not include non-linear columns (e.g. p_resistances(v^2)) because those interpolated values would be highly inaccurate!

Returns

the wot interpolated on a v-grid accommodating all gears with 2-level columns (item, gear)

wltp.engine.parse_wot(wot) → pandas.core.frame.DataFrame[source]

Make a wot-df from 2D-matrix(lists/numpy), dict, df(1-or-2 cols) or series,

ensuring the result wot contains one of p, p_norm, and n, n_norm columns.

Use if from interactive code to quickly feed algo with some tabular wot.

wltp.engine.preproc_wot(mdl: collections.abc.Mapping, wot) → pandas.core.frame.DataFrame[source]

Parses & validates wot from string or other matrix format

see parse_wot()

wltp.engine.validate_wot(wot: pandas.core.frame.DataFrame, n_idle, n_rated, p_rated, n_min_drive_set) → pandas.core.frame.DataFrame[source]

Higher-level validation of the wot-curves with respect to model.

7.6. Module: wltp.vehicle

formulae for cycle/vehicle dynamics

wltp.vehicle.calc_default_resistance_coeffs(test_mass, regression_curves)[source]

Approximating typical P_resistance based on vehicle test-mass.

The regression-curves are in the model resistance_coeffs_regression_curves. Use it for rough results if you are missing the real vehicle data.

wltp.vehicle.calc_inertial_power(V, A, test_mass, f_inertial)[source]

@see: Annex 2-3.1

wltp.vehicle.calc_p_resist(V: Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float], f0, f1, f2)[source]

The p_resist required to overcome vehicle-resistances for various velocities,

as defined in Annex 2-2.i (calculate V_max_vehicle).

wltp.vehicle.calc_required_power(p_resist: Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float], p_inert: Union[pandas.core.generic.NDFrame, numpy.ndarray, int, float])[source]

Equals \(road_loads + inertial_power\)

@see: Annex 2-3.1

7.7. Module: wltp.vmax

formulae estimating v_max from wot

The v_max is found by the maximum gear where p_avail_stable intersects p_resist.

Note

On Aug 2019 Mr Heinz confirmed a shortcut of the vmax discovery procedure, implemented here: scan 3 gear from top, and stop on first having v_max less-or-equal than previous, and accept v_max from that previous gear.

class wltp.vmax.VMaxRec(v_max, n_vmax, g_vmax, is_n_lim, wot)

Bases: tuple

Solution results of the equation finding the v-max of each gear:

  • v_max: in kmh; np.NAN if not found

  • n_vmax: the engine speed producing v_max; np.NAN if not found

  • g_vmax: the number of the gear producing v_max

  • is_n_lim: true if max-WOT(n) reached for VMax (ie. p_avail_stable always > p_resist)

  • wot: intermediate curves on grid-V used to solve the equation

_asdict()[source]

Return a new OrderedDict which maps field names to their values.

classmethod _make(iterable)[source]

Make a new VMaxRec object from a sequence or iterable

_replace(**kwds)[source]

Return a new VMaxRec object replacing specified fields with new values

property g_vmax

Alias for field number 2

property is_n_lim

Alias for field number 3

property n_vmax

Alias for field number 1

property v_max

Alias for field number 0

property wot

Alias for field number 4

wltp.vmax._find_p_remain_root(gid: int, wot: pandas.core.frame.DataFrame, p_resist: Union[pandas.core.series.Series, numpy.ndarray])wltp.vmax.VMaxRec[source]

Find the velocity (the “x”) where p_avail (the “y”) crosses p_resist,

rounded towards the part of wot where p_remain > 0 (like MSAccess in e.g. F new vehicle.form.vbs#L3273) or v @ max p_wot, if p_remain_stable is always positive.

Parameters

gear_gwot – A df indexed by grid v with (at least) p_remain_stable column.

Returns

a VMaxRec with v_max in kmh or np.NAN

wltp.vmax.calc_v_max(gwots: Union[pandas.core.series.Series, pandas.core.frame.DataFrame])wltp.vmax.VMaxRec[source]

Finds maximum velocity by scanning gears from the top.

Parameters

gwots – a dataframe indexed by a grid of rounded velocities, containing (at least) p_resist and p_avail_stable columns for all gears, as generated by interpolate_wot_on_v_grid(), and augmented by calc_p_avail_in_gwots() (in kW) and calc_p_resist().

Returns

a VMaxRec namedtuple.

7.8. Module: wltp.downscale

formulae downscaling cycles based on pmr/test_mass ratio

wltp.downscale.calc_f_dsc(f_dsc_orig: float, f_dsc_threshold: float, f_dsc_decimals)float[source]

ATTENTION: by the spec, f_dsc MUST be > 0.01 to apply, but in F_new_vehicle.form.txt:(3537, 3563, 3589) a +0.5 is ADDED! (see CHANGES.rst)

wltp.downscale.calc_f_dsc_orig(wltc_dsc_p_max_values, wltc_dsc_coeffs, p_rated, test_mass, f0, f1, f2, f_inertial)[source]

Check if downscaling required, and apply it.

Returns

(float) the factor

@see: Annex 1-7, p 68

wltp.downscale.calc_v_dsc(v: pandas.core.series.Series, f_dsc, dsc_phases) → pandas.core.series.Series[source]

Downscale velocity profile by f_dsc.

Returns

the downscaled velocity profile, not-rounded (by the Spec should have 1 decimal only)

  • The Spec demarks 2 UP/DOWN phases with 3 time-points in dsc_phases, eg. for class3:

    • 1533: the “start” of downscaling

    • 1724: the “tip”

    • 1763: the “end”

  • V @ start & end (1533, 1763) must remain unchanged (by the Spec & asserted).

  • The “tip” is scaled with the UP-phase (by the Spec).

  • Those numbers are recorded in the model @ <class>/downscale/phases/

  • The code asserts that the scaled V remains as smooth at tip as originally (and a bit more, due to the downscaling).

Compare v075(class-3a) with AccDB:

V_accdb V_python diff% 45.1636 45.1637 -0.000224059 # middle on tip(eg. 1724), both scale & recurse 45.1636 45.1637 -0.000122941 # on tip, scale & recurse, round(1) 45.1636 45.1637 -5.39439e-05 # on tip-1 45.1636 45.1636 0 # on tip-1, scale & recurse, round(1) 45.1636 45.1637 -6.48634e-05 # on tip+1 45.1636 45.1636 0 # on tip+1, scale & recurse, round(1)

@see: Annex 1-8, p 64-68

wltp.downscale.decide_wltc_class(wltc_data, p_m_ratio, v_max)[source]

Vehicle classification according to Annex 1-2.

wltp.downscale.downscale_by_recursing(V, f_dsc, phases)[source]

Downscale by recursing (according to the Spec).

wltp.downscale.downscale_by_scaling(V: pandas.core.series.Series, f_dsc, phases) → pandas.core.series.Series[source]

Multiply the UP/DOWN phases with 2 factors (no recurse, against the Spec).

Example, for class-3:

\[ \begin{align}\begin{aligned}V_{dsc}[1520:1725] = V[1520] + (V[1520:1725] - V[1520]) imes (1 - f_{dsc})\\V_{dsc}[1526:1743] = V[1743] + (V[1526:1743] - V[1743]) imes f_{corr}\end{aligned}\end{align} \]

7.9. Module: wltp.nmindrive

Calculate/Validate n_min_drive parameters, defined mostly in Annex 2-2.k.

>>> from wltp.nmindrive import *
>>> __name__ = "wltp.nmindrive"
class wltp.nmindrive.NMinDrives(n_min_drive1, n_min_drive2_up, n_min_drive2_stopdecel, n_min_drive2, n_min_drive_set, n_min_drive_up, n_min_drive_up_start, n_min_drive_down, n_min_drive_down_start, t_cold_end)

Bases: tuple

Consume (R)ounded values to construct a _NMinDrives instance.

_asdict()[source]

Return a new OrderedDict which maps field names to their values.

classmethod _make(iterable)[source]

Make a new NMinDrives object from a sequence or iterable

_replace(**kwds)[source]

Return a new NMinDrives object replacing specified fields with new values

property n_min_drive1

Alias for field number 0

property n_min_drive2

Alias for field number 3

property n_min_drive2_stopdecel

Alias for field number 2

property n_min_drive2_up

Alias for field number 1

property n_min_drive_down

Alias for field number 7

property n_min_drive_down_start

Alias for field number 8

property n_min_drive_set

Alias for field number 4

property n_min_drive_up

Alias for field number 5

property n_min_drive_up_start

Alias for field number 6

property t_cold_end

Alias for field number 9

wltp.nmindrive._NMinDrives

alias of wltp.nmindrive.NMinDrives

wltp.nmindrive.mdl_2_n_min_drives = Pipeline('mdl_2_n_min_drives', needs=['n_min_drive1_R', 'n_min_drive2_up_R', 'n_min_drive2_stopdecel_R', 'n_min_drive2_R', 'n_min_drive_set_R', 'n_min_drive_up_R', 'n_min_drive_up_start_R', 'n_min_drive_down_R', 'n_min_drive_down_start_R', 't_cold_end', sfx('valid: n_min_drives'), 'n_idle', 'n_idle_R', 'n_min_drive1', 'n_min_drive2', 'n_min_drive2_stopdecel', 'n_min_drive2_up', 'n_min_drive_set', 'n_min_drive_down', 'n_min_drive_down_start', 'n_rated_R', 'n_min_drive_up', 'n_min_drive_up_start', 'n_rated', sfx('valid: n_idle'), sfx('valid: n_rated'), sfx('valid: n_min_drive_up'), sfx('valid: n_min_drive_down'), sfx('valid: n_min_drive_up_start'), sfx('valid: n_min_drive_down_start')], provides=['n_min_drives', 'n_idle_R', 'n_min_drive1', 'n_min_drive1_R', 'n_min_drive2', 'n_min_drive2_R', 'n_min_drive2_stopdecel', 'n_min_drive2_stopdecel_R', 'n_min_drive2_up', 'n_min_drive2_up_R', 'n_min_drive_down', 'n_min_drive_down_R', 'n_min_drive_down_start', 'n_min_drive_down_start_R', 'n_min_drive_set', 'n_min_drive_set_R', 'n_min_drive_up', 'n_min_drive_up_R', 'n_min_drive_up_start', 'n_min_drive_up_start_R', 'n_rated_R', sfx('valid: n_min_drive_down'), sfx('valid: n_min_drive_down_start'), sfx('valid: n_min_drive_up'), sfx('valid: n_min_drive_up_start'), sfx('valid: n_min_drives'), sfx('valid: n_rated'), sfx('valid: n_idle')], x31 ops: NMinDrives, calc_n_idle_R, calc_n_min_drive1, calc_n_min_drive1_R, calc_n_min_drive2, calc_n_min_drive2_R, calc_n_min_drive2_stopdecel, calc_n_min_drive2_stopdecel_R, calc_n_min_drive2_up, calc_n_min_drive2_up_R, calc_n_min_drive_down, calc_n_min_drive_down_R, calc_n_min_drive_down_start, calc_n_min_drive_down_start_R, calc_n_min_drive_set, calc_n_min_drive_set_R, calc_n_min_drive_up, calc_n_min_drive_up_R, calc_n_min_drive_up_start, calc_n_min_drive_up_start_R, calc_n_rated_R, validate_n_min_drive_down_V1, validate_n_min_drive_down_V2, validate_n_min_drive_down_start_V1, validate_n_min_drive_down_start_V2, validate_n_min_drive_up_V1, validate_n_min_drive_up_V2, validate_n_min_drive_up_start_V1, validate_n_min_drive_up_start_V2, validate_n_min_drives, validate_n_rated_above_n_idle)

A pipeline to pre-process n_min_drives values. (the validation nodes in the plot below are hidden, not to clutter the diagram):

>>> import networkx as nx
>>> netop = mdl_2_n_min_drives
>>> hidden = netop.net.find_ops(lambda n, _: not n.name.startswith("validate_"))
>>> g = nx.DiGraph()
>>> node_attrs = {"_no_plot": True}
>>> g.add_nodes_from((n, node_attrs) for n in hidden)
>>> hidden = [n for n in netop.net.graph.nodes if str(n).startswith("sideffect(")]
>>> g.add_nodes_from((n, node_attrs) for n in hidden)

nmindrives

Example:

>>> from wltp.nmindrive import mdl_2_n_min_drives
>>> mdl = {"n_idle": 500, "n_rated": 3000, "p_rated": 80, "t_cold_end": 470}
>>> n_min_drives = mdl_2_n_min_drives.compute(mdl, "n_min_drives")
>>> n_min_drives
{'n_min_drives': NMinDrives(n_min_drive1=500, n_min_drive2_up=575, n_min_drive2_stopdecel=500,
 n_min_drive2=450, n_min_drive_set=813, n_min_drive_up=813, n_min_drive_up_start=813,
 n_min_drive_down=813, n_min_drive_down_start=813, t_cold_end=470)}
wltp.nmindrive.validate_n_min_drives()[source]

Ensure all no-sideffect validations run.

7.10. Module: wltp.invariants

definitions & idempotent formulae for physics/engineering

wltp.invariants.AND_columns_with_NANFLAGs(df: pandas.core.frame.DataFrame, nan_val: int = 1, NANFLAG=- 1) → pandas.core.series.Series[source]

see apply_bool_op_on_columns_with_NANFLAGs()

wltp.invariants.OR_columns_with_NANFLAGs(df: pandas.core.frame.DataFrame, nan_val: int = 0, NANFLAG=- 1) → pandas.core.series.Series[source]

see apply_bool_op_on_columns_with_NANFLAGs()

wltp.invariants.apply_bool_op_on_columns_with_NANFLAGs(df: pandas.core.frame.DataFrame, op, nan_val: int, NANFLAG=- 1) → pandas.core.series.Series[source]

NANs assumed nan_val`, rows with all NANs are skipped.

Parameters
  • df – a preferably dtype=int8 dataframe with NANFLAGs denoting missing values

  • op – one of pd.Series.__or__(), __and__, etc

  • nan_val – replace NANs with this value (typically 0 or 1, to cleanly convert to astype(bool)). Applied only on rows that are not all NANs.

Returns

A series(dtype=int8) with NANFLAG elements where all columns were NANFLAGs.

Example:

>>> df0 = pd.DataFrame({'a': [-1, 0, 1], 'b': [-1, -1, -1]})
>>> df0
   a  b
0 -1 -1
1  0 -1
2  1 -1
>>> df = df0.copy()
>>> apply_bool_op_on_columns_with_NANFLAGs(df0, pd.Series.__or__, 0)
0   -1
1    0
2    1
dtype: int8
>>> apply_bool_op_on_columns_with_NANFLAGs(df0, pd.Series.__and__, 1)
0   -1
1    0
2    1
dtype: int8
wltp.invariants.asint(n)[source]

Convert numbers or arrays to integers, only when not containing NAN/INFs.

Parameters

n – number/sequence of numbers

Returns

number/ndarray, or the unrounded(!) n if it contained NAN/INFs

Examples:

>>> asint(3.14)
3
>>> type(_)
<class 'int'>
>>> asint(float('inf'))
inf
>>> type(_)
<class 'float'>
>>> asint([1, 3.14])
array([1, 3])
>>> _.dtype             # doctest: +SKIP
'int64'
>>> asint([np.NAN, 3.14, -np.inf])  # input untouched!!
array([ nan, 3.14, -inf])
>>> _.dtype
dtype('float64')
wltp.invariants.nround1(n)[source]

The GTR rounding for N (RPM) to integer precision, e.g. for n_min_drive_set.

wltp.invariants.nround10(n)[source]

The GTR rounding for N (RPM) to the nearest 10 RPMs precision, e.g. for n_idle.

wltp.invariants.round1(n, decimals=0)[source]

Rounding with the Access DB method (all ties half-up: 0.5 –> 1).

TIP: Double rounding might be needed to achieve stability on ties with long decimals (see downscale scale vs recurse)

Parameters
  • n – number/array to round

  • decimals – Number of decimal places to round to (default: 0). If decimals is negative, it specifies the number of positions to the left of the decimal point. None means keep it as it is.

>>> round1(2.5, None)
2.5
>>> round1(2.5)
3.0
>>> round1(np.arange(-6.55, 7), 1)
array([-6.5, -5.5, -4.5, -3.5, -2.5, -1.5, -0.5,
       0.5,  1.5,  2.5,  3.5, 4.5,  5.5,  6.5])
>>> round1(np.arange(-6.65, 7), 1)
array([-6.6, -5.6, -4.6, -3.6, -2.7, -1.7, -0.7,
       0.3,  1.3,  2.3,  3.4, 4.4,  5.4,  6.4])
>>> round1([0.49999999999999994, 5000000000000001.0, -2.4, 2.4])
 array([ 1.e+00,  5.e+15, -2.e+00,  2.e+00])
wltp.invariants.vround(n, *, decimals=1)[source]

The rounding of the GTR, used for Vs already close to grid, e.g. to index with results from operations on the grid.

7.11. Module: wltp.autograph

Harvest functions & annotate their dependencies to build pipelines.

class wltp.autograph.Autograph(out_patterns: Union[str, Iterable[str]] = None, overrides: Mapping[Union[str, Iterable[str]], Mapping] = None, renames: Mapping = None, full_path_names: bool = False, sep=None)[source]

Bases: wltp.autograph.Prefkey

Make a graphtik operation by inspecting a function

The params below (except full_path_names) are merged in this order (1st takes precendance):

  1. args in wrap_fn()

  2. dict from overrides keyed by name

  3. decorated with autographed()

  4. inspected from the callable

Parameters
  • out_patterns

    Autodeduce provides by parsing function-names against a collection of these items, and decide provides by the the 1st one matching (unless provides are specified in the overrides):

    • regex: may contain 1 or 2 groups:

      • 1 group: the name of a single provides

      • 2 groups: 2nd is the name of a single sideffected dependency, the 1st is the sideffect acting upon the former;

    • str: matched as a prefix of the function-name, which is trimmed by the first one matching to derrive a single provides;

    Note that any out_sideffects in overrides, alone, do not block the rule above.

  • overrides

    a mapping of fn-keys --> dicts with keys:

    name, needs, provides, renames, inp_sideffects, out_sideffects
    

    An fn-key may be a string-tuple of names like:

    [module, [class, ...] callable
    

  • renames – global from --> to renamings applied both onto needs & provides. They are applied after merging has been completed, so they can rename even “inspected” names.

  • full_path_names – whether operation-nodes would be named after the fully qualified name (separated with / by default)

Example:

>>> def calc_sum_ab(a, b=0):
...     return a + b
>>> aug = Autograph(out_patterns=['calc_', 'upd_'], renames={"a": "A"})
>>> aug.wrap_fn(calc_sum_ab)
FunctionalOperation(name='calc_sum_ab',
                    needs=['A', 'b'(?)],
                    provides=['sum_ab'],
                    fn='calc_sum_ab')
__init__(out_patterns: Union[str, Iterable[str]] = None, overrides: Mapping[Union[str, Iterable[str]], Mapping] = None, renames: Mapping = None, full_path_names: bool = False, sep=None)[source]

Initialize self. See help(type(self)) for accurate signature.

_apply_renames(rename_maps: Iterable[Union[Mapping, unset]], word_lists: Iterable)[source]

Rename words in all word_lists matching keys in rename_maps.

_collect_rest_op_args(decors: dict)[source]

Collect the rest operation arguments from autographed decoration.

_match_fn_name_pattern(fn_name, pattern) → Union[str, Tuple[str, str]][source]

return matched group or groups, callable results or after matched prefix string

wrap_fn(fn_path, name_path=T(unset), needs=T(unset), provides=T(unset), renames=T(unset), inp_sideffects=T(unset), out_sideffects=T(unset))graphtik.op.FunctionalOperation[source]

Overriddes order: my-args, self.overrides, autograph-decorator, inspection

Parameters
  • fn_path

    either a callable, or the path to a callable, like:

    [module[, class, ...]] callable
    

  • name_path – either a single string, or a tuple-of-strings, corresponding to the given fn_path

class wltp.autograph.FnHarvester(*, excludes: Iterable[Union[str, Iterable[str]]] = None, base_modules: Iterable[Union[module, str]] = None, predicate: Callable[[Any], bool] = None, include_methods=False, sep=None)[source]

Bases: wltp.autograph.Prefkey

Collect public routines, classes & their methods into collected attribute.

Parameters
  • collected

    a list of 2-tuples:

    (name_path, item_path)
    

    where the 2 paths correspond to the same items; the last path element is always a callable, and the previous items may be modules and/or classes, in case non-modules are given directly in harvest():

    [module, [class, ...] callable
    

    E.g. the path of a class constructor is (module_name, class_name).

  • excludes – names to exclude; they can/be/prefixed or not

  • base_modules – skip function/classes not in these modules; if not given, include all items. If string, they are searched in sys.modules.

  • predicate – any user callable accepting a single argument returning falsy to exclude the visited item

  • include_methods – Whether to collect methods from classes

Example:

>>> from wltp import cycler, downscale, engine, vehicle, vmax
>>> modules = (cycler, downscale, engine, vehicle, vmax)
>>> funcs = FnHarvester(
...     include_methods=False,
...     predicate=_is_in_my_project
... ).harvest(*modules)
>>> len(funcs) > 60
True
>>> sorted(list(zip(*funcs))[0])
[('wltp.cycler', 'CycleBuilder'),
 ('wltp.cycler', 'NMinDrives'),
 ('wltp.cycler', 'PhaseMarker'),
...
>>> excludes = "utils io invariant cycles datamodel idgears plots".split()
>>> excludes = (
...     "utils wio inv cycles datamodel idgears plots "
...     "GearMultiIndexer VMaxRec "
...     "timelens "
... ).split()
>>> funcs = FnHarvester(
...     include_methods=True,
...     excludes=(excludes),
...     base_modules=modules
... ).harvest()
>>> len(funcs) > 30
True
>>> sorted(list(zip(*funcs))[0])
[('wltp.cycler', 'CycleBuilder'),
 ('wltp.cycler', 'CycleBuilder', 'add_columns'),
...
 ('wltp.vmax', 'calc_v_max')]
__init__(*, excludes: Iterable[Union[str, Iterable[str]]] = None, base_modules: Iterable[Union[module, str]] = None, predicate: Callable[[Any], bool] = None, include_methods=False, sep=None)[source]

Initialize self. See help(type(self)) for accurate signature.

_collect(name_path, item_path)[source]

Obey decorated name

_harvest(name_path, item_path)[source]

Recursively collect modules, routines & classes,.

harvest(*items: Any, base_modules=Ellipsis) → List[Tuple[str, Callable]][source]
Parameters

items

items with __name__, like module, class, functions. If nothing is given, attr:`baseModules is used instead.

Note

This parameter works differently from base_modules, that is, harvesting is not limited to those modules only, recursing to any imported ones from items.

Returns

the collected

is_harvestable(name_path, item)[source]

Exclude already-seen, private, user-excluded objects(by name or path).

paths()[source]

returns the paths only (no callables), sorted

class wltp.autograph.Prefkey(sep=None)[source]

Bases: object

Index into dicts with a key or a joined(prefix+key), where prefix: tuple

__init__(sep=None)[source]

Initialize self. See help(type(self)) for accurate signature.

wltp.autograph._is_in_my_project(item)bool[source]

UNUSED

wltp.autograph.autographed(fn=T(unset), *, name=T(unset), needs=T(unset), provides=T(unset), renames=T(unset), returns_dict=T(unset), aliases=T(unset), inp_sideffects=T(unset), out_sideffects=T(unset), domain=None, **kws)[source]

Decorator adding _autograph func-attribute with overrides for Autograph.

The rest arguments coming from graphtik.operation.

Parameters
  • domain – if set, overrides are not applied for the “default” domain; it allows to reuse the same function to build different operation.

  • renames – mappings to rename both any matching the final needs & provides

  • inp_sideffects – appended into needs; if a tuple, makes it a sfxed

  • out_sideffects – appended into provides; if a tuple, makes it a sfxed

  • kws

    the rest arguments of graphtik.operation, such as:

    endured, parallel, marshalled, node_props
    

wltp.autograph.camel_2_snake_case(word)[source]
>>> camel_2_snake_case("HTTPResponseCodeXYZ")
'http_response_code_xyz'

From https://stackoverflow.com/a/1176023/548792

wltp.autograph.get_autograph_decors(fn, default=None, domain=None)dict[source]

Return the dict with autographed() keywords as keys.

7.12. Module: wltp.io

utilities for starting-up, parsing, naming, indexing and spitting out data

class wltp.io.GearMultiIndexer(items: Optional[Iterable[str]], gnames: pandas.core.series.Series, top_gear: int, generator: Callable[[int], str])[source]

Bases: object

Multi-indexer for 2-level df columns like (item, gear) with 1-based & closed-bracket gear.

Example grid_wots:

p_avail  p_avail  ... n_foo  n_foo
     g1       g2  ...    g1     g2
… Warning::

negative indices might not work as expected if gnames do not start from g1 (e.g. when constructed with from_df() static method)

Examples:

  • Without items you get simple gear-indexing:

    >>> G = GearMultiIndexer.from_ngears(5)
    >>> G.gnames
    1    g1
    2    g2
    3    g3
    4    g4
    5    g5
    dtype: object
    >>> G[1:3]
    ['g1', 'g2', 'g3']
    >>> G[::-1]
    ['g5', 'g4', 'g3', 'g2', 'g1']
    >>> G[3:2:-1]
    ['g3', 'g2']
    >>> G[3:]
    ['g3', 'g4', 'g5']
    >>> G[3:-1]
    ['g3', 'g4', 'g5']
    >>> G[-1:-2:-1]
    ['g5', 'g4']
    
    >>> G[[1, 3, 2]]
    ['g1', 'g3', 'g2']
    
    >>> G[-1]
    'g5'
    
  • When items are given, you get a “product” MultiIndex:

    >>> G.with_item("foo", "bar")[1:3]
    MultiIndex([('foo', 'g1'),
                ('foo', 'g2'),
                ('foo', 'g3'),
                ('bar', 'g1'),
                ('bar', 'g2'),
                ('bar', 'g3')],
               )
    >>> G.with_item("foo")[2]
    MultiIndex([('foo', 'g2')],
               )
    

    Use no items to reset them:

    >>> G.with_item('foo').with_item()[:]
    ['g1', 'g2', 'g3', 'g4', 'g5']
    
  • Notice that G0 changes “negative” indices:

    >>> G[[-5, -6, -7]]
    ['g1', 'g5', 'g4']
    >>> G = GearMultiIndexer.from_ngears(5, gear0=True)
    >>> G[:]
    ['g0', 'g1', 'g2', 'g3', 'g4', 'g5']
    >>> G[[-5, -6, -7]]
    ['g1', 'g0', 'g5']
    
classmethod from_df(df, items: Iterable[str] = None, generator: Callable[[int], str] = <function gear_name>)[source]

Derive gears from the 2nd-level columns, sorted, and the last one becomes ngear

Parameters

df – the 2-level df, not stored, just to get gear-names.

… Warning::

Negative indices might not work as expected if gnames does not start from g1.

generator: GearGenerator = None[source]

a function returns the string representation of a gear, like 1 --> 'g1'

gnames: pd.Series = None[source]

2-level columns; use a generator like gear_names() (default)

to make a pd.Series like:

{1: 'g1', 2: 'g2', ...}
items: Optional[Iterable[str]] = None[source]

1st level column(s)

property ng

The number of gears extracted from 2-level dataframe.

It equals top_gear if gnames are from 1–>top_gear.

top_gear: int = None[source]

Setting it to a gear not in gnames, indexing with negatives may not always work.

wltp.io._root_pstep = ``[source]

Contains all path/column names used, after code has run code. Don’t use it directly, but either - through context-vars to allow for redefinitions, or - call paths_collected() at the end of a code run.

wltp.io.flatten_columns(columns, sep='/')[source]

Use inflate_columns() to inverse it

wltp.io.getdval(mdl, key, default)[source]

Returns default if key not in mdl or value is None/NAN

wltp.io.inflate_columns(columns, levels=2, sep='/')[source]

Use flatten_columns() to inverse it

wltp.io.paths_collected(with_orig=False, tag=None) → List[str][source]

Return path/column names used, after code has run code.

See mappings.Pstep._paths().

wltp.io.pstep_factory = <ContextVar name='root' default=``>

The root-path wrapped in a context-var so that client code can redfine paths & column names momentarily with:

token = wio.pstep_factory.set(mapping.Pstep(<mappings>))
try:
    ...
finally:
    wio.pstep_factory.reset(token)
   ...

7.13. Module: wltp.utils

software utils unrelated to physics or engineering

class wltp.utils.Token[source]

Bases: str

wltp.utils.asdict(i, argname: str)[source]

Converts iterables-of-pairs or just a pair-tuple into a dict.

Parameters

argname – Used in the exception raised when i not an iterable.

wltp.utils.aslist(i, argname: Optional[str], allowed_types=<class 'list'>)[source]

Converts iterables (except strings) into a list.

Parameters

argname – If string, it’s used in the exception raised when i not an iterable. If None, wraps non-iterables in a single-item list.

wltp.utils.astuple(i, argname: Optional[str])[source]

Converts iterables (except strings) into a tuple.

Parameters

argname – If string, it’s used in the exception raised when i not an iterable. If None, wraps non-iterables in a single-item tuple.

wltp.utils.matlab_pwd_changed(path: os.PathLike, oc: oct2py.octave)[source]

Temporarily change Matlab’s Oct2Pyc session’s working-dir to (and yield) given path.

Returns

yields the given path as a pathlib.Path instance

wltp.utils.pwd_changed(path: os.PathLike)[source]

Temporarily change working-dir to (and yield) given path.

7.14. Module: wltp.cli

(OUTDATED) command-line entry-point for launching this wltp tool

See also

main()

class wltp.cli.FileSpec(io_method, fname, file, frmt, path, append, renames, kws)

Bases: tuple

_asdict()[source]

Return a new OrderedDict which maps field names to their values.

classmethod _make(iterable)[source]

Make a new FileSpec object from a sequence or iterable

_replace(**kwds)[source]

Return a new FileSpec object replacing specified fields with new values

property append

Alias for field number 5

property file

Alias for field number 2

property fname

Alias for field number 1

property frmt

Alias for field number 3

property io_method

Alias for field number 0

property kws

Alias for field number 7

property path

Alias for field number 4

property renames

Alias for field number 6

class wltp.cli.RawTextHelpFormatter(prog, indent_increment=2, max_help_position=24, width=None)[source]

Bases: argparse.RawDescriptionHelpFormatter

Help message formatter which retains formatting of all help text.

Only the name of this class is considered a public API. All the methods provided by the class are considered an implementation detail.

wltp.cli.main(argv=None)[source]

Calculates an engine-map by fitting data-points vectors, use –help for getting help.

REMARKS:

* All string-values are case-sensitive.
* Boolean string-values are case insensitive:
    False  : false, off, no,  == 0
    True   : true,  on,  yes, != 0
* In KEY=VALUE pairs, the values are passed as string.  For other types,
  substitute '=' with:.
    +=     : integer
    *=     : float
    ?=     : boolean
    :=     : parsed as json
    @=     : parsed as python (with eval())

EXAMPLES:

Assuming a ‘vehicle.json’ file like this:

{
    "unladen_mass":1230,
    "test_mass":   1300,
    "v_max":    195,
    "p_rated":  100,
    "n_rated":  5450,
    "n_idle":   950,
    "n_min":    None, # Can be overridden by manufacturer.
    "gear_ratios":      [120.5, 75, 50, 43, 37, 32],
    "f0": 100,
    "f1": 0.5,
    "f2": 0.04,
}

then the following examples:

## Calculate and print fitted engine map's parameters
#     for a petrol vehicle with the above engine-point's CSV-table:
>> %(prog)s -I vehicle.csv file_model_path=/vehicle
-I vehicle.csv file_frmt=SERIES model_path=/params header@=None 
## ...and if no header existed:
>> %(prog)s -m /vehicle:=n_idle -I engine.csv header@=None

## Assume PME column contained normalized-Power in Watts,
#    instead of P in kW:
>> %(prog)s -m fuel=petrol -I engine.csv  -irenames X X 'Pnorm (w)'

## Read the same table above but without header-row and
#    store results into Excel file, 1st sheet:
>> %(prog)s -m fuel=petrol -I engine.csv --icolumns CM PME PMF -I engine_map.xlsx sheetname+=0

## Supply as inline-json more model-values required for columns [RPM, P, FC]
#    read from <stdin> as json 2D-array of values (no headers).
#    and store results in UTF-8 regardless of platform's default encoding:
>> %(prog)s -m '/engine:={"fuel":"petrol", "stroke":15, "capacity":1359}' \
        -I - file_frmt=JSON orient=values -c RPM P FC \
        -O engine_map.txt encoding=UTF-8

Now, if input vectors are in 2 separate files, the 1st, ‘engine_1.xlsx’, having 5 columns with different headers than expected, like this:

OTHER1   OTHER2       N        "Fuel waste"   OTHER3
0       -1            12       0.14           "some text"
...

and the 2nd having 2 columns with no headers at all and the 1st column being ‘Pnorm’, then it, then use the following command:

>> %(prog)s -O engine_map -m fuel=petrol \
        -I=engine_1.xlsx sheetname+=0 \
        -c X   X   N   'Fuel consumption'  X \
        -r X   X   RPM 'FC(g/s)'           X \
        -I=engine_2.csv header@=None \
        -c Pnorm X
wltp.cli.parse_column_specifier(arg)[source]

Argument-type for –icolumns, syntaxed like: COL_NAME [(UNITS)].

wltp.cli.parse_key_value_pair(arg)[source]

Argument-type for syntax like: KEY [+*?:]= VALUE.

wltp.cli.store_part_as_df(filespec, part)[source]

If part is Pandas, store it as it is, else, store it as json recursively.

Parameters
  • filespec (FileSpec) – named_tuple

  • part – what to store, originating from model(filespec.path))

7.15. Module: wltp.plots

(OUTDATED) code for plotting diagrams related to wltp cycles & results

class wltp.plots.DataCursor(ax=None, text_template='x: {x:0.2f}\ny: {y:0.2f}\n{txt}', annotations=None)[source]

Bases: object

Use:

fig.canvas.mpl_connect('pick_event', DataCursor(plt.gca()))
__init__(ax=None, text_template='x: {x:0.2f}\ny: {y:0.2f}\n{txt}', annotations=None)[source]

Initialize self. See help(type(self)) for accurate signature.

class wltp.plots.MidPointNorm(midpoint=0, vmin=None, vmax=None, clip=False)[source]

Bases: matplotlib.colors.Normalize

A “diverging” or “bipolar” Normalize for Colormaps on a central-point, with values going up or down.

Example:

norm = MidPointNorm(midpoint=3) imshow(X, norm=norm)

__init__(midpoint=0, vmin=None, vmax=None, clip=False)[source]

If vmin or vmax is not given, they are initialized from the minimum and maximum value respectively of the first input processed. That is, __call__(A) calls autoscale_None(A). If clip is True and the given value falls outside the range, the returned value will be 0 or 1, whichever is closer. Returns 0 if:

vmin==vmax

Works with scalars or arrays, including masked arrays. If clip is True, masked values are set to 1; otherwise they remain masked. Clipping silently defeats the purpose of setting the over, under, and masked colors in the colormap, so it is likely to lead to surprises; therefore the default is clip = False.

wltp.plots.cartesians_to_polarDiffs(X1, Y1, X2, Y2)[source]

Given 2 sets of 2D-points calcs the polar euclidean-distance and angle from 2nd-pair of points to 1st-pair.

7.16. Module: wltp.idgears

(OUTDATED, irrelevant) Detects vehile’s gear-ratios from cycle-data and reconstructs the gears-profile by identifying the actual gears used.

Note

NOT RELLEVANT to generation of wltp cyles.

The following terms and arguments are used throughout this module:

gear-ratio(s):

the “NoverV”, which is the inverse of the “engine-speed-to-velocity” (“STV”). Conceptually it is the number of engine revolutions required, in RPM, in order for the the vehicle to travel with 1 km/h.

cycle-ratios:

The actual or detected NoverV-ratio on each cycle-point.

cycle-gears:

The actual or identified gear used on each cycle-point.

cycle-data

a pd.DataFrame containing (at the begining) N and V columns with [rpm] and [km/h] as units respectively.

The detection of the gear-ratios happens in a 3 steps, approximation or guessing, estimation and selection:

  1. Produce a number of different approximate sets of gear-ratios (the “guesses”) by producing histograms of the ratios with different combinations of bins, and then taking the first #gears of peaks.

  2. Feed these “guessed” sets of gear-ratios into a robust (with median) kmeans clustering algorithm, and

  3. pick the gear-ratios with the minimum distortion.

The identification of the actual gear on each cycle-data point (reconstructing the gear-profile) happens in 2 steps:

  1. On each cycle-point select the Gear with smallest absolute-difference with the respective identified ratio;

  2. Reconstruct engine-speed by dividing velocity-profile with identified gear-ratio on each cycle-point.

class wltp.idgears.Detekt(distort, guess, final, all_peaks_df, hist_X, hist_Y)

Bases: tuple

_asdict()[source]

Return a new OrderedDict which maps field names to their values.

classmethod _make(iterable)[source]

Make a new Detekt object from a sequence or iterable

_replace(**kwds)[source]

Return a new Detekt object replacing specified fields with new values

property all_peaks_df

Alias for field number 3

property distort

Alias for field number 0

property final

Alias for field number 2

property guess

Alias for field number 1

property hist_X

Alias for field number 4

property hist_Y

Alias for field number 5

wltp.idgears._append_aproximate_Detekt(ngears, cases, ratios, all_peaks_df, hist_X, hist_Y)[source]

Appends 2 sets of ratios for each one specified as input, the 2nd one being a linspace between the min-max.

wltp.idgears._approximate_ratios_by_binning(ratios, bins, ngears)[source]
Returns

3 sets of ratios: 1. all peaks detected with bins specified 2. the first #gears peaks 3. the first #gears peaks detected by binning the space between the previous #gears identified

wltp.idgears._estimate_ratios_by_kmeans(obs, guess, **kmeans_kws)[source]

Adapted kmeans to use norm1 distances (identical to euclidean-norm2 for 1D) and using median() for each guess, to ignore outliers and identify “gear-lines”.

wltp.idgears._gather_final_Detekts(ngears, cycle_df, guessed_gears)[source]
Parameters

cycle_df (pd.DataFrame) – a dataframe with N and V columns with units [rpm] and [km/h] respectively (or inferred by comparing the means of these 2 columns).

wltp.idgears._gather_guessed_Detekts(ngears, cycle_df)[source]

Makes a number gear-ratios guesses based on histograms with different bin combinations.

wltp.idgears._norm1_1d_vq(obs, guess, is_robust=False)[source]

Simplified from scipy.cluster.vq.py_vq2()

wltp.idgears.dequantize(df, method='linear')[source]

Tries to undo results of a non-constant sampling rate (ie due to indeterministic buffering).

Parameters

method (str) – see pd.DataFrame.interpolate() that is used to fill-in column-values that are held constant

Note

The results wil never have a flat section, so checking for some value (ie 0) must always apply for some margin (ie (-e-4, e-4).

wltp.idgears.dequantize_unstabbleMean(df, method='linear')[source]
Parameters

method (str) – see pd.DataFrame.interpolate() that is used to fill-in column-values that are held constant

wltp.idgears.detect_gear_ratios_from_cycle_data(ngears, cycle_df)[source]

Use a 2 step procedure if you want to plot the results, by invoking run_gear_ratios_detections_on_cycle_data() and plot_idgears_results() separately.

Returns

a ndarray with the detected gear-ratios (for the STVs, inverse them)

wltp.idgears.identify_gears_from_cycle_data(cycle_df, gear_ratios)[source]

Like identify_gears_from_ratios() but with more sane filtering (ie v above 1 km/h).

Parameters
  • cycle_df (pd.DataFrame) – it must contain (at least) N and V columns (units: [rpm] and [km/h] respectively)

  • gear_ratios (ndarray) – the same as identify_gears_from_ratios()

Returns

the same as identify_gears_from_ratios()

wltp.idgears.identify_gears_from_ratios(cycle_ratios, gear_ratios)[source]

Return arrays will miss NaNs!

Parameters
  • cycle_ratios (ndarray) – a single column array/list/ndarray of ratios (STVs or inverse).

  • gear_ratios (ndarray) – this list/ndarray of gear-ratios with len equal to the #gears

Returns

a 2-tuple, where [0] is the 0-based identified-gears, and [1] the distortion for each cycle-point.

wltp.idgears.moving_average(x, window)[source]
Parameters

window (int) – odd windows preserve phase

From http://nbviewer.ipython.org/github/demotu/BMC/blob/master/notebooks/DataFiltering.ipynb

wltp.idgears.plot_idgears_results(cycle_df, detekt, fig=None, axes=None, original_points=None)[source]
Parameters

detekt – A Detekt-namedtuple with the data to plot

wltp.idgears.reconstruct_engine_speed(cycle_df, gear_ratios)[source]

Adds

Parameters

gear_ratios (ndarray) – this list/ndarray of gear-ratios with len equal to the #gears

TODO: Class-method

wltp.idgears.run_gear_ratios_detections_on_cycle_data(ngears, cycle_df)[source]

Invoke this one if you want to draw the results.

Parameters

cycle_df (pd.DataFrame) – it must contain (at least) N and V columns (units: [rpm] and [km/h] respectively)

Returns

a list of all Detekt tuples sorted with the most probable one at the the head, needed. Its 1st element is the solution

7.17. Validation tests & HDF5 DB

Among the various tests, those running on ‘sample’ databases for comparing differences with existing tool are the following:

test_samples_db

(DEPRECATED) Compares the results of synthetic vehicles from JRC against pre-phase-1b Heinz’s tool.

test_wltp_db

(DEPRECATED) Compares the results of a batch of wltp_db vehicles against phase-1b-alpha Heinz’s tool.

The following scripts in the sources maybe used to preprocess various wltc data:

  • devtools/printwltcclass.py

  • devtools/csvcolumns8to2.py

7.17.1. Module: tests.test_samples_db

(abandoned)

(DEPRECATED) Compares the results of synthetic vehicles from JRC against pre-phase-1b Heinz’s tool.

  • Run as Test-case to generate results for sample-vehicles.

  • Run it as cmd-line to compare with Heinz’s results.

class tests.test_samples_db.ExperimentSampleVehs(methodName='runTest')[source]

Bases: unittest.case.TestCase

Compares a batch of vehicles with results obtained from “Official” implementation.

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test1_AvgRPMs()[source]

Check mean-engine-speed diff with Heinz within some percent.

Results:

                   mean         std          min          max
python      1876.555626  146.755857  1652.457262  2220.657166
heinz       1892.048584  148.248303  1660.710716  2223.772904
diff_prcnt     0.008256    0.010170     0.004995     0.001403

Keeping idle engine revs:

                   mean         std          min          max
python      1898.453462  146.889032  1674.151741  2239.621701
heinz       1892.048584  148.248303  1660.710716  2223.772904
diff_prcnt    -0.003385    0.009254    -0.008094    -0.007127
test1_PMRatio()[source]

Check mean-engine-speed diff with Heinz within some percent for all PMRs.

Results:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(40.759, 49.936]       1814.752308     1822.011660    0.004000      4
(49.936, 59.00401]     1861.137208     1879.822876    0.010040      4
(59.00401, 68.072]     2015.693195     2031.240237    0.007713      3
(68.072, 77.14]        1848.735584     1859.116047    0.005615      5
(77.14, 86.208]                NaN             NaN         NaN      0
(86.208, 95.276]       1786.879366     1807.764020    0.011688      5
(95.276, 104.344]      1956.288657     1980.523043    0.012388      3
(104.344, 113.412]     1929.718933     1947.787155    0.009363      3
(113.412, 122.48]      2033.321183     2051.602998    0.008991      1
(122.48, 131.548]      1781.487338     1781.591893    0.000059      1
(131.548, 140.616]             NaN             NaN         NaN      0
(140.616, 149.684]     1895.125082     1907.872848    0.006727      1

Keeping idle engine revs:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(40.759, 49.936]       2079.060852     2071.114936   -0.003837      4
(49.936, 59.00401]     1915.715680     1911.017351   -0.002459      4
(59.00401, 68.072]     1941.701195     1930.170461   -0.005974      3
(68.072, 77.14]        1867.228321     1863.086063   -0.002223      5
(77.14, 86.208]                NaN             NaN         NaN      0
(86.208, 95.276]       1803.169294     1795.347029   -0.004357      5
(95.276, 104.344]      1813.784185     1807.303905   -0.003586      3
(104.344, 113.412]     1929.050124     1929.524894    0.000246      3
(113.412, 122.48]      1716.185416     1704.537479   -0.006833      1
(122.48, 131.548]      1769.131368     1750.813992   -0.010462      1
(131.548, 140.616]             NaN             NaN         NaN      0
(140.616, 149.684]     2083.586370     2084.413659    0.000397      1
tests.test_samples_db.driver_weight = 70

For calculating unladen_mass.

7.17.2. Module: tests.test_wltp_db

(abandoned)

(DEPRECATED) Compares the results of a batch of wltp_db vehicles against phase-1b-alpha Heinz’s tool.

  • Run as Test-case to generate results for sample-vehicles.

  • Run it as cmd-line to compare with Heinz’s results.

class tests.test_wltp_db.WltpDbTests(methodName='runTest')[source]

Bases: unittest.case.TestCase

Compares a batch of vehicles with results obtained from “official” implementation.

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test1_Downscale()[source]

Check mean-downscaled-velocity diff with Heinz within some percent.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

           python       heinz    diff_prcnt
count  378.000000  378.000000  0.000000e+00
mean    45.973545   46.189082  4.688300e-01
std      1.642335    1.126555 -4.578377e+01
min     35.866421   36.659117  2.210133e+00
25%     46.506718   46.504909 -3.892020e-03
50%     46.506718   46.506504 -4.620879e-04
75%     46.506718   46.506719  4.116024e-08
max     46.506718   46.506719  4.116024e-08

Not forcing class3b, honoring declared v_max & unladen_mass:

           python       heinz    diff_prcnt
count  382.000000  382.000000  0.000000e+00
mean    44.821337   44.846671  5.652189e-02
std      5.054214    5.050208 -7.933394e-02
min     28.091672   28.388418  1.056347e+00
25%     46.506718   46.504868 -3.978244e-03
50%     46.506718   46.506478 -5.162230e-04
75%     46.506718   46.506719  4.116033e-08
max     46.506718   46.506719  4.116033e-08
test2a_gear_diffs()[source]

Check diff-gears with Heinz stays within some percent.

### Comparison history ###

Class3b-Vehicles, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

             count       MEAN        STD  min  max
gears        23387  75.931818  56.921729    6  279
accell       19146  62.162338  48.831155    4  238
senza rules  16133  52.379870  35.858415   11  170

Separated test/unladen masses:

         diff_gears    diff_accel     diff_orig
count    378.000000    378.000000    378.000000
mean     104.965608     86.171958     90.235450
std      100.439783     82.613475    109.283901
min        6.000000      4.000000     11.000000
25%       36.250000     25.250000     23.000000
50%       69.000000     57.500000     51.000000
75%      142.000000    119.750000    104.750000
max      524.000000    404.000000    600.000000
sum    39677.000000  32573.000000  34109.000000
mean%      5.831423      4.787331      5.013081

Not forcing class3b, honoring declared v_max & unladen_mass:

         diff_gears    diff_accel     diff_orig
count    382.000000    382.000000    382.000000
mean      75.994764     63.633508     54.083770
std       58.290971     51.885162     38.762326
min        2.000000      2.000000      6.000000
25%       29.000000     22.000000     19.000000
50%       57.000000     48.500000     45.000000
75%      111.000000     97.000000     78.750000
max      279.000000    243.000000    173.000000
sum    29030.000000  24308.000000  20660.000000
mean%      4.221931      3.535195      3.004654
test2b_gear_diffs_transplanted()[source]

Check driveability-only diff-gears with Heinz stays within some percent.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

        diff_gears   diff_accel  diff_orig
count   378.000000   378.000000        378
mean     15.566138     5.634921          0
std      16.554295     8.136700          0
min       0.000000     0.000000          0
25%       5.000000     1.000000          0
50%      11.000000     3.000000          0
75%      19.750000     7.000000          0
max     123.000000    78.000000          0
sum    5884.000000  2130.000000          0
mean%     0.864785     0.313051          0

Not forcing class3b, honoring declared v_max & unladen_mass:

        diff_gears   diff_accel  diff_orig
count   382.000000   382.000000        382
mean     12.599476     4.651832          0
std      15.375930     7.566103          0
min       0.000000     0.000000          0
25%       4.000000     0.000000          0
50%       9.000000     2.000000          0
75%      15.000000     6.000000          0
max     123.000000    78.000000          0
sum    4813.000000  1777.000000          0
mean%     0.699971     0.258435          0
test3a_n_mean()[source]

Check mean-rpm diff with Heinz stays within some percent.

### Comparison history ###

Class3b-Vehicles, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

                   mean         std          min          max
python      1766.707825  410.762478  1135.458463  3217.428423
heinz       1759.851498  397.343498  1185.905053  3171.826208
diff_prcnt    -0.3896     -3.3772       4.4428      -1.4377

Separated test/unladen masses:

            python        heinz  diff_prcnt
count   378.000000   378.000000    0.000000
mean   1923.908119  1899.366431   -1.292099
std     628.998854   593.126296   -6.048047
min    1135.458463  1185.905053    4.442839
25%    1497.544940  1495.699889   -0.123357
50%    1740.927971  1752.668517    0.674384
75%    2121.459309  2111.876041   -0.453780
max    4965.206982  4897.154914   -1.389625

Not forcing class3b, honoring declared v_max & unladen_mass:

            python        heinz  diff_prcnt
count   382.000000   382.000000    0.000000
mean   1835.393402  1827.572965   -0.427914
std     476.687485   464.264779   -2.675781
min    1135.458463  1185.905053    4.442839
25%    1486.886555  1482.789006   -0.276341
50%    1731.983662  1739.781233    0.450210
75%    2024.534101  2018.716963   -0.288160
max    3741.849187  3750.927263    0.242609

Keeping idle engine revs:

            python        heinz  diff_prcnt
count   382.000000   382.000000    0.000000
mean   1852.183403  1827.572965   -1.346619
std     473.142045   464.264779   -1.912113
min    1168.757027  1185.905053    1.467202
25%    1507.030779  1482.789006   -1.634877
50%    1749.246014  1739.781233   -0.544021
75%    2043.861777  2018.716963   -1.245584
max    3747.026551  3750.927263    0.104102
test3b_n_mean_transplanted()[source]

Check driveability-only mean-rpm diff with Heinz stays within some percent.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

            python        heinz  diff_prcnt
count   378.000000   378.000000    0.000000
mean   1880.045112  1899.366431    1.027705
std     572.842493   593.126296    3.540904
min    1150.940393  1185.905053    3.037921
25%    1477.913404  1495.699889    1.203486
50%    1739.882957  1752.668517    0.734852
75%    2073.715015  2111.876041    1.840225
max    4647.136063  4897.154914    5.380063

Not forcing class3b, honoring declared v_max & unladen_mass:

            python        heinz  diff_prcnt
count   382.000000   382.000000    0.000000
mean   1818.519842  1827.572965    0.497829
std     469.276397   464.264779   -1.079474
min    1150.940393  1185.905053    3.037921
25%    1467.153958  1482.789006    1.065672
50%    1730.051632  1739.781233    0.562388
75%    2010.264758  2018.716963    0.420452
max    3704.999890  3750.927263    1.239605
test4a_n_mean__PMR()[source]

Check mean-rpm diff with Heinz stays within some percent for all PMRs.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

                    gened_mean_rpm  heinz_mean_rpm  diff_ratio  count
pmr
(9.973, 24.823]        1566.018469     1568.360963    0.001496     32
(24.823, 39.496]       1701.176128     1702.739797    0.000919     32
(39.496, 54.17]        1731.541637     1724.959671   -0.003816    106
(54.17, 68.843]        1894.477475     1877.786294   -0.008889     61
(68.843, 83.517]       1828.518522     1818.720627   -0.005387     40
(83.517, 98.191]       1824.060716     1830.482140    0.003520      3
(98.191, 112.864]      1794.673461     1792.693611   -0.001104     31
(112.864, 127.538]     3217.428423     3171.826208   -0.014377      1
(127.538, 142.211]     1627.952896     1597.571904   -0.019017      1
(142.211, 156.885]             NaN             NaN         NaN      0
(156.885, 171.558]             NaN             NaN         NaN      0
(171.558, 186.232]     1396.061758     1385.176569   -0.007858      1

Separated test/unladen masses:

                     gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(11.504, 26.225]        1579.612698     1585.721306    0.386716     28
(26.225, 40.771]        1706.865069     1700.689983   -0.363093     41
(40.771, 55.317]        1866.150857     1841.779091   -1.323273    119
(55.317, 69.863]        2122.662626     2085.262950   -1.793523    122
(69.863, 84.409]        2228.282795     2171.952804   -2.593518     29
(84.409, 98.955]        1783.316413     1787.378401    0.227777      4
(98.955, 113.501]       1718.157828     1718.516147    0.020855     31
(113.501, 128.0475]     2005.415058     1954.763742   -2.591173      2
(128.0475, 142.594]     1566.601860     1553.383676   -0.850928      1
(142.594, 157.14]               NaN             NaN         NaN      0
(157.14, 171.686]               NaN             NaN         NaN      0
(171.686, 186.232]      1396.061758     1385.176569   -0.785834      1

Not forcing class3b, honoring declared v_max & unladen_mass:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(9.973, 24.823]        1560.010258     1563.836656    0.245280     33
(24.823, 39.496]       1725.209986     1725.004638   -0.011904     34
(39.496, 54.17]        1737.811065     1730.770088   -0.406812    123
(54.17, 68.843]        1996.999520     1983.753219   -0.667739     94
(68.843, 83.517]       2051.088434     2034.594136   -0.810692     59
(83.517, 98.191]       1964.832555     1958.081066   -0.344801      4
(98.191, 112.864]      1682.122484     1684.443875    0.138004     31
(112.864, 127.538]     2718.877009     2687.055802   -1.184241      2
(127.538, 142.211]     1660.925042     1668.155469    0.435325      1
(142.211, 156.885]             NaN             NaN         NaN      0
(156.885, 171.558]             NaN             NaN         NaN      0
(171.558, 186.232]     1396.061758     1385.176569   -0.785834      1
Mean: 0.419219429398

pandas 0.15.1:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(9.973, 24.823]        2037.027221     2038.842442    0.089111     33
(24.823, 39.496]       2257.302959     2229.999526   -1.224369     34
(39.496, 54.17]        1912.075914     1885.792807   -1.393743    123
(54.17, 68.843]        1716.720028     1717.808457    0.063402     94
(68.843, 83.517]       1677.882399     1683.916224    0.359610     59
(83.517, 98.191]       1535.881170     1551.609661    1.024070      4
(98.191, 112.864]      1571.290286     1589.997331    1.190553     31
(112.864, 127.538]     1409.308426     1425.965019    1.181898      2
(127.538, 142.211]     1975.481368     1967.808440   -0.389923      1
(142.211, 156.885]             NaN             NaN         NaN      0
(156.885, 171.558]             NaN             NaN         NaN      0
(171.558, 186.232]     1950.377512     1937.426430   -0.668468      1
Mean diff_prcnt: 0.632095580562
                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
Keeping idle engine revs::

pmr (9.973, 24.823] 2058.624153 2038.842442 -0.970242 33 (24.823, 39.496] 2271.419763 2229.999526 -1.857410 34 (39.496, 54.17] 1927.898841 1885.792807 -2.232803 123 (54.17, 68.843] 1733.545963 1717.808457 -0.916139 94 (68.843, 83.517] 1694.461857 1683.916224 -0.626256 59 (83.517, 98.191] 1553.854990 1551.609661 -0.144710 4 (98.191, 112.864] 1590.081566 1589.997331 -0.005298 31 (112.864, 127.538] 1427.367629 1425.965019 -0.098362 2 (127.538, 142.211] 1989.461646 1967.808440 -1.100372 1 (142.211, 156.885] NaN NaN NaN 0 (156.885, 171.558] NaN NaN NaN 0 (171.558, 186.232] 1960.918157 1937.426430 -1.212522 1 Mean diff_prcnt: 0.76367613389

test4b_n_mean__PMR_transplanted()[source]

Check driveability-only mean-rpm diff with Heinz stays within some percent for all PMRs.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(9.973, 24.823]        1557.225037     1568.360963    0.715113     32
(24.823, 39.496]       1686.859826     1696.482640    0.570457     34
(39.496, 54.17]        1771.670097     1789.409819    1.001299    120
(54.17, 68.843]        2133.400050     2165.214662    1.491263     94
(68.843, 83.517]       2020.903728     2043.741660    1.130085     59
(83.517, 98.191]       1886.836446     1890.040533    0.169813      4
(98.191, 112.864]      1788.434592     1792.693611    0.238142     31
(112.864, 127.538]     2580.884314     2568.011660   -0.501269      2
(127.538, 142.211]     1581.625191     1597.571904    1.008249      1
(142.211, 156.885]             NaN             NaN         NaN      0
(156.885, 171.558]             NaN             NaN         NaN      0
(171.558, 186.232]     1367.068837     1385.176569    1.324566      1

Separated test/unladen masses:

                     gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(11.504, 26.225]        1572.733597     1585.721306    0.825805     28
(26.225, 40.771]        1690.081663     1700.689983    0.627681     41
(40.771, 55.317]        1821.319706     1841.779091    1.123327    119
(55.317, 69.863]        2060.507029     2085.262950    1.201448    122
(69.863, 84.409]        2142.964427     2171.952804    1.352723     29
(84.409, 98.955]        1783.214173     1787.378401    0.233524      4
(98.955, 113.501]       1713.473617     1718.516147    0.294287     31
(113.501, 128.0475]     1950.373771     1954.763742    0.225084      2
(128.0475, 142.594]     1543.937285     1553.383676    0.611838      1
(142.594, 157.14]               NaN             NaN         NaN      0
(157.14, 171.686]               NaN             NaN         NaN      0
(171.686, 186.232]      1367.068837     1385.176569    1.324566      1

Not forcing class3b, honoring declared v_max & unladen_mass:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(9.973, 24.823]        1551.901645     1563.836656    0.769057     33
(24.823, 39.496]       1713.382835     1725.004638    0.678296     34
(39.496, 54.17]        1722.174466     1730.770088    0.499114    123
(54.17, 68.843]        1974.768859     1983.753219    0.454958     94
(68.843, 83.517]       2026.630271     2034.594136    0.392961     59
(83.517, 98.191]       1954.817179     1958.081066    0.166966      4
(98.191, 112.864]      1676.678357     1684.443875    0.463149     31
(112.864, 127.538]     2678.973439     2687.055802    0.301696      2
(127.538, 142.211]     1658.577318     1668.155469    0.577492      1
(142.211, 156.885]             NaN             NaN         NaN      0
(156.885, 171.558]             NaN             NaN         NaN      0
(171.558, 186.232]     1367.068837     1385.176569    1.324566      1
Mean diff_prcnt: 0.469021296461

pandas 0.15.1:

                    gened_mean_rpm  heinz_mean_rpm  diff_prcnt  count
pmr
(9.973, 24.823]        2021.882193     2038.842442    0.838835     33
(24.823, 39.496]       2204.136804     2229.999526    1.173372     34
(39.496, 54.17]        1880.733341     1885.792807    0.269016    123
(54.17, 68.843]        1710.819917     1717.808457    0.408491     94
(68.843, 83.517]       1677.846860     1683.916224    0.361735     59
(83.517, 98.191]       1541.587174     1551.609661    0.650141      4
(98.191, 112.864]      1579.049392     1589.997331    0.693325     31
(112.864, 127.538]     1411.921405     1425.965019    0.994646      2
(127.538, 142.211]     1976.193317     1967.808440   -0.426102      1
(142.211, 156.885]             NaN             NaN         NaN      0
(156.885, 171.558]             NaN             NaN         NaN      0
(171.558, 186.232]     1954.662077     1937.426430   -0.889616      1
Mean diff_prcnt: 0.558773102894
test5a_n_mean__gear()[source]

Check mean-rpm diff% with Heinz stays within some percent for all gears.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

n_mean      python        heinz      diff%
gear
0       732.358286   804.656085  -9.925769
1       870.080494  1177.547512 -44.450903
2      1789.787609  1650.383967   6.520319
3      1921.271483  1761.172027   7.804359
4      1990.286402  1886.563262   5.401895
5      2138.445024  2112.552162   1.892950
6      2030.970322  1987.865039   2.228276

Not forcing class3b, honoring declared v_max & unladen_mass:

gear
0        735.143823   808.795812 -10.052865
1        799.834530  1139.979330 -47.027383
2       1598.773915  1582.431975   1.119054
3       1793.617644  1691.589756   5.768020
4       1883.863510  1796.957457   5.024360
5       2095.211754  2052.059948   2.430360
6       2033.663975  1990.344346   2.238421
test5b_n_mean__gear_transplanted()[source]

Check mean-rpm diff% with Heinz stays within some percent for all gears.

### Comparison history ###

Force class3b, Phase-1b-beta(ver <= 0.0.8, Aug-2014) with Heinz maxt gear-time=2sec:

n_mean      python        heinz      diff%
gear
0       732.357001   804.656085  -9.926855
1       966.022039  1177.547512 -24.409425
2      1678.578373  1650.383967   1.616768
3      1791.644768  1761.172027   1.700642
4      1883.504933  1886.563262   0.119165
5      2099.218160  2112.552162  -0.320293
6      1985.732086  1987.865039  -0.096754

Not forcing class3b, honoring declared v_max & unladen_mass:

n_mean       python        heinz      diff%
gear
0        735.077116   808.795812 -10.065886
1        932.586982  1139.979330 -24.285307
2       1606.040896  1582.431975   1.379144
3       1721.141364  1691.589756   1.686708
4       1803.212699  1796.957457   0.370703
5       2053.822313  2052.059948   0.142138
6       1988.195381  1990.344346  -0.097482
tests.test_wltp_db._file_pairs(fname_glob)[source]

Generates pairs of files to compare, skipping non-existent and those with mismatching #_of_rows.

Example:

for (veh_num, df_g, df_h) in _file_pairs(‘wltp_db_vehicles-00*.csv’):

pass

tests.test_wltp_db.aggregate_single_columns_means(gened_column, heinz_column)[source]

Runs experiments and aggregates mean-values from one column of each (gened, heinz) file-sets.

tests.test_wltp_db.driver_weight = 70

For calculating unladen_mass.

tests.test_wltp_db.vehicles_applicator(fname_glob, pair_func)[source]

Applies the fun onto a pair of (generated, heinz) files for each tested-vehicle in the glob and appends results to list, preffixed by veh_num.

Parameters

pair_func – signature: func(veh_no, gened_df, heinz_df)–>sequence_of_numbers

Returns

a dataframe with the columns returned from the pair_func, row_indexed by veh_num

8. Schema

The JSON-schema of the data for this project:

>>> from wltp import datamodel, utils
>>> schema = datamodel._get_model_schema()
>>> print(utils.yaml_dumps(schema))
$schema: http://json-schema.org/draft-07/schema#
$id: /data
title: Json-schema describing the input for a WLTC simulator.
type: object
additionalProperties: false
description: The vehicle attributes required for generating the WLTC velocity-profile
  downscaling and gear-shifts.
properties:
  id:
    title: Any identifier for the object
    type:
    - integer
    - string
  unladen_mass:
    title: vehicle unladen mass
    type:
    - number
    exclusiveMinimum: 0
    description: The mass (kg) of the vehicle without the driver, used to decide its
      class, as defined in Annex-4
  test_mass:
    title: vehicle test mass
    $ref: '#/definitions/positiveNumber'
    description: The test mass of the vehicle used in all calculations (kg), as defined
      in Annex 4.2.1.3.1, pg 94.
  v_max:
    title: maximum vehicle velocity
    type:
    - number
    exclusiveMinimum: 0
    description: (OUT) The calculated maximum velocity, as defined in Annex 2-2.i.
  n_vmax:
    title: engine speed for maximum vehicle velocity
    type:
    - number
    exclusiveMinimum: 0
    description: (OUT) The engine speed for `v_max`.
  g_vmax:
    title: gear for maximum vehicle velocity
    type:
    - number
    exclusiveMinimum: 0
    description: (OUT) The gear for achieving `v_max`.
  p_rated:
    title: maximum rated power
    $ref: '#/definitions/positiveNumber'
    description: The maximum rated engine power (kW) as declared by the manufacturer.
  n_rated:
    title: rated engine revolutions
    $ref: '#/definitions/positiveNumber'
    description: |
      The rated engine revolutions at which an engine develops its maximum power.
      If the maximum power is developed over an engine revolutions range,
      it is determined by the mean of this range.
  n_idle:
    title: idling revolutions
    $ref: '#/definitions/positiveNumber'
    description: The idling engine revolutions (Annex 1).
  n_min:
    title: minimum engine revolutions
    type:
    - array
    - number
    description: |
      Either a number with the minimum engine revolutions for gears > 2 when the vehicle is in motion,
      or an array with the exact `n_min` for each gear (array must have length equal to gears).

      If unspecified, the minimum `n` for gears > 2 is determined by the following equation:

          n_min = n_idle + f_n_min(=0.125) * (n_rated - n_idle)

      Higher values may be used if requested by the manufacturer, by setting this one.
  gear_ratios:
    title: gear ratios
    $ref: '#/definitions/positiveNumbers'
    maxItems: 24
    minItems: 3
    description: An array with the gear-ratios obtained by dividing engine-revolutions
      (1/min) by vehicle-velocity (km/h).
  f0:
    title: driving resistance coefficient f0
    type:
    - number
    description: The driving resistance coefficient f0, in N (Annex 4).
  f1:
    title: driving resistance coefficient f1
    type:
    - number
    description: The driving resistance coefficient f1, in N/(km/h) (Annex 4).
  f2:
    title: driving resistance coefficient f2
    type:
    - number
    description: The driving resistance coefficient f2, in N/(km/h)² (Annex 4).
  n_min_drive1:
    description: '[1/min], see Annex 2-2.k, n_min for gear 1'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive2_up:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive2_stopdecel:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive2:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive_set:
    description: |
      [1/min], Annex 2-2.k,
      calculated minimum engine speed for gears > 2:

        n_min_drive = n_idle + 0.125 (n_rated - n_idle)

      Do not override this, its value will be ignored.
      Set higher values only into parameters n_min_drive_up/down.

      Matlab call this `CalculatedMinDriveEngineSpeedGreater2nd`.
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive_up:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive_up_start:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive_down:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  n_min_drive_down_start:
    description: '[1/min], Annex 2-2.k'
    type:
    - number
    exclusiveMinimum: 0
  t_cold_end:
    description: see Annex 2-2.k about n_mins
    type:
    - number
    minimum: 0
    default: 0
  wot:
    title: wide open throttle curves
    description: |
      An array/dict/dataframe holding the full load power curves for (at least) 2 columns ('n', 'p')
      or the normalized values ('n_norm', 'p_norm').

      Example:

          np.array([
              [ 600, 1000, ... 7000 ],
              [ 4, 10, ... 30 ]
          ]).T

      * The 1st column or `n` is the engine revolutions in min^-1:
      * The 2nd column or `p` is the full-power load in kW:

      Normalized N/P Example:

          np.array([
              [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 ],
              [ 6.11, 21.97, 37.43, 51.05, 62.61, 72.49, 81.13, 88.7, 94.92, 98.99, 100., 96.28, 87.66 ]
          ]).T

      * The 1st column or `n_norm` is the normalized engine revolutions, within [0.0, 1.20]:

                  n_norm = (n - n_idle) / (n_rated  - n_idle)

      * The 2nd column or `p_norm` is the normalized values of the full-power load against the p_rated,
        within [0, 1]:

                  p_norm = p / p_rated
    type:
    - object
    - array
  grid_wots:
    description: |
      A dataframe with 2-level columns (item, gear)
      - `p_avail_stable`: reduced by safety-margin, but not by ASM
      - `p_avail`: reduced by both SM & ASM
      - `p_resist`: road loads power
      - `p_req`: road loads & cycle power
  pmr:
    title: Power to Unladen-Mass
    description: Power/unladen-Mass ratio (W/kg).
    type: number
  wltc_class:
    description: The name of the WLTC-class (found within WLTC-data/classes) as selected
      by the experiment.
    type: string
    enum:
    - class1
    - class2
    - class3a
    - class3b
  resistance_coeffs_regression_curves:
    description: Regression curve factors for calculating vehicle's `resistance_coeffs`
      when missing.
    type: array
    minItems: 3
    maxItems: 3
    items:
      type: array
      minItems: 2
      maxItems: 2
      items:
        type: number
  f_dsc_threshold:
    title: Downscale-factor threshold
    description: |
      The limit for the calculated `f_dsc` below which no downscaling happens.
    type:
    - number
    default: 0.01
  f_dsc_decimals:
    title: Downscale-factor rounding decimals
    type:
    - number
    default: 3
  driver_mass:
    title: Driver's mass (kg)
    description: |
      The mass (kg) of the vehicle's driver (Annex 1-3.2.6, p9), where:

          Unladen_mass = Test_mass - driver_mass
    type:
    - number
    default: 75
  v_stopped_threshold:
    description: Velocity (km/h) under which (<=) to idle gear-shift (Annex 2-3.3,
      p71).
    type:
    - number
    default: 1
  f_inertial:
    description: This is the `kr` inertial-factor used in the 2nd part of the formula
      for calculating required-power (Annex 2-3.1).
    type:
    - number
    default: 1.03
  f_safety_margin:
    description: |
      Safety-margin(SM) factor for load-curve (Annex 2-3.4).
    type:
    - number
    default: 0.1
  f_n_min:
    description: For each gear > 2, N :> n_min = n_idle + f_n_min * n_range (unless
      `n_min` overridden by manufacturer)
    type:
    - number
    default: 0.125
  f_n_min_gear2:
    description: Gear-2 is invalid when N :< f_n_min_gear2 * n_idle.
    type:
    - number
    default: 0.9
  f_n_clutch_gear2:
    description: |
      A 2-value number-array(f1, f2) controlling when to clutch gear-2:
          N < n_clutch_gear2 := max(f1 * n_idle, f2 * n_range + n_idle),
      unless "clutched"...
    type:
    - array
    default:
    - 1.15
    - 0.03
  f_dsc:
    description: |
      The downscaling-factor as calculated by the experiment (Annex 1-8.3).

      Set it to 0 to disable downscaling, (or to any other value to force it).
    type: number
  b_no_g0_downshift:
    description: |
      a flag to suppress shifting to gear-0(idle) during downshifts
    type: boolean
  wltc_data:
    $ref: /wltc
  cycle:
    description: |
      An inp/out dataframe matrix with 2-level columns(item, gear),
      and items, in addition to those of `grid_wots`:
      - `v_cycle`: reduced by safety-margin, but not by ASM
      - `v_dsc`: (optional)
      - `v_target`: road loads power
      - `(ok_..., gN)`: rflags denoting the validity of certain conditions for gear-N
      - `g_max0`: does not include corrections for the `g1-->g2 n_min` rule,
        nor points with insufficient power.
definitions:
  positiveInteger:
    type: integer
    exclusiveMinimum: 0
  positiveNumber:
    type: number
    exclusiveMinimum: 0
  positiveIntegers:
    type: array
    items:
      $ref: '#/definitions/positiveInteger'
  positiveNumbers:
    type: array
    items:
      $ref: '#/definitions/positiveNumber'
# Must follow `properties` due to `autoRemoveNull`.
required:
- f0
- f1
- f2
- test_mass
- p_rated
- n_rated
- n_idle
- gear_ratios
- wot
- driver_mass
- v_stopped_threshold
- f_inertial
- f_safety_margin
- f_n_min
- f_n_min_gear2
- f_n_clutch_gear2
- wltc_data