163 lines
7.1 KiB
C++
163 lines
7.1 KiB
C++
/**
|
||
* @file PulseGeneratorGAM.h
|
||
* @brief GAM that synthesizes a triggered high-voltage pulse waveform.
|
||
* @date 29/08/2026
|
||
* @author Martino Ferrari
|
||
*
|
||
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
|
||
* the Development of Fusion Energy ('Fusion for Energy').
|
||
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
|
||
* by the European Commission - subsequent versions of the EUPL (the "Licence")
|
||
* You may not use this work except in compliance with the Licence.
|
||
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
|
||
*
|
||
* @warning Unless required by applicable law or agreed to in writing,
|
||
* software distributed under the Licence is distributed on an "AS IS"
|
||
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||
* or implied. See the Licence permissions and limitations under the Licence.
|
||
*
|
||
* @details Emulates a charged-capacitor pulse discharge on a high-voltage bus:
|
||
*
|
||
* - on a rising edge of the (optional) Trigger input — the EPICS "start"
|
||
* setpoint — the output ramps linearly from its current level to HighLevel
|
||
* over RampUpMs (default 1 ms, the charger ramp);
|
||
* - it then holds HighLevel flat for PlateauMs — read from the (optional)
|
||
* PlateauMs input at trigger time, i.e. the EPICS "duration" setpoint;
|
||
* - finally it ramps back to 0 over RampDownMs (default 100 ms, the
|
||
* capacitive discharge);
|
||
* - until the next trigger the output sits at 0 (the "off" phase).
|
||
*
|
||
* Gaussian noise (NoiseStdDev, default 333.33 V → 3σ ≈ ±1000 V) is added to
|
||
* every sample, and random EMI spikes of ±EMIAmplitude (default 5000 V,
|
||
* probability EMIProbabilityPerSample per sample, EMISpikeSamples long) strike
|
||
* during both the on and off phases.
|
||
*
|
||
* With no Trigger input connected, AutoTriggerPeriodMs > 0 self-triggers the
|
||
* sequence periodically so the GAM runs standalone.
|
||
*
|
||
* Configuration:
|
||
* <pre>
|
||
* +MyGAM = {
|
||
* Class = PulseGeneratorGAM
|
||
* SamplingRate = 1000000.0 // must match the output signal rate
|
||
* RampUpMs = 1.0
|
||
* RampDownMs = 100.0
|
||
* HighLevel = -40000.0
|
||
* NoiseStdDev = 333.33
|
||
* EMIAmplitude = 5000.0
|
||
* EMIProbabilityPerSample = 0.00001
|
||
* EMISpikeSamples = 5
|
||
* PlateauMsDefault = 500.0 // used when PlateauMs input absent
|
||
* AutoTriggerPeriodMs = 0.0 // 0 = external trigger only
|
||
* Seed = 0 // PRNG seed; 0 = from wall clock
|
||
* InputSignals = { // optional: 0, 1 or 2 inputs
|
||
* Trigger = { DataSource = DDB; Type = float32 }
|
||
* PlateauMs = { DataSource = DDB; Type = float32 }
|
||
* }
|
||
* OutputSignals = {
|
||
* HV = { DataSource = DDB; Type = float32; NumberOfElements = 1000 }
|
||
* }
|
||
* }
|
||
* </pre>
|
||
*/
|
||
|
||
#ifndef PULSEGENERATORGAM_H_
|
||
#define PULSEGENERATORGAM_H_
|
||
|
||
/*---------------------------------------------------------------------------*/
|
||
/* Standard header includes */
|
||
/*---------------------------------------------------------------------------*/
|
||
|
||
/*---------------------------------------------------------------------------*/
|
||
/* Project header includes */
|
||
/*---------------------------------------------------------------------------*/
|
||
#include "CompilerTypes.h"
|
||
#include "GAM.h"
|
||
|
||
/*---------------------------------------------------------------------------*/
|
||
/* Class declaration */
|
||
/*---------------------------------------------------------------------------*/
|
||
|
||
namespace MARTe {
|
||
|
||
class PulseGeneratorGAM : public GAM {
|
||
public:
|
||
CLASS_REGISTER_DECLARATION()
|
||
|
||
/**
|
||
* @brief Constructor. Sets safe defaults.
|
||
*/
|
||
PulseGeneratorGAM();
|
||
|
||
/**
|
||
* @brief Destructor.
|
||
*/
|
||
virtual ~PulseGeneratorGAM();
|
||
|
||
/**
|
||
* @brief Reads the waveform parameters from config and seeds the PRNG.
|
||
*/
|
||
virtual bool Initialise(StructuredDataI &data);
|
||
|
||
/**
|
||
* @brief Resolves the output array and the optional input scalars.
|
||
* @return true if exactly one float32 output signal and at most two inputs.
|
||
*/
|
||
virtual bool Setup();
|
||
|
||
/**
|
||
* @brief Emits the next block of waveform samples (noise + EMI included).
|
||
* @return true always.
|
||
*/
|
||
virtual bool Execute();
|
||
|
||
private:
|
||
/** @brief Pulse state machine phases. */
|
||
typedef enum {
|
||
PulsePhaseOff = 0u, /**< Output at 0 V, waiting for a trigger */
|
||
PulsePhaseRampUp = 1u, /**< Charger ramp: startLevel → HighLevel */
|
||
PulsePhaseFlat = 2u, /**< Holding HighLevel for the plateau */
|
||
PulsePhaseRampDown = 3u /**< Discharge ramp: HighLevel → 0 */
|
||
} PulsePhase;
|
||
|
||
float64 samplingRate; /**< Sample rate [Hz] */
|
||
float64 rampUpMs; /**< Charger ramp duration [ms] */
|
||
float64 rampDownMs; /**< Discharge ramp duration [ms] */
|
||
float64 highLevel; /**< Plateau level [V] */
|
||
float64 noiseStdDev; /**< Gaussian noise sigma [V] */
|
||
float64 emiAmplitude; /**< EMI spike amplitude [V] */
|
||
float64 emiProbabilityPerSample; /**< Probability of starting an EMI spike per sample */
|
||
uint32 emiSpikeSamples; /**< Length of one EMI spike [samples] */
|
||
float64 plateauMsDefault; /**< Plateau used when the PlateauMs input is absent [ms] */
|
||
float64 autoTriggerPeriodMs; /**< Self-trigger period [ms]; 0 = external only */
|
||
uint32 seed; /**< PRNG seed; 0 = wall clock */
|
||
|
||
uint32 nElements; /**< Output samples per Execute() call */
|
||
float32 *outputBuf; /**< Output waveform memory */
|
||
float32 *triggerIn; /**< Optional rising-edge trigger input */
|
||
float32 *plateauMsIn; /**< Optional plateau-duration input [ms] */
|
||
|
||
PulsePhase phase; /**< Current state machine phase */
|
||
float64 startLevel; /**< Waveform level when the current ramp started */
|
||
float64 currentLevel; /**< Clean (pre-noise) level of the last emitted sample */
|
||
uint64 phaseElapsed; /**< Samples consumed in the current phase */
|
||
uint64 phaseTotal; /**< Total samples of the current phase */
|
||
uint64 rampUpSamples; /**< RampUpMs expressed in samples */
|
||
uint64 rampDownSamples; /**< RampDownMs expressed in samples */
|
||
uint64 plateauSamples; /**< Plateau for the current pulse [samples] */
|
||
float64 prevTrigger; /**< Previous Trigger input value (edge detection) */
|
||
uint64 samplesSinceTrigger; /**< Samples since the last trigger (auto-trigger) */
|
||
uint32 spikeRemaining; /**< Samples left in the current EMI spike */
|
||
float64 spikeValue; /**< Signed amplitude of the current EMI spike */
|
||
|
||
/** @brief Starts a new pulse: ramp up from the current level. */
|
||
void StartSequence(float64 plateauMs);
|
||
|
||
/** @brief Advances to the next phase, skipping zero-length ones. */
|
||
void AdvanceToNextPhase();
|
||
};
|
||
|
||
} /* namespace MARTe */
|
||
|
||
#endif /* PULSEGENERATORGAM_H_ */
|