PLC Programming SAPLC ProgrammingSOUTH AFRICA

learn · South Africa

Recipe management: parameter sets and audit trails

Recipe management for SA controls engineers — three bottling-line recipes, ISA-88 parameter sets, audit logs, and changeover from 22 minutes to 90 sec.

Recipe management is the part of the controls job that production keeps asking for and that engineering keeps shipping as a quick fix until somebody asks for an audit trail and the quick fix becomes an emergency. The bottling line that runs 250 ml on Monday, 500 ml on Tuesday, and 1 L on Wednesday wants a clean changeover that does not require an engineer at the keyboard for an hour, and it wants to know — three months later, when a regulator asks — exactly which recipe was loaded into which batch and who pressed the button. This tutorial walks the simulator's three-product bottling-line scenario, shows what a recipe parameter set actually looks like, builds the audit-log entry format, and quantifies the changeover-time win.

Try the simulator →

Why this matters on real plants

Most lines on FMCG and pharma plants run more than one product, and the changeover from one product to the next is one of the five biggest sources of lost production time on a typical line. A line that runs two shifts at 80 percent OEE loses about three hours per shift to non-producing time; of those three hours, somewhere between 30 and 60 minutes is changeover. A bottling line that switches between three SKUs across a 16-hour day might do four changeovers per shift; at 22 minutes each that is 88 minutes per shift, or about 18 percent of available production time. Cutting that to 90 seconds per changeover with a recipe-load button — same parameters, same setpoints, same sequence steps — gives the line back roughly 80 minutes of production per shift, or 13 percent of capacity, without buying any new hardware.

The cost of getting recipe management wrong is not just the changeover time. It is the misruns. A line where the operator types parameters into the HMI by hand on every changeover is a line where a typo on the fill volume turns a Wednesday morning's first hundred bottles into reject product. The operator typed 950 instead of 1000 because their finger slipped. The line ran for nine minutes before the QC tech caught it and pulled the bottles. Ninety bottles times R8 reject cost equals R720 lost, every changeover, on the changeovers where the operator typoed — call it one in twenty changeovers, R720 times 200 changeovers per year times 5 percent miss rate, about R7000 per year on this single line. Trivial money in the context of the plant; embarrassing money in the context of "we have a controls engineer on staff and a recipe-load button would have prevented this".

The third reason it matters more on regulated SA plants — pharma, food, beverage — than on a generic discrete-manufacturing line: the audit trail. The South African regulator, and the international regulators that audit local plants supplying export markets, all require traceability of which recipe was loaded into which batch, who authorised it, and when. A line that holds the recipe parameters in retentive memory but has no audit log of recipe-load events is a line that cannot produce that traceability when asked. The first time an audit lands and the engineer cannot answer "what recipe was used on batch 240517-B-013", the line is on a finding and on a remediation plan, and the controls team is suddenly working weekends.

The mental model

A recipe is a named set of parameters. Not a program — the program is the same for every product, written once, debugged once, and reused. The parameters are the values that the program reads on every cycle: setpoints, timer presets, counter targets, ramp rates, sequence-step durations. A recipe is a snapshot of those parameter values, given a name (LARGE, MEDIUM, SMALL — or by SKU code, or by product description), stored in the controller (or on a recipe server reachable by the controller), and loaded into the runtime parameter block when the operator selects it.

The mental separation that makes recipe management work is between runtime parameters (the values the program actually uses, held in a single struct or UDT in the PLC), recipe storage (the named sets of values, held in a dedicated recipe array or in a database reachable from the PLC), and the load operation (the explicit, audited copy from a named recipe into the runtime parameter block, triggered by an operator action and logged to the audit trail). The program runs against the runtime parameters. The recipes sit alongside as a library. The load operation is the only place where recipes touch runtime, and it is the only place that needs auditing.

Audit-log discipline is the second pillar. Every recipe-load event writes a single, structured row to the audit log: timestamp (down to the second), operator badge or login (not "OPERATOR1" — the actual person), recipe name (or ID), batch number it was loaded against, and a one-line free-text reason field that the operator fills in if the load was outside the normal scheduled changeover. The audit log lives in a tamper-evident store — typically a database with append-only permissions, or a file with cryptographic signing — and the controls engineer never touches it after the fact. Tampering is what the regulator is actually testing for; the engineer who can prove that the audit log has not been edited is the engineer who passes audit.

The third pillar is data integrity on the recipe storage itself. Recipe parameters held in retentive PLC memory survive a power cycle, which is good for production, but they are also vulnerable to memory corruption (a bad battery on the older platforms, a wear-out on the newer flash-based retentive memory, a wild pointer in a maintenance program). A recipe with a corrupted parameter — fill volume now reads 99999 ml instead of 1000 ml — will run the line into a fault as soon as it is loaded, but only if the program checks for sane values before applying them. The discipline is to compute a CRC over each recipe at write time, store it alongside the recipe, and verify it on every load. A failed CRC means the load is rejected and the operator gets an alarm; a passed CRC means the recipe is intact and the load proceeds.

Worked example

Open the simulator. Drop a CompactLogix CPU on the rack with the bottling-line scenario loaded. The line has three product SKUs — SMALL (250 ml), MEDIUM (500 ml), LARGE (1 L) — and twelve parameters per product. The parameters are: fill volume (ml), fill rate (ml/s), cap torque (N·m), label height (mm above bottle base), conveyor speed (m/min), filler dwell time (s), capper dwell time (s), labeller dwell time (s), reject reject (boolean — pull bottles failing in-line check), CIP cycle override (boolean), bottle-detect debounce (ms), and operator-set fill tolerance (ml plus or minus).

The runtime parameter block — the UDT that the program actually reads from on every scan — is held at a single tag named RECIPE_RUN. The recipe library sits in an array RECIPE_LIB[1..3], one element per product, each element a copy of the same UDT. Loading a recipe is a single FB call that copies RECIPE_LIB[selected] into RECIPE_RUN, verifies the CRC, writes the audit-log entry, and signals the operator that the load completed. The Structured Text for the load FB looks like this:

(* Recipe load FB — bottling line, three SKUs, ISA-88 style       *)
(* Inputs:  RECIPE_ID (1..3), OPERATOR (string), BATCH (string)   *)
(* Outputs: LOAD_OK, LOAD_FAULT, AUDIT_ROW (string for log)       *)

FUNCTION_BLOCK FB_RecipeLoad
VAR_INPUT
    LOAD_REQ    : BOOL;
    RECIPE_ID   : INT;
    OPERATOR    : STRING[16];
    BATCH       : STRING[16];
END_VAR
VAR_OUTPUT
    LOAD_OK     : BOOL;
    LOAD_FAULT  : BOOL;
    AUDIT_ROW   : STRING[120];
END_VAR
VAR
    crc_expected : DWORD;
    crc_actual   : DWORD;
    ts           : DT;
END_VAR

IF R_TRIG(LOAD_REQ) AND PLANT_RUN_PERMIT THEN
    IF RECIPE_ID < 1 OR RECIPE_ID > 3 THEN
        LOAD_FAULT := TRUE;
        AUDIT_ROW  := CONCAT('REJECT bad RECIPE_ID by ', OPERATOR);
    ELSE
        crc_expected := RECIPE_LIB[RECIPE_ID].CRC;
        crc_actual   := CRC32_OF(RECIPE_LIB[RECIPE_ID]);
        IF crc_actual <> crc_expected THEN
            LOAD_FAULT := TRUE;
            AUDIT_ROW  := CONCAT('REJECT CRC fail batch ', BATCH);
        ELSE
            RECIPE_RUN := RECIPE_LIB[RECIPE_ID];
            ts         := CURRENT_DATETIME();
            LOAD_OK    := TRUE;
            AUDIT_ROW  := DT_TO_STR(ts) +
                          ' Operator ' + OPERATOR +
                          ' loaded recipe ' + RECIPE_LIB[RECIPE_ID].NAME +
                          ' for batch ' + BATCH;
        END_IF;
    END_IF;
END_IF;
END_FUNCTION_BLOCK

A typical audit-log row written by this FB on a real run looks like this:

2026-06-10T14:23:01 Operator JSmith loaded recipe LARGE for batch 260610-B-013

That single row, written to a tamper-evident database table, is the answer to the regulator's question "what recipe ran in batch 260610-B-013, and who authorised it". The row is generated automatically on every recipe load; the operator does nothing extra; the engineer does not touch the log after the event.

The changeover-time win is measurable on the simulator. The "manual" baseline — operator opens the HMI parameter screen, types twelve values, double-checks each one, presses commit — takes between 18 and 25 minutes on the simulator's stopwatch panel, with about 22 minutes the median. The "recipe load" alternative — operator selects LARGE from a dropdown, presses load, the FB validates the CRC and copies the parameters in under 100 ms, the audit-log row is written, the line is ready to run — takes 90 seconds end-to-end including the operator's confirmation dialogue. The 22-minute to 90-second improvement, multiplied by four changeovers per shift, gives back about 80 minutes of production time per shift on this line.

Common mistakes

  • Allowing recipe edits in run mode. A recipe library that is writable while the program is running is a recipe library that an operator will modify at 2 AM when the line is misbehaving and no engineer is on site. The next batch runs against the modified recipe, the QC tech finds the misruns, and nobody can reconstruct what was changed. Always lock the recipe library writable only in maintenance mode, with a separate role permission, and treat every edit as a change-control event with a recorded reason.

  • No audit log of recipe loads — compliance failure on regulated product. A recipe management system that does not log every load is a system that cannot answer "what was loaded into batch X". On regulated product (pharma, food, beverage exported to regulated markets) that gap is a finding on the next audit. Always write a structured audit row on every load — timestamp, operator, recipe ID, batch ID — to a tamper-evident store, and never let the controls program have write access to the log after the row is written.

  • Recipe parameters held in retentive memory without CRC check. Retentive memory is good — the recipes survive a power cycle. But corrupted retentive memory is silent — the parameters look fine to a casual inspection and produce nonsense at runtime. Always compute a CRC32 (or stronger) over each recipe at write time, store the CRC alongside, and verify on every load. A failed CRC rejects the load and alarms the operator; the recipe is restored from a known-good backup before production resumes.

  • Recipe ID not stored alongside batch data. A line that records the batch number into its production database but does not record the recipe ID that was loaded for that batch is a line that cannot reconstruct what was made. The audit log knows what was loaded; the production database knows the batch number; if the two are not joined by recipe ID, the trail breaks. Always include the active recipe ID as a column in every batch-level production record, populated at batch start from the most recent successful recipe load.

  • One recipe per HMI screen. A common antipattern is to give every product its own custom HMI screen with hard-coded labels and parameter limits. That works for three products and breaks at the fourth, because the engineering work to add a new SKU now includes editing the HMI. Always use one HMI screen for parameter display, with the labels and limits driven from the recipe parameter block — adding a new SKU is then a recipe-library edit, not a HMI redesign.

  • Treating recipe management as a feature, not a discipline. Recipe management is not a button on the HMI; it is a contract between the production team, the QC team, the engineering team, and the regulator. The button is the easy part. The discipline — version control on the recipe library, change control on edits, role-based access on writes, audit log on loads, CRC verification on every read — is the part that takes a project to set up and a process to keep alive. Always treat it as the second category, not the first.

How to practise this in the simulator

The simulator's bottling-line scenario ships with the three-SKU recipe library, the runtime parameter block, the recipe-load FB, and a built-in audit-log viewer that shows every load event with timestamp, operator, recipe, and batch. Open the scenario, switch to operator role, load a recipe, and watch the audit row appear. Switch to engineer role and try to edit the recipe library while the line is running — the simulator will block you with the same role-permission alarm a real platform would raise. Inject a CRC corruption on one of the recipes (the simulator has a fault-injection panel for retentive memory) and try to load it; the FB rejects the load and writes the rejection event to the audit log. Twenty minutes on the scenario teaches the difference between a recipe button and a recipe management system.

Start the free tier →

Vendor reference

The cross-vendor reference for recipe management on regulated batch processes is the Wikipedia: ANSI/ISA-88 article, which summarises the ISA-88 batch control standard's separation of recipe, equipment, and procedure, and links to the ISA-88 standards committee on isa.org for the canonical document. The Siemens Batch / SIMATIC PCS 7 documentation and the Rockwell FactoryTalk Batch documentation both implement the ISA-88 model in their batch products; reading either before designing your own recipe library saves a significant amount of avoidable rework. On a smaller line where a full batch product is overkill, the recipe-load FB pattern shown above — runtime parameter block, recipe library array, audited load operation — implements the same separation in a lightweight form.

What we don't claim

This site is not SAQA-registered, not MerSETA-accredited, and not an NQF-registered qualification provider. Our completion certificates are course-level only — they describe what you covered, not an NQF Level X qualification. The CCST cert from ISA is the portable industry credential we recommend; we are not an ISA cert delivery partner either, but our cert packs are CCST-aligned. Recipe management on a regulated product line is a discipline that touches QC, engineering, and the regulator — the simulator gives you the implementation patterns, but the validated change-control process for your real plant still needs the QC team and the responsible person on site.

By PLC Programming SA · Last updated 2026-06-10