/********************************************************************\ HVFeedback.cc Class handling the feedback of GAPD high voltage Oliver Grimm \********************************************************************/ #include "HVFeedback.h" #include "PixelMap.h" #define PIXMAP_LOCATION "../config/PixelMap.txt" static const char* FBState_Description[] = { "Feedback off", "Feedback active", "Feedback acquiring new targets", "Feedback measuring response with first voltage", "Feedback measuring response with second voltage" }; // // Constructor: Initialise feedback // HVFeedback::HVFeedback(DAQReadout* DAQClass, char* Configfile): EvidenceServer(SERVER_NAME){ m = DAQClass; fNumberOfChannels = m->fNumberOfChannels; fNumberOfChips = m->fNumberOfChips; PixMap = new PixelMap(PIXMAP_LOCATION, false); // Initialise with zero content Average = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); Sigma = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); Response = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); Target = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); Buffer = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); DIMAverage = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); DIMSigma = new float [m->NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax](); // Read configuration file FILE *File; if ((File = fopen(Configfile,"r")) == NULL) { printf("Error: Could not open feedback configuration file '%s'\n", Configfile); } else { printf("Reading feedback configuration file %s\n", Configfile); ReadCard("TrigBoard", &fLedTrigBoard, 'I', File); ReadCard("TrigChannel", &fLedTrigChannel, 'I', File); ReadCard("TrigChip", &fLedTrigChip, 'I', File); ReadCard("TrigSample", &fLedTrigSample, 'I', File); ReadCard("TrigThreshold", &fLedTrigThreshold, 'f', File); ReadCard("SignalSample", &fLedSignalSample, 'I', File); ReadCard("BaselineSample", &fLedBaselineSample, 'I', File); ReadCard("IntHalfWidth", &fIntHalfWidth, 'U', File); ReadCard("DefaultNumAverage", &fDefaultNumAverage, 'I', File); ReadCard("DefaultResponse", Response, 'f', File, m->NumBoards*fNumberOfChips*fNumberOfChannels); ReadCard("DefaultTarget", Target, 'f', File, m->NumBoards*fNumberOfChips*fNumberOfChannels); // Add also initial gain to configuration parameters fclose(File); } PrintConfig(MsgToLog); // Provide DIM services FeedbackAverage = new DimService (SERVER_NAME"/Average", "F", DIMAverage, m->NumBoards*kNumberOfChipsMax*kNumberOfChannelsMax*sizeof(float)); FeedbackSigma = new DimService (SERVER_NAME"/Sigma", "F", DIMSigma, m->NumBoards*kNumberOfChipsMax*kNumberOfChannelsMax*sizeof(float)); FeedbackResponse = new DimService (SERVER_NAME"/Response", "F", Response, m->NumBoards*kNumberOfChipsMax*kNumberOfChannelsMax*sizeof(float)); FeedbackTarget = new DimService (SERVER_NAME"/Target", "F", Target, m->NumBoards*kNumberOfChipsMax*kNumberOfChannelsMax*sizeof(float)); CountService = new DimService (SERVER_NAME"/Count", Count); // Initial state Gain = 0.2; SetFBMode(FB_Off); SetNumAverages(fDefaultNumAverage); LastServiceUpdate = 0; } // // Destructor // HVFeedback::~HVFeedback() { delete CountService; delete FeedbackAverage; delete FeedbackSigma; delete FeedbackResponse; delete FeedbackTarget; delete[] Average; delete[] Response; delete[] Target; delete[] Buffer; delete PixMap; } // // Check if LED trigger present, if yes accumulate feedback data and // calculate new high voltages if the required number of events is reached. // bool HVFeedback::ProcessEvent() { int i,j,k,q; float Correction, Integral; // Check for LED trigger channel on given channel and if feedback running if (FBMode==FB_Off || m->WaveForm[fLedTrigBoard][fLedTrigChip][fLedTrigChannel][(fLedTrigSample+m->TriggerCell[fLedTrigBoard][fLedTrigChip])%kNumberOfBins] < fLedTrigThreshold) { return false; } // Calculate average signal of LED pulse as integral of signal for (i=m->FirstBoard; i<=m->LastBoard; i++) { for (j=0; jWaveForm[i][j][k][(fLedSignalSample+q+m->TriggerCell[i][j])%kNumberOfBins] - m->WaveForm[i][j][k][(fLedBaselineSample+q+m->TriggerCell[i][j])%kNumberOfBins])*m->GetBoard(i)->GetPrecision(); } Integral /= 2*fIntHalfWidth+1; Average[i][j][k] += Integral; Sigma[i][j][k] += pow(Integral,2); } } } // Update DIM service regularly if (time(NULL)-LastServiceUpdate > 2) { LastServiceUpdate = time(NULL); CountService->updateService(); } // Check if acquired number of event requires action if (++CountFirstBoard; i<=m->LastBoard; i++) { for (j=0; j 0.1) Correction = fabs(Correction)/Correction*0.1; // Limit changes to 100 mV if(Correction==0 || Target[i][j][k] ==0 || PixMap->DRS_to_Pixel(i,j,k).empty()) break; printf("Average of board %d, chip %d, channel %d is %.2f +/- %.2f Correction %.3f\n",i,j,k,Average[i][j][k],Sigma[i][j][k],Correction); if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n"); else WriteHVCommand("hv %s %+f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), Correction); break; case FB_Targets: // Take average as new targets Target[i][j][k] = Average[i][j][k]; break; case FB_ResponseFirst: // First point of response measurement done Buffer[i][j][k] = Average[i][j][k]; if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hv %s %+f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage); break; case FB_ResponseSecond: // Determine response from signal variation if(Buffer[i][j][k] == Average[i][j][k]) { m->PrintMessage("HV Feedback: Warning, response singular for board %d, chip %d, channel %d.\n",i,j,k); Response[i][j][k] = 0; } else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]); if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hv %s %+f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2); break; default: break; // to suppress warning abount not handled enumeration value } } // for() channels } // for() chips } // for() boards // Update DIM service FeedbackAverage->updateService(); FeedbackSigma->updateService(); switch (FBMode) { case FB_Targets: FeedbackTarget->updateService(); m->PrintMessage("HV Feedback: New targets set, switching off.\n"); SetFBMode(FB_Off, true); break; case FB_ResponseFirst: SetFBMode(FB_ResponseSecond, true); m->PrintMessage("HV Feedback: Increasing voltages by %f for response measurement, acquiring data.\n", DiffVoltage); break; case FB_ResponseSecond: FeedbackResponse->updateService(); m->PrintMessage("HV Feedback: Response measurements finished, original voltages set, switching off.\n"); SetFBMode(FB_Off, true); break; default: break; // to suppress warning abount not handled enumeration value } ClearAverages(); return true; } // // Clear average values and event counter // void HVFeedback::ClearAverages() { for (int i=m->FirstBoard; i<=m->LastBoard; i++) for (int j=0; jupdateService(); } // // Number of events to accumulate before correction acts // void HVFeedback::SetNumAverages(unsigned int Averages) { NumAverages = Averages; } // // Get requested number of events // unsigned int HVFeedback::GetNumAverages() { return NumAverages; } // // Set feedback gain // void HVFeedback::SetGain(float FBGain) { Gain = FBGain; } // // Get feedback gain // float HVFeedback::GetGain() { return Gain; } // // Set feedback mode and clear averages // void HVFeedback::SetFBMode(FBState Mode, bool Internal) { if((Mode==FB_ResponseFirst || Mode==FB_ResponseFirst) && !Internal) m->PrintMessage("Start reponse measurement by calling MeasureResponse().\n"); else { FBMode = Mode; if (Mode != FB_ResponseFirst) State(INFO, "%s", FBState_Description[FBMode]); else State(INFO, "%s (voltage difference %.3f)", FBState_Description[FBMode], DiffVoltage); ClearAverages(); } } // // Get feedback mode // FBState HVFeedback::GetFBMode() { m->PrintMessage("%s.\n", FBState_Description[FBMode]); return FBMode; } // // Return current number of events // unsigned int HVFeedback::GetCurrentCount() { return Count; } // // Set target values // void HVFeedback::SetTarget(int Board, int Chip, int Channel, float TargetVal) { if(BoardNumBoards && ChipupdateService(); } else printf("Invalid board, chip or channel number.\n"); } // // Print target values // void HVFeedback::GetTargets() { for (int i=m->FirstBoard; i<=m->LastBoard; i++) for (int j=0; jPrintMessage("Board %d, chip %d:",i,j); for (int k=0; kPrintMessage(" %.2f",Target[i][j][k]); m->PrintMessage("\n\r"); } } // // Measure response matrix // void HVFeedback::MeasureResponse(float U) { if (U==0) { m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n"); return; } for (int i=m->FirstBoard; i<=m->LastBoard; i++) for (int j=0; jDRS_to_Pixel(i,j,k).empty()) { WriteHVCommand("hv %s %+f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2); } } DiffVoltage = U; SetFBMode(FB_ResponseFirst, true); m->PrintMessage("HV Feedback: Decreasing voltages by %f for response measurement, acquiring data.\n",DiffVoltage/2); } // // Print response values // void HVFeedback::GetResponse() { for (int i=m->FirstBoard; i<=m->LastBoard; i++) { for (int j=0; jPrintMessage("Board %d, chip %d:",i,j); for (int k=0; kPrintMessage(" %.3f",Response[i][j][k]); m->PrintMessage("\n\r"); } } } // // Write bias voltage commmand // bool HVFeedback::WriteHVCommand(const char *Format, ...) { char Textbuffer[MAX_COM_SIZE]; va_list ArgumentPointer; va_start(ArgumentPointer, Format); vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer); DimClient::sendCommand("Bias/Command", Textbuffer); return true; } // // Print feedback configuration // void HVFeedback::PrintConfig(int Target) { m->PrintMessage(Target, "LedTrigBoard: %d\t\tLedTrigChip: %d\t\tLedTrigChannel: %d\n" "LedTrigSample: %d\tLedTrigThreshold: %.2f\n" "LedSignalSample: %d\tLedBaselineSample: %d\tDefaultNumAverage: %d\n" "IntHalfWidth:%u\n", fLedTrigBoard, fLedTrigChip, fLedTrigChannel, fLedTrigSample, fLedTrigThreshold, fLedSignalSample, fLedBaselineSample, fDefaultNumAverage, fIntHalfWidth); }