mirror of https://github.com/PentHertz/srsLTE.git
Added more information in NR PHY SA cell search test
This commit is contained in:
parent
5b744bb6c5
commit
4f86c2fac7
|
@ -64,6 +64,8 @@ public:
|
||||||
uint32_t ssb_periodicity_ms;
|
uint32_t ssb_periodicity_ms;
|
||||||
srsran_duplex_mode_t duplex_mode;
|
srsran_duplex_mode_t duplex_mode;
|
||||||
std::set<uint32_t> pci_list;
|
std::set<uint32_t> pci_list;
|
||||||
|
float channel_hst_fd_hz = 0.0f;
|
||||||
|
float channel_hst_period_s = 7.2f;
|
||||||
};
|
};
|
||||||
|
|
||||||
gnb_rf_emulator(const args_t& args)
|
gnb_rf_emulator(const args_t& args)
|
||||||
|
@ -83,6 +85,11 @@ public:
|
||||||
gnb_args.ssb_periodicity_ms = args.ssb_periodicity_ms;
|
gnb_args.ssb_periodicity_ms = args.ssb_periodicity_ms;
|
||||||
gnb_args.duplex_mode = args.duplex_mode;
|
gnb_args.duplex_mode = args.duplex_mode;
|
||||||
|
|
||||||
|
gnb_args.channel.hst_enable = std::isnormal(args.channel_hst_fd_hz) and std::isnormal(args.channel_hst_period_s);
|
||||||
|
gnb_args.channel.hst_fd_hz = args.channel_hst_fd_hz;
|
||||||
|
gnb_args.channel.hst_period_s = args.channel_hst_period_s;
|
||||||
|
gnb_args.channel.enable = gnb_args.channel.hst_enable;
|
||||||
|
|
||||||
gnb_vector.emplace_back(std::make_shared<gnb_emulator>(gnb_args));
|
gnb_vector.emplace_back(std::make_shared<gnb_emulator>(gnb_args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gnb_rf_emulator.h"
|
#include "gnb_rf_emulator.h"
|
||||||
#include "srsran/asn1/rrc_nr.h"
|
|
||||||
#include "srsran/common/band_helper.h"
|
#include "srsran/common/band_helper.h"
|
||||||
#include "srsran/common/crash_handler.h"
|
#include "srsran/common/crash_handler.h"
|
||||||
#include "srsran/common/string_helpers.h"
|
#include "srsran/common/string_helpers.h"
|
||||||
|
@ -46,8 +45,7 @@ public:
|
||||||
pending_tti_cvar.notify_all();
|
pending_tti_cvar.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t count = 0;
|
void tick()
|
||||||
void tick()
|
|
||||||
{
|
{
|
||||||
// Wait for TTI to get processed
|
// Wait for TTI to get processed
|
||||||
std::unique_lock<std::mutex> lock(pending_tti_mutex);
|
std::unique_lock<std::mutex> lock(pending_tti_mutex);
|
||||||
|
@ -79,7 +77,9 @@ struct args_t {
|
||||||
std::string stack_log_level = "warning";
|
std::string stack_log_level = "warning";
|
||||||
|
|
||||||
// Simulation parameters
|
// Simulation parameters
|
||||||
uint32_t sim_ssb_periodicity_ms = 10;
|
uint32_t sim_ssb_periodicity_ms = 10;
|
||||||
|
float sim_channel_hst_fd_hz = 0.0f;
|
||||||
|
float sim_channel_hst_period_s = 7.2f;
|
||||||
std::set<uint32_t> sim_cell_pci;
|
std::set<uint32_t> sim_cell_pci;
|
||||||
|
|
||||||
// RF parameters
|
// RF parameters
|
||||||
|
@ -152,34 +152,36 @@ int parse_args(int argc, char** argv, args_t& args)
|
||||||
bpo::options_description simulation("Mode 2: Simulation options (enabled if simulation_cell_list is not empty)");
|
bpo::options_description simulation("Mode 2: Simulation options (enabled if simulation_cell_list is not empty)");
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
over_the_air.add_options()
|
over_the_air.add_options()
|
||||||
("rf.device_name", bpo::value<std::string>(&args.rf_device_name)->default_value(args.rf_device_name), "RF Device Name")
|
("rf.device_name", bpo::value<std::string>(&args.rf_device_name)->default_value(args.rf_device_name), "RF Device Name")
|
||||||
("rf.device_args", bpo::value<std::string>(&args.rf_device_args)->default_value(args.rf_device_args), "RF Device arguments")
|
("rf.device_args", bpo::value<std::string>(&args.rf_device_args)->default_value(args.rf_device_args), "RF Device arguments")
|
||||||
("rf.log_level", bpo::value<std::string>(&args.rf_log_level)->default_value(args.rf_log_level), "RF Log level (none, warning, info, debug)")
|
("rf.log_level", bpo::value<std::string>(&args.rf_log_level)->default_value(args.rf_log_level), "RF Log level (none, warning, info, debug)")
|
||||||
("rf.rx_gain", bpo::value<float>(&args.rf_rx_gain_dB)->default_value(args.rf_rx_gain_dB), "RF Receiver gain in dB")
|
("rf.rx_gain", bpo::value<float>(&args.rf_rx_gain_dB)->default_value(args.rf_rx_gain_dB), "RF Receiver gain in dB")
|
||||||
("rf.freq_offset", bpo::value<float>(&args.rf_freq_offset_Hz)->default_value(args.rf_freq_offset_Hz), "RF Frequency offset")
|
("rf.freq_offset", bpo::value<float>(&args.rf_freq_offset_Hz)->default_value(args.rf_freq_offset_Hz), "RF Frequency offset")
|
||||||
;
|
;
|
||||||
|
|
||||||
simulation.add_options()
|
simulation.add_options()
|
||||||
("sim.pci_list", bpo::value<std::string>(&simulation_cell_list)->default_value(simulation_cell_list), "Comma separated PCI cell list to simulate")
|
("sim.pci_list", bpo::value<std::string>(&simulation_cell_list)->default_value(simulation_cell_list), "Comma separated PCI cell list to simulate")
|
||||||
("sim.bw", bpo::value<uint32_t>(&args.base_carrier.nof_prb)->default_value(args.base_carrier.nof_prb), "Carrier bandwidth in RB")
|
("sim.bw", bpo::value<uint32_t>(&args.base_carrier.nof_prb)->default_value(args.base_carrier.nof_prb), "Carrier bandwidth in RB")
|
||||||
("sim.ssb_period", bpo::value<uint32_t>(&args.sim_ssb_periodicity_ms)->default_value(args.sim_ssb_periodicity_ms), "SSB period in ms")
|
("sim.ssb_period", bpo::value<uint32_t>(&args.sim_ssb_periodicity_ms)->default_value(args.sim_ssb_periodicity_ms), "SSB period in ms")
|
||||||
;
|
("sim.channel.hst.fd", bpo::value<float>(&args.sim_channel_hst_fd_hz)->default_value(args.sim_channel_hst_fd_hz), "Channel emulator HST maximum frequency")
|
||||||
|
("sim.channel.hst.period", bpo::value<float>(&args.sim_channel_hst_period_s)->default_value(args.sim_channel_hst_period_s), "Channel emulator HST period")
|
||||||
|
;
|
||||||
|
|
||||||
phy.add_options()
|
phy.add_options()
|
||||||
("phy.srate", bpo::value<double>(&args.srate_hz)->default_value(args.srate_hz), "Sampling Rate in Hz")
|
("phy.srate", bpo::value<double>(&args.srate_hz)->default_value(args.srate_hz), "Sampling Rate in Hz")
|
||||||
("phy.log.level", bpo::value<std::string>(&args.phy_log_level)->default_value(args.phy_log_level), "Physical layer logging level")
|
("phy.log.level", bpo::value<std::string>(&args.phy_log_level)->default_value(args.phy_log_level), "Physical layer logging level")
|
||||||
;
|
;
|
||||||
|
|
||||||
stack.add_options()
|
stack.add_options()
|
||||||
("stack.log.level", bpo::value<std::string>(&args.stack_log_level)->default_value(args.stack_log_level), "Stack logging level")
|
("stack.log.level", bpo::value<std::string>(&args.stack_log_level)->default_value(args.stack_log_level), "Stack logging level")
|
||||||
;
|
;
|
||||||
|
|
||||||
options.add(over_the_air).add(simulation).add(phy).add(stack).add_options()
|
options.add(over_the_air).add(simulation).add(phy).add(stack).add_options()
|
||||||
("help,h", "Show this message")
|
("help,h", "Show this message")
|
||||||
("duration", bpo::value<uint32_t>(&args.duration_ms)->default_value(args.duration_ms), "Duration of the test in milli-seconds")
|
("duration", bpo::value<uint32_t>(&args.duration_ms)->default_value(args.duration_ms), "Duration of the test in milli-seconds")
|
||||||
("freq_dl", bpo::value<double>(&args.base_carrier.dl_center_frequency_hz)->default_value(args.base_carrier.dl_center_frequency_hz), "Carrier center frequency in Hz")
|
("freq_dl", bpo::value<double>(&args.base_carrier.dl_center_frequency_hz)->default_value(args.base_carrier.dl_center_frequency_hz), "Carrier center frequency in Hz")
|
||||||
;
|
;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
bpo::variables_map vm;
|
bpo::variables_map vm;
|
||||||
|
@ -223,6 +225,8 @@ public:
|
||||||
phy.wait_initialize();
|
phy.wait_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cell_search_read_and_clear() { return stack.get_cell_search_finished(); }
|
||||||
|
|
||||||
bool start_cell_search(const srsue::phy_interface_stack_nr::cell_search_args_t& args)
|
bool start_cell_search(const srsue::phy_interface_stack_nr::cell_search_args_t& args)
|
||||||
{
|
{
|
||||||
return phy.start_cell_search(args);
|
return phy.start_cell_search(args);
|
||||||
|
@ -243,6 +247,8 @@ public:
|
||||||
// Stop PHY
|
// Stop PHY
|
||||||
phy.stop();
|
phy.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ue_dummy_stack::metrics_t& get_metrics() const { return stack.get_metrics(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
@ -270,6 +276,8 @@ int main(int argc, char** argv)
|
||||||
gnb_args.ssb_scs = args.ssb_scs;
|
gnb_args.ssb_scs = args.ssb_scs;
|
||||||
gnb_args.duplex_mode = args.duplex_mode;
|
gnb_args.duplex_mode = args.duplex_mode;
|
||||||
gnb_args.pci_list = args.sim_cell_pci;
|
gnb_args.pci_list = args.sim_cell_pci;
|
||||||
|
gnb_args.channel_hst_fd_hz = args.sim_channel_hst_fd_hz;
|
||||||
|
gnb_args.channel_hst_period_s = args.sim_channel_hst_period_s;
|
||||||
|
|
||||||
radio = std::make_shared<gnb_rf_emulator>(gnb_args);
|
radio = std::make_shared<gnb_rf_emulator>(gnb_args);
|
||||||
} else {
|
} else {
|
||||||
|
@ -277,13 +285,13 @@ int main(int argc, char** argv)
|
||||||
srsran::rf_args_t rf_args = {};
|
srsran::rf_args_t rf_args = {};
|
||||||
rf_args.type = "multi";
|
rf_args.type = "multi";
|
||||||
rf_args.log_level = args.rf_log_level;
|
rf_args.log_level = args.rf_log_level;
|
||||||
// rf_args.srate_hz = args.srate_hz;
|
rf_args.srate_hz = args.srate_hz;
|
||||||
rf_args.rx_gain = args.rf_rx_gain_dB;
|
rf_args.rx_gain = args.rf_rx_gain_dB;
|
||||||
rf_args.nof_carriers = 1;
|
rf_args.nof_carriers = 1;
|
||||||
rf_args.nof_antennas = 1;
|
rf_args.nof_antennas = 1;
|
||||||
rf_args.device_args = args.rf_device_args;
|
rf_args.device_args = args.rf_device_args;
|
||||||
rf_args.device_name = args.rf_device_name;
|
rf_args.device_name = args.rf_device_name;
|
||||||
rf_args.freq_offset = args.rf_freq_offset_Hz;
|
rf_args.freq_offset = args.rf_freq_offset_Hz;
|
||||||
|
|
||||||
// Instantiate
|
// Instantiate
|
||||||
std::shared_ptr<srsran::radio> r = std::make_shared<srsran::radio>();
|
std::shared_ptr<srsran::radio> r = std::make_shared<srsran::radio>();
|
||||||
|
@ -362,7 +370,8 @@ int main(int argc, char** argv)
|
||||||
// Transition PHY to cell search
|
// Transition PHY to cell search
|
||||||
srsran_assert(ue.start_cell_search(cs_args_), "Failed cell search start");
|
srsran_assert(ue.start_cell_search(cs_args_), "Failed cell search start");
|
||||||
|
|
||||||
for (uint32_t i = 0; i < args.duration_ms; i++) {
|
// Run slot until the PHY reported to the stack
|
||||||
|
while (not ue.cell_search_read_and_clear()) {
|
||||||
ue.run_tti();
|
ue.run_tti();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,8 +382,41 @@ int main(int argc, char** argv)
|
||||||
// Stop Radio
|
// Stop Radio
|
||||||
radio->reset();
|
radio->reset();
|
||||||
|
|
||||||
|
const ue_dummy_stack::metrics_t& metrics = ue.get_metrics();
|
||||||
|
printf("| %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s |\n",
|
||||||
|
"PCI",
|
||||||
|
"SSB",
|
||||||
|
"Count",
|
||||||
|
"RSRP min",
|
||||||
|
"RSRP avg",
|
||||||
|
"RSRP max",
|
||||||
|
"SNR min",
|
||||||
|
"SNR avg",
|
||||||
|
"SNR max",
|
||||||
|
"CFO min",
|
||||||
|
"CFO avg",
|
||||||
|
"CFO max");
|
||||||
|
for (auto& pci : metrics.cell_search) {
|
||||||
|
for (auto& ssb : pci.second) {
|
||||||
|
printf("| %10d | %10d | %10d | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | "
|
||||||
|
"%+10.1f |\n",
|
||||||
|
pci.first,
|
||||||
|
ssb.first,
|
||||||
|
(uint32_t)ssb.second.count,
|
||||||
|
ssb.second.rsrp_db_min,
|
||||||
|
ssb.second.rsrp_db_avg,
|
||||||
|
ssb.second.rsrp_db_max,
|
||||||
|
ssb.second.snr_db_min,
|
||||||
|
ssb.second.snr_db_avg,
|
||||||
|
ssb.second.snr_db_max,
|
||||||
|
ssb.second.cfo_hz_min,
|
||||||
|
ssb.second.cfo_hz_avg,
|
||||||
|
ssb.second.cfo_hz_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Erase radio
|
// Erase radio
|
||||||
radio = nullptr;
|
radio = nullptr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -25,7 +25,24 @@ public:
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cell_search_metrics_t {
|
||||||
|
float epre_db_avg = 0.0f;
|
||||||
|
float epre_db_min = +INFINITY;
|
||||||
|
float epre_db_max = -INFINITY;
|
||||||
|
float rsrp_db_avg = 0.0f;
|
||||||
|
float rsrp_db_min = +INFINITY;
|
||||||
|
float rsrp_db_max = -INFINITY;
|
||||||
|
float snr_db_avg = 0.0f;
|
||||||
|
float snr_db_min = +INFINITY;
|
||||||
|
float snr_db_max = -INFINITY;
|
||||||
|
float cfo_hz_avg = 0.0f;
|
||||||
|
float cfo_hz_min = +INFINITY;
|
||||||
|
float cfo_hz_max = -INFINITY;
|
||||||
|
uint32_t count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct metrics_t {
|
struct metrics_t {
|
||||||
|
std::map<uint32_t, std::map<uint32_t, cell_search_metrics_t> > cell_search;
|
||||||
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
|
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
|
||||||
uint32_t sr_count = 0; ///< Counts number of transmitted SR
|
uint32_t sr_count = 0; ///< Counts number of transmitted SR
|
||||||
};
|
};
|
||||||
|
@ -48,6 +65,8 @@ private:
|
||||||
dummy_tx_harq_entity tx_harq_proc;
|
dummy_tx_harq_entity tx_harq_proc;
|
||||||
dummy_rx_harq_entity rx_harq_proc;
|
dummy_rx_harq_entity rx_harq_proc;
|
||||||
|
|
||||||
|
std::atomic<bool> cell_search_finished = {false};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct args_t {
|
struct args_t {
|
||||||
uint16_t rnti = 0x1234; ///< C-RNTI for PUSCH and PDSCH transmissions
|
uint16_t rnti = 0x1234; ///< C-RNTI for PUSCH and PDSCH transmissions
|
||||||
|
@ -134,39 +153,71 @@ public:
|
||||||
}
|
}
|
||||||
bool is_valid() const { return valid; }
|
bool is_valid() const { return valid; }
|
||||||
|
|
||||||
metrics_t get_metrics() { return metrics; }
|
const metrics_t& get_metrics() const { return metrics; }
|
||||||
|
|
||||||
void set_phy_config_complete(bool status) override {}
|
void set_phy_config_complete(bool status) override {}
|
||||||
|
|
||||||
|
bool get_cell_search_finished()
|
||||||
|
{
|
||||||
|
bool ret = cell_search_finished;
|
||||||
|
|
||||||
|
cell_search_finished = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void cell_search_found_cell(const cell_search_result_t& result) override
|
void cell_search_found_cell(const cell_search_result_t& result) override
|
||||||
{
|
{
|
||||||
if (result.cell_found) {
|
// Flag as cell search is done
|
||||||
// Unpack MIB with ASN1
|
cell_search_finished = true;
|
||||||
asn1::rrc_nr::mib_s mib_asn1;
|
|
||||||
asn1::cbit_ref cbit(result.pbch_msg.payload, SRSRAN_PBCH_MSG_NR_SZ);
|
|
||||||
mib_asn1.unpack(cbit);
|
|
||||||
|
|
||||||
// Convert MIB to JSON
|
if (not result.cell_found) {
|
||||||
asn1::json_writer json;
|
logger.info("Cell search finished without detecting any cell");
|
||||||
mib_asn1.to_json(json);
|
return;
|
||||||
|
|
||||||
// Unpack MIB with C lib
|
|
||||||
srsran_mib_nr_t mib_c = {};
|
|
||||||
srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib_c);
|
|
||||||
|
|
||||||
// Convert MIB from C lib to info
|
|
||||||
std::array<char, 512> mib_info = {};
|
|
||||||
srsran_pbch_msg_nr_mib_info(&mib_c, mib_info.data(), (uint32_t)mib_info.size());
|
|
||||||
|
|
||||||
// Convert CSI to string
|
|
||||||
std::array<char, 512> csi_info = {};
|
|
||||||
srsran_csi_meas_info_short(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
"Cell found pci=%d %s %s ASN1: %s", result.pci, mib_info.data(), csi_info.data(), json.to_string().c_str());
|
|
||||||
} else {
|
|
||||||
logger.info("Cell not found\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pack PBCH message bits
|
||||||
|
std::array<uint8_t, SRSRAN_PBCH_MSG_NR_SZ> bit_pack_pbch_msg = {};
|
||||||
|
asn1::cbit_ref cbit(bit_pack_pbch_msg.data(), bit_pack_pbch_msg.size());
|
||||||
|
srsran_bit_pack_vector((uint8_t*)result.pbch_msg.payload, bit_pack_pbch_msg.data(), SRSRAN_PBCH_MSG_NR_SZ);
|
||||||
|
|
||||||
|
// Unpack MIB with ASN1
|
||||||
|
asn1::rrc_nr::bcch_bch_msg_s bcch;
|
||||||
|
bcch.unpack(cbit);
|
||||||
|
|
||||||
|
// Convert MIB to JSON
|
||||||
|
asn1::json_writer json;
|
||||||
|
bcch.to_json(json);
|
||||||
|
|
||||||
|
// Unpack MIB with C lib
|
||||||
|
srsran_mib_nr_t mib_c = {};
|
||||||
|
srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib_c);
|
||||||
|
|
||||||
|
// Convert MIB from C lib to info
|
||||||
|
std::array<char, 512> mib_info = {};
|
||||||
|
srsran_pbch_msg_nr_mib_info(&mib_c, mib_info.data(), (uint32_t)mib_info.size());
|
||||||
|
|
||||||
|
// Convert CSI to string
|
||||||
|
std::array<char, 512> csi_info = {};
|
||||||
|
srsran_csi_meas_info_short(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"Cell found pci=%d %s %s ASN1: %s", result.pci, mib_info.data(), csi_info.data(), json.to_string().c_str());
|
||||||
|
|
||||||
|
cell_search_metrics_t& m = metrics.cell_search[result.pci][result.pbch_msg.ssb_idx];
|
||||||
|
m.epre_db_min = SRSRAN_MIN(m.epre_db_min, result.measurements.epre_dB);
|
||||||
|
m.epre_db_max = SRSRAN_MAX(m.epre_db_max, result.measurements.epre_dB);
|
||||||
|
m.epre_db_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.epre_dB, m.epre_db_avg, m.count);
|
||||||
|
m.rsrp_db_min = SRSRAN_MIN(m.rsrp_db_min, result.measurements.rsrp_dB);
|
||||||
|
m.rsrp_db_max = SRSRAN_MAX(m.rsrp_db_max, result.measurements.rsrp_dB);
|
||||||
|
m.rsrp_db_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.rsrp_dB, m.rsrp_db_avg, m.count);
|
||||||
|
m.snr_db_min = SRSRAN_MIN(m.snr_db_min, result.measurements.snr_dB);
|
||||||
|
m.snr_db_max = SRSRAN_MAX(m.snr_db_max, result.measurements.snr_dB);
|
||||||
|
m.snr_db_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.snr_dB, m.snr_db_avg, m.count);
|
||||||
|
m.cfo_hz_min = SRSRAN_MIN(m.cfo_hz_min, result.measurements.cfo_hz);
|
||||||
|
m.cfo_hz_max = SRSRAN_MAX(m.cfo_hz_max, result.measurements.cfo_hz);
|
||||||
|
m.cfo_hz_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.cfo_hz, m.cfo_hz_avg, m.count);
|
||||||
|
m.count++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue