// This function gates the detector data first, and then demodulates the channels. // This means that it can give innacurate results for non-linear combinations // of channels that vary appreciably over the TOF. There's another, slower, function // DemodulateBlockNL that takes care of this. public DemodulatedBlock DemodulateBlock(Block b, DemodulationConfig config) { // *** copy across the metadata *** DemodulatedBlock db = new DemodulatedBlock(); db.TimeStamp = b.TimeStamp; db.Config = b.Config; db.DemodulationConfig = config; // *** extract the gated detector data using the given config *** List <GatedDetectorData> gatedDetectorData = new List <GatedDetectorData>(); int ind = 0; foreach (string d in b.detectors) { GatedDetectorExtractSpec gdes; config.GatedDetectorExtractSpecs.TryGetValue(d, out gdes); if (gdes != null) { gatedDetectorData.Add(GatedDetectorData.ExtractFromBlock(b, gdes)); db.DetectorIndices.Add(gdes.Name, ind); ind++; db.DetectorCalibrations.Add(gdes.Name, ((TOF)((EDMPoint)b.Points[0]).Shot.TOFs[gdes.Index]).Calibration); } } //foreach (KeyValuePair<string, GatedDetectorExtractSpec> spec in config.GatedDetectorExtractSpecs) //{ // GatedDetectorExtractSpec gate = spec.Value; // gatedDetectorData.Add(GatedDetectorData.ExtractFromBlock(b, gate)); // db.DetectorIndices.Add(gate.Name, ind); // ind++; // db.DetectorCalibrations.Add(gate.Name, // ((TOF)((EDMPoint)b.Points[0]).Shot.TOFs[gate.Index]).Calibration); //} // ** normalise the top detector ** gatedDetectorData.Add( gatedDetectorData[db.DetectorIndices["top"]] / gatedDetectorData[db.DetectorIndices["norm"]]); db.DetectorIndices.Add("topNormed", db.DetectorIndices.Count); // *** extract the point detector data *** List <PointDetectorData> pointDetectorData = new List <PointDetectorData>(); foreach (string channel in config.PointDetectorChannels) { pointDetectorData.Add(PointDetectorData.ExtractFromBlock(b, channel)); // for the moment all single point detector channels are set to have a calibration // of 1.0 . db.DetectorCalibrations.Add(channel, 1.0); } // *** build the list of detector data *** List <DetectorData> detectorData = new List <DetectorData>(); for (int i = 0; i < gatedDetectorData.Count; i++) { detectorData.Add(gatedDetectorData[i]); } for (int i = 0; i < config.PointDetectorChannels.Count; i++) { detectorData.Add(pointDetectorData[i]); db.DetectorIndices.Add(config.PointDetectorChannels[i], i + gatedDetectorData.Count); } // calculate the norm FFT db.NormFourier = DetectorFT.MakeFT(gatedDetectorData[db.DetectorIndices["norm"]], kFourierAverage); // *** demodulate channels *** // ** build the list of modulations ** List <string> modNames = new List <string>(); List <Waveform> modWaveforms = new List <Waveform>(); foreach (AnalogModulation mod in b.Config.AnalogModulations) { modNames.Add(mod.Name); modWaveforms.Add(mod.Waveform); } foreach (DigitalModulation mod in b.Config.DigitalModulations) { modNames.Add(mod.Name); modWaveforms.Add(mod.Waveform); } foreach (TimingModulation mod in b.Config.TimingModulations) { modNames.Add(mod.Name); modWaveforms.Add(mod.Waveform); } // ** work out the switch state for each point ** int blockLength = modWaveforms[0].Length; List <bool[]> wfBits = new List <bool[]>(); foreach (Waveform wf in modWaveforms) { wfBits.Add(wf.Bits); } List <uint> switchStates = new List <uint>(blockLength); for (int i = 0; i < blockLength; i++) { uint switchState = 0; for (int j = 0; j < wfBits.Count; j++) { if (wfBits[j][i]) { switchState += (uint)Math.Pow(2, j); } } switchStates.Add(switchState); } // pre-calculate the state signs for each analysis channel // the first index selects the analysis channel, the second the switchState int numStates = (int)Math.Pow(2, modWaveforms.Count); int[,] stateSigns = new int[numStates, numStates]; for (uint i = 0; i < numStates; i++) { for (uint j = 0; j < numStates; j++) { stateSigns[i, j] = stateSign(j, i); } } // ** the following needs to be done for each detector ** for (int detector = 0; detector < detectorData.Count; detector++) { DetectorChannelValues dcv = new DetectorChannelValues(); for (int i = 0; i < modNames.Count; i++) { dcv.SwitchMasks.Add(modNames[i], (uint)(1 << i)); } // * divide the data up into bins according to switch state * List <List <double> > statePoints = new List <List <double> >(numStates); for (int i = 0; i < numStates; i++) { statePoints.Add(new List <double>(blockLength / numStates)); } for (int i = 0; i < blockLength; i++) { statePoints[(int)switchStates[i]].Add(detectorData[detector].PointValues[i]); } // * calculate the channel values * int subLength = blockLength / numStates; double[,] channelValues = new double[numStates, subLength]; for (int channel = 0; channel < numStates; channel++) { for (int subIndex = 0; subIndex < subLength; subIndex++) { double chanVal = 0; for (int i = 0; i < numStates; i++) { chanVal += stateSigns[channel, i] * statePoints[i][subIndex]; } chanVal /= (double)numStates; channelValues[channel, subIndex] = chanVal; } } //* calculate the channel means * double[] channelMeans = new double[numStates]; for (int channel = 0; channel < numStates; channel++) { double total = 0; for (int i = 0; i < subLength; i++) { total += channelValues[channel, i]; } total /= blockLength / numStates; channelMeans[channel] = total; } dcv.Values = channelMeans; //* calculate the channel errors * double[] channelErrors = new double[numStates]; for (int channel = 0; channel < numStates; channel++) { double total = 0; for (int i = 0; i < subLength; i++) { total += Math.Pow(channelValues[channel, i] - channelMeans[channel], 2); } total /= subLength * (subLength - 1); total = Math.Sqrt(total); channelErrors[channel] = total; } dcv.Errors = channelErrors; db.ChannelValues.Add(dcv); } return(db); }