aboutsummaryrefslogtreecommitdiff
path: root/src/devices/pcm_device.cpp
diff options
context:
space:
mode:
authorClément Zrounba <6691770+clement-z@users.noreply.github.com>2023-09-30 23:06:01 +0200
committerClément Zrounba <6691770+clement-z@users.noreply.github.com>2023-09-30 23:26:46 +0200
commitff9b8bb838ecdfbfc1dc81038fcf3b2a87636982 (patch)
tree21f27be782ce11c6d00b96ce100a2bff88141b2e /src/devices/pcm_device.cpp
downloadspecs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.tar.gz
specs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.zip
Initial release
Diffstat (limited to 'src/devices/pcm_device.cpp')
-rw-r--r--src/devices/pcm_device.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/devices/pcm_device.cpp b/src/devices/pcm_device.cpp
new file mode 100644
index 0000000..dc018da
--- /dev/null
+++ b/src/devices/pcm_device.cpp
@@ -0,0 +1,150 @@
+#include <algorithm>
+#include <iostream>
+
+#include <pcm_device.h>
+
+#define ZERO_PULSE_THRESHOLD (1e-10)
+
+using namespace std;
+
+void PCMElement::on_input_changed()
+{
+ // setting the transmission for the initial state
+ update_transmission_local();
+
+
+ if (specsGlobalConfig.verbose_component_initialization)
+ {
+ cout << name() << ":" << endl;
+ cout << "Emelt = " << m_meltEnergy*1e9 << " nJ" << endl;
+ cout << "Nstates = " << m_nStates << "" << endl;
+ cout << (dynamic_cast<spx::oa_signal_type *>(p_in.get_interface()))->name();
+ cout << " --> ";
+ cout << (dynamic_cast<spx::oa_signal_type *>(p_out.get_interface()))->name();
+ cout << endl;
+ cout << endl;
+ }
+
+ m_last_pulse_power = 0;
+ bool in_window = false;
+ vector<pulse_sample_t> vector_of_samples;
+ uint32_t cur_wavelength_id;
+ m_memory_in[0] = 0;
+ double total_in_power = 0;
+
+ while (true) {
+ // Wait next input change
+ wait();
+
+ // Read signal and store field in memory for that wavelength
+ auto s = p_in->read();
+ cur_wavelength_id = s.m_wavelength_id;
+ m_memory_in[cur_wavelength_id] = s.m_field;
+
+ // Summing powers of all wavelengths
+ total_in_power = 0;
+ for (auto lambdaID_field : m_memory_in)
+ {
+ total_in_power += norm(lambdaID_field.second);
+ }
+
+ // Storage of optical state on the input
+ const sc_time &now = sc_time_stamp();
+
+ bool last_was_zero = m_last_pulse_power < ZERO_PULSE_THRESHOLD;
+ bool current_is_zero = total_in_power < ZERO_PULSE_THRESHOLD;
+ bool rising_edge = last_was_zero && !current_is_zero;
+ if (!rising_edge)
+ {
+ // Enter here when:
+ // - a signal is received on top of another one (pulse intersect)
+ // - a signal ends (power falls to 0)
+
+ // Record the event
+ vector_of_samples.emplace_back(now.to_seconds(), total_in_power);
+ }
+ else
+ {
+ // Enter here when:
+ // - a signal starts (power rises from 0 to non-0 value)
+ // This case is necessarily the first rise
+
+ // Will unroll events and check if there was a phase change before according to
+ // the vector and advance the state accordingly to get the transmission
+ // cout << "\t\t first rise detected" << endl;
+ in_window = phase_change(vector_of_samples, true);
+ if (!in_window)
+ vector_of_samples.clear();
+
+ // Record the current event
+ vector_of_samples.emplace_back(now.to_seconds(), total_in_power);
+ }
+
+ m_last_pulse_power = total_in_power;
+
+ // Write attenuated signal to output
+ s *= m_transmission;
+ s.getNewId();
+
+ m_out_writer.delayedWrite(s, SC_ZERO_TIME);
+ }
+}
+
+bool PCMElement::phase_change(const vector<pulse_sample_t> &samples, const bool &local)
+{
+ // Here should decide between sending the
+ // sim off to external or resolving inside
+
+ // Should set new values for m_state and m_transmission
+
+ double energy_absorbed = 0;
+ double dur_pulse = 0;
+ // will return true if we shouldn't erase the vector
+ bool in_influence_window = false;
+
+ if (samples.empty())
+ return true;
+
+ if (sc_time_stamp().to_seconds() - samples.back().first < influence_time_ns*1e-9)
+ return true;
+
+ if (local)
+ {
+ // Integrating power along each duration
+ // pulse 0 stays at pow[0] for tim[1]-tim[0] seconds
+ // the last sample is zero in power, just here to get the final time
+ for (unsigned int i = 0; i < samples.size()-1; i++)
+ {
+ dur_pulse = samples[i+1].first - samples[i].first;
+ energy_absorbed += samples[i].second * dur_pulse;
+ }
+ // if enough energy and not saturated
+ if ((energy_absorbed > m_meltEnergy) && (m_state < m_nStates))
+ {
+ // cout << sc_time_stamp() << ": \n\t" << name() << " phase changed with "
+ // << energy_absorbed*1e6 << " uJ" << endl;
+ m_state++;
+ // cout << "\tnew state: " << m_state << endl;
+ update_transmission_local();
+ }
+ }
+ else // external phase change simulation
+ {
+ // send the simulation to external software
+ cout << "TODO: implement handles to external sim"
+ << endl;
+ }
+ return in_influence_window;
+}
+
+void PCMElement::update_transmission_local()
+{
+ double sp = 0.85;
+ double ep = 0.95;
+ double speed = 3;
+ m_transmission = sp+(ep-sp)*tanh(speed*m_state/m_nStates);
+ // cout << "\tnew trans_power: " << m_transmission << "- W/W" << endl;
+
+ // For field need to do a square root
+ m_transmission = sqrt(m_transmission);
+}