Index: trunk/ppSim/src/Makefile.am
===================================================================
--- trunk/ppSim/src/Makefile.am	(revision 15005)
+++ trunk/ppSim/src/Makefile.am	(revision 15482)
@@ -23,5 +23,6 @@
 	ppSimSetPSF.c           \
 	ppSimUtils.c            \
-	ppSimLoop.c
+	ppSimLoop.c		\
+	ppSimBadPixels.c
 
 noinst_HEADERS = \
Index: trunk/ppSim/src/ppSim.h
===================================================================
--- trunk/ppSim/src/ppSim.h	(revision 15005)
+++ trunk/ppSim/src/ppSim.h	(revision 15482)
@@ -125,3 +125,10 @@
 bool ppSimInsertGalaxies (pmReadout *readout, psImage *expCorr, psArray *galaxies, pmConfig *config);
 
+/// Add bad pixels to an image
+bool ppSimBadPixels(pmReadout *readout, ///< Readout for which to generate bad pixels
+                    const pmConfig *config, ///< Configuration
+                    psRandom *rng       ///< Random number generator
+    );
+
+
 #endif
Index: trunk/ppSim/src/ppSimBadPixels.c
===================================================================
--- trunk/ppSim/src/ppSimBadPixels.c	(revision 15482)
+++ trunk/ppSim/src/ppSimBadPixels.c	(revision 15482)
@@ -0,0 +1,74 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppSim.h"
+
+
+// The idea is that the pattern should be completely *deterministic* (despite the use of 'random' numbers ---
+// with the seed specified, they should be deterministic) so that multiple calls of this function will result
+// in the same pattern.  These are set to (really) random values so that they do not dark-subtract or
+// flat-field.
+
+bool ppSimBadPixels(pmReadout *readout, const pmConfig *config, psRandom *rng)
+{
+    PS_ASSERT_PTR_NON_NULL(readout, false);
+    PS_ASSERT_IMAGE_NON_NULL(readout->image, false);
+    PS_ASSERT_PTR_NON_NULL(readout->parent, false);
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    bool mdok;                          // Status of MD lookup
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSIM_RECIPE); // Recipe
+    if (!recipe) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSIM_RECIPE);
+        return false;
+    }
+
+    psU64 seed = psMetadataLookupU64(&mdok, recipe, "BADPIX.SEED"); // Seed for RNG
+    if (seed == 0 || !mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "BADPIX.SEED not set, or zero.");
+        return false;
+    }
+
+    float frac = psMetadataLookupF32(&mdok, recipe, "BADPIX.FRAC"); // Fraction of bad pixels
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "BADPIX.FRAC not set.");
+        return false;
+    }
+    if (frac == 0.0) {
+        // Nothing to do
+        return true;
+    }
+
+    float saturation = psMetadataLookupF32(NULL, readout->parent->concepts, "CELL.SATURATION");
+    if (isnan(saturation)) {
+        psWarning("CELL.SATURATION is not set; reverting to recipe value SATURATION.");
+        saturation = psMetadataLookupF32(&mdok, recipe, "SATURATION");
+        if (!mdok) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find SATURATION in recipe.");
+            return false;
+        }
+    }
+
+    psRandom *pseudoRNG = psRandomAlloc(PS_RANDOM_TAUS, seed); // Pseudo-random number generator
+
+    psImage *image = readout->image;    // Image of interest
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+
+    for (int y = 0; y < numRows; y++) {
+        for (int x = 0; x < numCols; x++) {
+            if (psRandomUniform(pseudoRNG) < frac) {
+                image->data.F32[y][x] = psRandomUniform(rng) * saturation;
+            }
+        }
+    }
+
+    psFree(pseudoRNG);
+
+    return true;
+}
Index: trunk/ppSim/src/ppSimLoop.c
===================================================================
--- trunk/ppSim/src/ppSimLoop.c	(revision 15005)
+++ trunk/ppSim/src/ppSimLoop.c	(revision 15482)
@@ -140,4 +140,6 @@
                 ppSimSaturate(readout, config);
 
+                ppSimBadPixels(readout, config, rng);
+
                 ppSimAddOverscan (readout, config, biasCols, biasRows, rng);
                 psFree(biasRows);
