![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
baseline build
Dependencies: FastPWM mbed-os mbed
PowerController.cpp
- Committer:
- jrhodes5150
- Date:
- 2017-06-19
- Revision:
- 0:8a420ac6394e
File content as of revision 0:8a420ac6394e:
#include "mbed.h" #include "PowerController.h" #include "MillisecondCounter.h" #include "CMSerial.h" #include "math.h" #include "DebugPort.h" DebugPort pc; PowerController::PowerController(void) : led3(LED3), led4(LED4), ADC(), acquisitionTimer(this, &PowerController::AcquireData), pidTimer(this, &PowerController::ProcessPID) { thread.start(this, &PowerController::ThreadEntry); } void PowerController::ThreadEntry(void) { ioControl.Activate(); ioControl.Deactivate(); for(;;) { led3 = (GetTime_ms() / 1000) & 1; Device.deviceConfig.voltageSensed = 0.0; Device.deviceConfig.currentSensed = 0.0; Device.deviceConfig.sensedResistance = 0.0; Device.deviceConfig.sensedPower = 0.0; // Wait for an activation if( ioControl.isActivateSwitchOn() && ioControl.hasFalling()) { Device.deviceConfig.doneBit = 0; // Start acquiring data myTime = GetTime_ms(); loopTimer = 0; Device.ClearAcquisitionData(); switch (Device.deviceConfig.outputMode) { case OMRamp: ExecuteRamp(); break; case OMConstantVoltage: ExecuteConstantVoltage(); break; case OMConstantPower: ExecuteConstantPower(); break; case OMCalibrate: Calibrate(); break; default: break; } Device.deviceConfig.doneBit = 1; ioControl.SetOutputVoltage(0); ioControl.Deactivate(); led4 = 0; // pause to get a couple more samples rtos::Thread::wait(Device.deviceConfig.msSamplePeriod * 2); acquisitionTimer.stop(); } // let others run rtos::Thread::wait(1); } } void PowerController::ExecuteRamp(void) { // Set initial output voltage. ioControl.SetOutputVoltage(Device.deviceConfig.startVoltage); ioControl.SetPWMFrequency(Device.deviceConfig.pwmFrequency); loopTimer = 0; double resistance; unsigned powerStartTime = GetTime_ms(); led4 = 1; if(Device.deviceConfig.msOpenLoopDuration > 0) { // Begin activation pid.SetTarget(Device.deviceConfig.startVoltage); // used to put the voltage into the Acquisition Data // Start acquiring data acquisitionTimer.start(Device.deviceConfig.msSamplePeriod); ioControl.Activate(); //OPEN LOOP Control loop for (;;) { loopTimer = GetTime_ms() - powerStartTime; if (loopTimer > (Device.deviceConfig.msOpenLoopDuration)) break; if (!ioControl.isActivateSwitchOn()) break; } } if(Device.deviceConfig.msRampDuration >0) { resistance = Device.deviceConfig.startVoltage/ADC.GetSensedCurrent(); // Calculate the voltage from the difference needed from the end and start power. double endVoltage = sqrt(Device.deviceConfig.rampEndPower * resistance); double startVoltage = sqrt(Device.deviceConfig.rampStartPower * resistance); double voltageDelta = endVoltage - startVoltage; // Calculate the voltagePerMS to find the step value for the ramp time double voltagePerMs = voltageDelta / (Device.deviceConfig.msRampDuration); // Set the Ramp starting Voltage ioControl.ChangeOutputVoltage( startVoltage ); // We want to loop until our Ramp duration is complete or the activation switch has been depressed. // Because we don't know how long the loop takes, we need to check the loop time and set the new output // voltage based on the number of milliseconds that have passed during the loop. Since our discrete voltage // increments are the change needed/millisecond, if our loop is faster than 1 ms, we should see a nice clean // ramp. If it is slower than a millisecond, the ramp will be jagged. unsigned startTime = GetTime_ms(); unsigned elapsedTime = 0; double setVoltage = startVoltage; // Begin activation pid.SetTarget(setVoltage); // used to put the voltage into the Acquisition Data for (;;) { // Determine how long it took us to go through the loop. The first time this should be zero elapsedTime = GetTime_ms() - startTime; loopTimer = GetTime_ms() - powerStartTime; // Break out of the loop if we have activated longer than the ramp duration + the open loop duration. if ( elapsedTime > ( Device.deviceConfig.msRampDuration ) + ( Device.deviceConfig.msOpenLoopDuration )) { break; } // Double check that the user is still activating. if ( !ioControl.isActivateSwitchOn() ) { break; } // Now, set out output voltage to the last voltage plus however many steps we need to catch up. That is, if it took // 4 ms to get through the loop the first time, we should set the new voltage to the last voltage + 4 ms worth of steps. setVoltage = (startVoltage + (voltagePerMs * elapsedTime)); pid.SetTarget(setVoltage); // used to put the voltage into the Acquisition Data only // Make sure that we don't exceed the max voltage if ( setVoltage < endVoltage ) { ioControl.ChangeOutputVoltage( setVoltage ); } rtos::Thread::wait(1); } } //start PID Control pid.Reset(); pid.SetOutputRange(0,3.3); pid.SetTarget(Device.deviceConfig.rampEndPower); Device.deviceConfig.voltageSensed = ADC.GetSensedVoltage(); Device.deviceConfig.currentSensed = ADC.GetSensedCurrent(); pid.SetPID(Device.deviceConfig.kp,Device.deviceConfig.ki,Device.deviceConfig.kd); ioControl.SetLimits(Device.deviceConfig.vLim, Device.deviceConfig.iLim); for(;;) { loopTimer = GetTime_ms() - powerStartTime; if(loopTimer > (Device.deviceConfig.TotalDurationSeconds )) break; if(!ioControl.isActivateSwitchOn()) break; Device.deviceConfig.voltageSensed = ADC.GetSensedVoltage(); Device.deviceConfig.currentSensed = ADC.GetSensedCurrent(); Device.deviceConfig.sensedResistance = ADC.GetResistance(); Device.deviceConfig.sensedPower = Device.deviceConfig.voltageSensed * Device.deviceConfig.currentSensed ; if(Device.deviceConfig.sensedResistance > 200) pid.SetTarget(25); else pid.SetTarget(Device.deviceConfig.rampEndPower); ProcessPID(); // set output double pidout = pid.GetOutput(); ioControl.SetHVControl(pidout); rtos::Thread::wait(1); } pidTimer.stop(); ioControl.Deactivate(); } //---------------------------------------------------------------------------------------------------------------------------------- void PowerController::ExecuteConstantVoltage(void) { led4 = 1; int powerStartTime = GetTime_ms(); ioControl.SetOutputVoltage(Device.deviceConfig.constantVoltage); ioControl.SetPWMFrequency(Device.deviceConfig.pwmFrequency); ioControl.SetLimits(Device.deviceConfig.vLim, Device.deviceConfig.iLim); pid.SetTarget(Device.deviceConfig.constantVoltage); // so Target voltage shows in Windows ioControl.Activate(); acquisitionTimer.start(Device.deviceConfig.msSamplePeriod); for (;;) { loopTimer = GetTime_ms() - powerStartTime; if (loopTimer > (Device.deviceConfig.TotalDurationSeconds )) break; if (!ioControl.isActivateSwitchOn()) break; Device.deviceConfig.voltageSensed = ADC.GetSensedVoltage(); Device.deviceConfig.currentSensed = ADC.GetSensedCurrent(); Device.deviceConfig.sensedResistance = ADC.GetResistance(); pc.Print("R: ", Device.deviceConfig.sensedResistance); } } //-------------------------------------------------------------------------------------------------------------------------------------------------- void PowerController::ExecuteConstantPower(void) { // Set our initial time pid.Reset(); pid.SetPID(Device.deviceConfig.kp,Device.deviceConfig.ki,Device.deviceConfig.kd); pid.SetOutputRange(0,3.3); pid.SetTarget(Device.deviceConfig.constantPower); // set output voltage ioControl.SetOutputVoltage(10); ioControl.SetPWMFrequency(Device.deviceConfig.pwmFrequency); ioControl.SetLimits(Device.deviceConfig.vLim, Device.deviceConfig.iLim); // Start acquiring data acquisitionTimer.start(Device.deviceConfig.msSamplePeriod); loopTimer = 0; ioControl.Activate(); rtos::Thread::wait(1); Device.deviceConfig.voltageSensed = ADC.GetSensedVoltage(); Device.deviceConfig.currentSensed = ADC.GetSensedCurrent(); led4 = 1; unsigned powerStartTime = GetTime_ms(); for(;;) { loopTimer = GetTime_ms() - powerStartTime; if(loopTimer > (Device.deviceConfig.TotalDurationSeconds )) break; if(!ioControl.isActivateSwitchOn()) break; Device.deviceConfig.voltageSensed = ADC.GetSensedVoltage(); Device.deviceConfig.currentSensed = ADC.GetSensedCurrent(); Device.deviceConfig.sensedResistance = ADC.GetResistance(); Device.deviceConfig.sensedPower = Device.deviceConfig.voltageSensed * Device.deviceConfig.currentSensed; if(ADC.GetResistance() > 200) { pid.SetTarget(25); } else { pid.SetTarget(Device.deviceConfig.constantPower); } ProcessPID(); // set output double pidout = pid.GetOutput(); ioControl.SetHVControl(pidout); rtos::Thread::wait(1); } pidTimer.stop(); } //----------------------------------------------------------------------------------------------------------------- void PowerController::Calibrate(void) { Device.deviceConfig.pwrCalHigh = 1; Device.deviceConfig.pwrCalLow = 1; ioControl.HVcalControl(Device.deviceConfig.voltageCal/10000); ioControl.Activate(); for(;;) { ioControl.HVcalControl(Device.deviceConfig.voltageCal/10000); if (!ioControl.isActivateSwitchOn()) break; rtos::Thread::wait(1); } acquisitionTimer.start(Device.deviceConfig.msSamplePeriod); Device.deviceConfig.pwrCalLow = ADC.GetSensedPower(); Device.deviceConfig.vCalLow = ADC.GetSensedVoltage(); acquisitionTimer.stop(); ioControl.Deactivate(); for(;;) { if( ioControl.isActivateSwitchOn() && ioControl.hasFalling()) break; rtos::Thread::wait(1); } ioControl.HVcalControl(Device.deviceConfig.voltageCal/10000); ioControl.Activate(); for(;;) { ioControl.HVcalControl(Device.deviceConfig.voltageCal/10000); if (!ioControl.isActivateSwitchOn()) break; rtos::Thread::wait(1); } acquisitionTimer.start(Device.deviceConfig.msSamplePeriod); Device.deviceConfig.pwrCalHigh = ADC.GetSensedPower(); Device.deviceConfig.vCalHigh = ADC.GetSensedVoltage(); acquisitionTimer.stop(); ioControl.Deactivate(); FILE *fp = fopen("/local/out.txt", "w"); // Open "out.txt" on the local file system for writing fprintf(fp," %f \n\r",Device.deviceConfig.pwrCalLow ); fprintf(fp," %f \n\r",Device.deviceConfig.pwrCalHigh ); fprintf(fp," %f \n\r",Device.deviceConfig.vCalLow ); fprintf(fp," %f \n\r",Device.deviceConfig.vCalHigh ); if(Device.deviceConfig.kp != 10000) { fprintf(fp," %f \n\r",Device.deviceConfig.kp ); fprintf(fp," %f \n\r",Device.deviceConfig.ki); fprintf(fp," %f \n\r",Device.deviceConfig.kd); } else { fprintf(fp," %f \n\r",0.0 ); fprintf(fp," %f \n\r",0.0); fprintf(fp," %f \n\r",0.0); } fclose(fp); } //------------------------------------------------------------------------------------------------------------------ void PowerController::AcquireData(void) { int elaspedTime = GetTime_ms() - myTime; AcquisitionData data; data.timestampMilliseconds = elaspedTime; data.vSense = Device.deviceConfig.voltageSensed ; data.iSense = Device.deviceConfig.currentSensed; data.vRMS = ADC.GetRMSVoltage(); data.iRMS = ADC.GetRMSCurrent(); data.targetVoltage = pid.GetTarget(); data.power = Device.deviceConfig.sensedPower; data.resistence = Device.deviceConfig.sensedResistance; Device.AddAcquisitionSample(data); } void PowerController::ProcessPID(void) { double snsV = Device.deviceConfig.voltageSensed; double snsI = Device.deviceConfig.currentSensed; double snsPowerCal = snsV * snsI; double snsPower = OffsetAndGain(Device.deviceConfig.pwrCalLow,Device.deviceConfig.pwrCalHigh ,50,100,snsPowerCal); double hvcontrol = ioControl.GetHVControl(); rtos::Thread::wait(10); pc.Print("P: ", snsPowerCal); pc.Print("Pcal: ", snsPower); pc.Print("H: ", hvcontrol); pid.AddSample(snsPower, hvcontrol); } double PowerController::OffsetAndGain(double min, double max, double refMin, double refMax, double inVal) { return ((inVal - min) * (refMax - refMin))/ (max - min) + refMin; }