Min Max Scaler — Machine Learning/Preprocessing
Machine_Learning/Preprocessing/Min_Max_Scaler · 1 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text
Description#
The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.
Min-Max Scaler
Machine Learning / Preprocessing
Per-feature rescaling to a fixed range, scikit-learn's
MinMaxScaler at inference:
X_std = (u − data_min) ÷ (data_max − data_min), then y = X_std × (f_max − f_min) + f_min.
Reach for this rather than the Standard Scaler when the network was trained on
inputs squashed to a fixed interval – image-style [0,1] features, or the
[−1,1] a tanh front end expects. Internally the four fitted numbers collapse
to the two sklearn itself stores, scale_ and min_, so a
feature costs one multiply and one add.
Ports
- u – the feature column, [m,1], where m is the number of entries in Data Min and Data Max. The size is checked rather than broadcast.
- Output – y, the same [m,1] shape: this block rescales a signal, it never changes its dimensions.
Parameters
- Data Min –
scaler.data_min_, an [m,1] column: the smallest value each feature took while fitting. - Data Max –
scaler.data_max_, an [m,1] column. A feature whose max EQUALS its min has no range; its denominator is replaced by one, matching scikit-learn's own rule, so a constant feature maps to f_min instead of making the whole vector infinite. - Feature Range – the target interval as a [2,1] column,
[f_min; f_max]. This is sklearn's
feature_range, whose default is [0; 1]; [−1; 1] is the other common fit. f_max must be greater than f_min. - Clip
- Off – a sample outside the fitted range maps outside the feature range too, in proportion. This is sklearn's default.
- On – the output is clamped into [f_min, f_max], which is
sklearn's
clip=True. This is what a deployed scaler is usually fitted with, because live data does leave the range seen during training and a network given an out-of-range input is extrapolating.
inverse_transformdoes not clamp either, and clamping a recovered engineering value to the SCALED range would pin it to the wrong quantity. - Direction
- Standardize – y = u × scale + off, the forward transform that feeds a model.
- Inverse – recovers the engineering value from a scaled one, which is what takes a deployed regression's output back into real units. Without it a model in this library predicts in scaled numbers, which is the wrong thing to hand a controller.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The two derived constants are baked into the generated code as literals at full precision; there is no tunable parameter, because a fitted statistic is not something to retune on the target.
The three HDL targets are genuine Q16.16 fixed point and synthesizable: the division that turns the fitted range into a scale happens once, when the configuration is loaded, so the datapath is a multiply, an add and – in Clip mode – two comparisons. The same constants are used by the block itself, so the exported core and the in-app run compute bit-identical values.
Simulink bridge
None, and the first reason is about this installation rather than about
Simulink: neither the Statistics and Machine Learning Toolbox nor the
Deep Learning Toolbox is installed here, so a bridge could not be run
against a parity testbench even if one were written. Base Simulink also offers no
fitted-scaler block – the nearest thing is a Gain, a Bias and a Saturation
wired together, and mapping this block onto any one of the three would assert an
equivalence false for the other two. The bridge reports the block rather than
dropping it silently, and it has no parity testbench, which is the
documented consequence of Support::None rather than a gap. Code
export verification still covers it across all ten languages.
Notes
- Algebraic and stateless: the output depends only on the current input, so the block cannot break an algebraic loop.
- No state space, deliberately – the map is affine, and y = C·x + D·u has nowhere to put the offset. Model reduction reports the block as unmergeable, which is the honest answer.
- Compared with the Standard Scaler: that one centres on the mean and divides by the standard deviation, leaving the output unbounded; this one pins the fitted range onto a chosen interval. Neither is a substitute for the other, and a model expects the one it was trained with.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Preprocessing/Min_Max_Scaler |
| family | Machine_Learning/Preprocessing |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Min_Max_Scaler |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Preprocessing/Min_Max_Scaler/ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Min_Max_Scaler.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Preprocessing/Min_Max_Scaler/ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Min_Max_Scaler.h |
| default size on canvas | 120 × 80 px |
| ports at insert | 1 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | u |
| 2 | out | ICoreDouble | y |
Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.
Configuration variables#
| Config variable | Default | Simulink parameter |
|---|---|---|
Data Min | [-2; 0; 10] | — |
Data Max | [6; 4; 30] | — |
Feature Range | [0; 1] | — |
Clip | Off%~%On~~Off | — |
Direction | Standardize%~%Inverse~~Standardize | — |
Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): no verifiable Simulink equivalent. Neither the Statistics and Machine Learning Toolbox nor the Deep Learning Toolbox is installed on this machine, so a bridge could not be run against a parity testbench even if one were written. Base Simulink offers no fitted-scaler block in any case: the nearest thing is a Gain, a Bias and a Saturation wired together, and mapping onto any one of the three would claim an equivalence false for the other two. Re-create the scaler from those blocks, using this block's derived scale and offset
Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0every stimulus in the sample errored — cross-checks skipped
The verdict above is
tools/docs/check_block_descriptions.py(P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.
File banner (developer view)#
The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).
Min-Max Scaler — sklearn's MinMaxScaler, evaluated at inference y = u * scale + off scale = (f_max - f_min) / (data_max - data_min) off = f_min - data_min * scale Clip mode: y is then clamped to [f_min, f_max]
The four fitted numbers collapse to TWO per feature, exactly as sklearn stores them (scale_ and min_), so a feature costs one multiply and one add. See the header for why that collapse is what keeps the HDL synthesizable and the export bit-identical.
⚠ The CLAMP is the reason Clip is a MODE and not a config flag: it is a different code path in all ten backends, and in three of them it is a different KIND of construct (a sequential if in VHDL, a nested ternary in the two Verilogs, MIN/MAX in ST). A config that merely retunes numbers can share a rig; this cannot.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Min Max Scaler. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.
Category unsampled · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60
Sample data: docs/generated/samples/Machine_Learning__Preprocessing__Min_Max_Scaler.json