Why Warehouses Need Check Characters
In high-volume retail fulfillment networks (such as Argos and Sainsbury’s logistics networks), human pickers navigate thousands of shelf bays per shift. If verification relied simply on reciting the shelf code itself (e.g., location "10AK"), confirmation bias would lead pickers to glance at the location code on their terminal, walk to an adjacent bay (e.g., "10AL"), and sub-consciously repeat "10AK" from memory.
To break this confirmation bias, warehouse systems decouple the shelf coordinate from the verification response. Each shelf label displays a prominently printed "Check Character" (or check digit) that cannot be deduced by simple visual inspection of the shelf code. The worker must read the physical check character printed on the shelf label into the microphone.
Behind the scenes, the warehouse system calculates this character deterministically using weighted mathematical algorithms.
The Store Location Algorithm: Weighted ASCII Modulo 26
In store stockrooms, locations typically follow a 4-character alphanumeric structure (e.g., "10AK", where "10" denotes the aisle, "A" denotes the bay, and "K" denotes the shelf level).
The algorithm processes each character by its 7-bit ASCII value and applies a position-dependent weight vector: W = [5, 7, 7, 3]. The weights ensure that adjacent digit swaps or single-character substitutions produce distinct mathematical sums.
The mathematical formulation is defined as:
/**
* Store Check Character Mathematical Formulation
*
* Location: c0, c1, c2, c3 (e.g. '1', '0', 'A', 'K')
* Position Weights: W = [5, 7, 7, 3]
*
* Sum = (ASCII(c0) * 5) + (ASCII(c1) * 7) + (ASCII(c2) * 7) + (ASCII(c3) * 3)
* Remainder = Sum % 26
* Check Character = NATO_PHONETIC_ALPHABET[Remainder]
*/
export function calculateStoreCheckChar(location: string): string {
const chars = location.trim().toUpperCase().substring(0, 4);
const weights = [5, 7, 7, 3];
let sum = 0;
for (let i = 0; i < 4; i++) {
sum += chars.charCodeAt(i) * weights[i];
}
const remainder = sum % 26;
const NATO = [
'ALPHA', 'BRAVO', 'CHARLIE', 'DELTA', 'ECHO', 'FOXTROT',
'GOLF', 'HOTEL', 'INDIA', 'JULIET', 'KILO', 'LIMA',
'MIKE', 'NOVEMBER', 'OSCAR', 'PAPA', 'QUEBEC', 'ROMEO',
'SIERRA', 'TANGO', 'UNIFORM', 'VICTOR', 'WHISKEY', 'X-RAY',
'YANKEE', 'ZULU'
];
return NATO[remainder];
}
Step-by-Step Calculation Walkthrough: Location "10AK"
Let us trace the exact arithmetic for location "10AK":
• Position 1: Character "1" → ASCII 49 × weight 5 = 245
• Position 2: Character "0" → ASCII 48 × weight 7 = 336
• Position 3: Character "A" → ASCII 65 × weight 7 = 455
• Position 4: Character "K" → ASCII 75 × weight 3 = 225
Total Sum: 245 + 336 + 455 + 225 = 1,261
Modulo Operation: 1,261 mod 26 = 13
NATO Alphabet Mapping: Index 13 maps to "NOVEMBER".
Therefore, when a picker arrives at shelf "10AK", the printed label displays "NOVEMBER" (or phonetic "N"), confirming exact location alignment.
| Prefix Code | Operational Zone Name | Spoken Voice Convention | Example Location |
|---|---|---|---|
| J | Jewellery | JEWELLERY [Bay] [Shelf] | J1PG → "JEWELLERY ONE PAPA GOLF" |
| S | Security | SECURITY [Bay] [Shelf] | S1PG → "SECURITY ONE PAPA GOLF" |
| L | Linbin (Small Parts Bin) | [Aisle] LINBIN [Shelf] | L10A → "ONE ZERO LINBIN ALPHA" |
| Z | Bulk Overstock | [Aisle] BULK [Shelf] | Z10A → "ONE ZERO BULK ALPHA" |
| CA | Cash Office | CASH OFFICE [Number] | CA12 → "CASH OFFICE ONE TWO" |
| CP | Collection Point | COLLECTION POINT [Number] | CP12 → "COLLECTION POINT ONE TWO" |
| RETS | Returns Holding | Fixed Static Assignment | RETS → "OSCAR" (Store) / "FOUR EIGHT" (RFC) |
The Regional Fulfilment Centre (RFC) Algorithm: Modulo 99
In massive Regional Fulfilment Centres (RFCs), warehouse layouts scale across multiple mezzanine floors and high-bay aisles. RFC locations use a 4-letter alphabetical coordinate system (e.g., "ABCD", "RETS", "ZZZZ").
Rather than mapping to a NATO word, the RFC engine outputs a two-digit spoken number (00 through 98) using an additive base offset of 45 and a modulo 99 operator.
The zero-indexed alphabetical value v_i is computed as ASCII(c_i) - 65, ensuring values range strictly between 0 and 25:
/**
* RFC Check Character Formulation
*
* Location: 4 letters (e.g. 'R', 'E', 'T', 'S')
* Letter Value: v_i = ASCII(char) - 65 (0 to 25)
* Base Offset: 45
* Position Weights: W = [5, 7, 7, 3]
*
* Sum = 45 + (v0 * 5) + (v1 * 7) + (v2 * 7) + (v3 * 3)
* Check Digit = Sum % 99
* Format: Spoken tens and units (e.g. 48 -> "FOUR EIGHT")
*/
export function calculateRfcCheckChar(location: string): { checkDigits: string; spokenWords: string } {
const chars = location.trim().toUpperCase().substring(0, 4);
const weights = [5, 7, 7, 3];
let sum = 45; // Base offset constant
for (let i = 0; i < 4; i++) {
const letterValue = chars.charCodeAt(i) - 65;
sum += letterValue * weights[i];
}
const checkVal = sum % 99;
const tens = Math.floor(checkVal / 10);
const units = checkVal % 10;
const DIGIT_WORDS = ['ZERO', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE'];
return {
checkDigits: checkVal.toString().padStart(2, '0'),
spokenWords: `${DIGIT_WORDS[tens]} ${DIGIT_WORDS[units]}`
};
}
Mathematical Comparison: Luhn vs Modulo 26 vs Modulo 99
How does this approach compare to standard commercial checksums like the Luhn algorithm (used in ISO/IEC 7812 credit card validation) or ISBN-10 (modulo 11)?
• Luhn Algorithm: Highly effective at detecting single-digit substitutions and adjacent digit transpositions for purely numeric strings, but relies on base-10 doubling and cannot natively handle mixed alphanumeric strings without character map tables.
• Store Modulo 26 with [5, 7, 7, 3] Weights: Tailored specifically for speech interaction. By mapping remainders to the 26 NATO words, it converts an abstract mathematical verification step into an unmistakable acoustic phrase.
• RFC Modulo 99: Expands the remainder space from 26 potential outcomes to 99 potential outcomes (00 to 98), reducing the probability of random accidental collision from 1 in 26 (~3.8%) down to approximately 1 in 99 (~1.01%).